Skip to content

Commit

Permalink
fix: handle boolean condition with bitwise OR and AND (#202) (PR #522)
Browse files Browse the repository at this point in the history
  • Loading branch information
asashour authored and skylot committed Mar 27, 2019
1 parent eb141ad commit b78349a
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import java.util.LinkedList;
import java.util.List;

import jadx.core.dex.instructions.ArithNode;
import jadx.core.dex.instructions.ArithOp;
import jadx.core.dex.instructions.IfNode;
import jadx.core.dex.instructions.IfOp;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.InsnWrapArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.RegisterArg;
Expand Down Expand Up @@ -142,7 +143,10 @@ public static IfCondition not(IfCondition cond) {
public static IfCondition simplify(IfCondition cond) {
if (cond.isCompare()) {
Compare c = cond.getCompare();
simplifyCmpOp(c);
IfCondition i = simplifyCmpOp(c);
if (i != null) {
return i;
}
if (c.getOp() == IfOp.EQ && c.getB().isLiteral() && c.getB().equals(LiteralArg.FALSE)) {
cond = not(new IfCondition(c.invert()));
} else {
Expand Down Expand Up @@ -190,20 +194,53 @@ public static IfCondition simplify(IfCondition cond) {
return cond;
}

private static void simplifyCmpOp(Compare c) {
private static IfCondition simplifyCmpOp(Compare c) {
if (!c.getA().isInsnWrap()) {
return;
return null;
}
if (!c.getB().isLiteral() || ((LiteralArg) c.getB()).getLiteral() != 0) {
return;
if (!c.getB().isLiteral()) {
return null;
}
long lit = ((LiteralArg) c.getB()).getLiteral();
if (lit != 0 && lit != 1) {
return null;
}

InsnNode wrapInsn = ((InsnWrapArg) c.getA()).getWrapInsn();
InsnType type = wrapInsn.getType();
if (type != InsnType.CMP_L && type != InsnType.CMP_G) {
return;
switch (wrapInsn.getType()) {
case CMP_L:
case CMP_G:
if (lit == 0) {
IfNode insn = c.getInsn();
insn.changeCondition(insn.getOp(), wrapInsn.getArg(0), wrapInsn.getArg(1));
}
break;

case ARITH:
ArithOp arithOp = ((ArithNode) wrapInsn).getOp();
if (arithOp == ArithOp.OR || arithOp == ArithOp.AND) {
IfOp ifOp = c.getInsn().getOp();
boolean isTrue = ifOp == IfOp.NE && lit == 0
|| ifOp == IfOp.EQ && lit == 1;

IfOp op = isTrue ? IfOp.NE : IfOp.EQ;
Mode mode = isTrue && arithOp == ArithOp.OR ||
!isTrue && arithOp == ArithOp.AND ? Mode.OR : Mode.AND;

IfNode if1 = new IfNode(op, -1, wrapInsn.getArg(0), LiteralArg.FALSE);
IfNode if2 = new IfNode(op, -1, wrapInsn.getArg(1), LiteralArg.FALSE);
return new IfCondition(mode,
Arrays.asList(new IfCondition(new Compare(if1)),
new IfCondition(new Compare(if2))));
}
break;

default:
break;
}
IfNode insn = c.getInsn();
insn.changeCondition(insn.getOp(), wrapInsn.getArg(0), wrapInsn.getArg(1));


return null;
}

public List<RegisterArg> getRegisterArgs() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package jadx.tests.integration.conditions;

import org.junit.jupiter.api.Test;

import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;

import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.MatcherAssert.assertThat;

public class TestBitwiseAnd extends IntegrationTest {

public static class TestCls {
private boolean a;
private boolean b;

public void test() {
if ((a & b) != false) {
test();
}
}
}

@Test
public void test() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (this.a && this.b) {"));
}

public static class TestCls2 {
private boolean a;
private boolean b;

public void test() {
if ((a & b) != true) {
test();
}
}
}

@Test
public void test2() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls2.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (!this.a || !this.b) {"));
}

public static class TestCls3 {
private boolean a;
private boolean b;

public void test() {
if ((a & b) == false) {
test();
}
}
}

@Test
public void test3() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls3.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (!this.a || !this.b) {"));
}

public static class TestCls4 {
private boolean a;
private boolean b;

public void test() {
if ((a & b) == true) {
test();
}
}
}

@Test
public void test4() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls4.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (this.a && this.b) {"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package jadx.tests.integration.conditions;

import org.junit.jupiter.api.Test;

import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;

import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.MatcherAssert.assertThat;

public class TestBitwiseOr extends IntegrationTest {

public static class TestCls {
private boolean a;
private boolean b;

public void test() {
if ((a | b) != false) {
test();
}
}
}

@Test
public void test() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (this.a || this.b) {"));
}

public static class TestCls2 {
private boolean a;
private boolean b;

public void test() {
if ((a | b) != true) {
test();
}
}
}

@Test
public void test2() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls2.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (!this.a && !this.b) {"));
}

public static class TestCls3 {
private boolean a;
private boolean b;

public void test() {
if ((a | b) == false) {
test();
}
}
}

@Test
public void test3() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls3.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (!this.a && !this.b) {"));
}

public static class TestCls4 {
private boolean a;
private boolean b;

public void test() {
if ((a | b) == true) {
test();
}
}
}

@Test
public void test4() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls4.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("if (this.a || this.b) {"));
}
}

This file was deleted.

0 comments on commit b78349a

Please sign in to comment.