From eb2a1734d3e02c19814f628e10bf80de5fb19772 Mon Sep 17 00:00:00 2001 From: Ahmed Ashour Date: Tue, 26 Mar 2019 13:29:39 +0100 Subject: [PATCH] fix: xor with boolean (#409) (PR #516) --- .../main/java/jadx/core/codegen/InsnGen.java | 3 +- .../core/dex/visitors/SimplifyVisitor.java | 31 +++++++++--- .../tests/integration/conditions/TestXor.java | 44 ++++++++++++---- .../src/test/smali/conditions/TestXor.smali | 50 +++++++++++++++++++ 4 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 jadx-core/src/test/smali/conditions/TestXor.smali diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index f8c53f04f..ec9cc1ef7 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -277,7 +277,8 @@ public class InsnGen { break; case NOT: - oneArgInsn(code, insn, state, '~'); + char op = insn.getArg(0).getType() == ArgType.BOOLEAN ? '!' : '~'; + oneArgInsn(code, insn, state, op); break; case RETURN: diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java index a7109faff..ed3aedf26 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java @@ -4,18 +4,26 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import jadx.core.dex.instructions.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.core.Consts; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.instructions.ArithNode; +import jadx.core.dex.instructions.ArithOp; +import jadx.core.dex.instructions.CallMthInterface; +import jadx.core.dex.instructions.ConstStringNode; +import jadx.core.dex.instructions.IfNode; +import jadx.core.dex.instructions.IndexInsnNode; +import jadx.core.dex.instructions.InsnType; +import jadx.core.dex.instructions.InvokeNode; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.FieldArg; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.args.LiteralArg; +import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.mods.ConstructorInsn; import jadx.core.dex.instructions.mods.TernaryInsn; import jadx.core.dex.nodes.BlockNode; @@ -54,7 +62,7 @@ public class SimplifyVisitor extends AbstractVisitor { } switch (insn.getType()) { case ARITH: - return simplifyArith(insn); + return simplifyArith((ArithNode) insn); case IF: simplifyIf((IfNode) insn); @@ -64,7 +72,7 @@ public class SimplifyVisitor extends AbstractVisitor { break; case INVOKE: - return convertInvoke(mth, insn); + return convertInvoke(mth, (InvokeNode) insn); case IPUT: case SPUT: @@ -151,8 +159,8 @@ public class SimplifyVisitor extends AbstractVisitor { * @param insn * @return */ - private static InsnNode convertInvoke(MethodNode mth, InsnNode insn) { - MethodInfo callMth = ((InvokeNode) insn).getCallMth(); + private static InsnNode convertInvoke(MethodNode mth, InvokeNode insn) { + MethodInfo callMth = insn.getCallMth(); // If this is a 'new StringBuilder(xxx).append(yyy).append(zzz).toString(), // convert it to STRING_CONCAT pseudo instruction. @@ -225,8 +233,7 @@ public class SimplifyVisitor extends AbstractVisitor { return null; } - private static InsnNode simplifyArith(InsnNode insn) { - ArithNode arith = (ArithNode) insn; + private static InsnNode simplifyArith(ArithNode arith) { if (arith.getArgsCount() != 2) { return null; } @@ -245,9 +252,17 @@ public class SimplifyVisitor extends AbstractVisitor { // fix 'c + (-1)' => 'c - (1)' if (arith.getOp() == ArithOp.ADD && lit < 0) { return new ArithNode(ArithOp.SUB, - arith.getResult(), insn.getArg(0), + arith.getResult(), arith.getArg(0), InsnArg.lit(-lit, litArg.getType())); } + InsnArg firstArg = arith.getArg(0); + if (arith.getOp() == ArithOp.XOR && firstArg.getType() == ArgType.BOOLEAN + && (lit == 0 || lit == 1)) { + InsnNode node = new InsnNode(lit == 0 ? InsnType.MOVE : InsnType.NOT, 1); + node.setResult(arith.getResult()); + node.addArg(firstArg); + return node; + } } return null; } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestXor.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestXor.java index bb40184f7..b49253635 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestXor.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestXor.java @@ -1,34 +1,58 @@ package jadx.tests.integration.conditions; import static jadx.tests.api.utils.JadxMatchers.containsOne; -import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.jupiter.api.Test; -import jadx.NotYetImplemented; import jadx.core.dex.nodes.ClassNode; -import jadx.tests.api.IntegrationTest; +import jadx.tests.api.SmaliTest; -public class TestXor extends IntegrationTest { +public class TestXor extends SmaliTest { public static class TestCls { - public boolean test() { - return test2() ^ true; + public boolean test1() { + return test() ^ true; } - public boolean test2() { + public boolean test2(boolean v) { + return v ^ true; + } + + public boolean test() { return true; } } @Test - @NotYetImplemented - public void test409() { + public void test() { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); - assertThat(code, not(containsOne("1"))); + assertThat(code, containsOne("return !test();")); + assertThat(code, containsOne("return !v;")); + } + + @Test + public void smali() { + /* + public boolean test1() { + return test() ^ true; + } + + public boolean test2() { + return test() ^ false; + } + + public boolean test() { + return true; + } + */ + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestXor"); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("return !test();")); + assertThat(code, containsOne("return test();")); } } diff --git a/jadx-core/src/test/smali/conditions/TestXor.smali b/jadx-core/src/test/smali/conditions/TestXor.smali new file mode 100644 index 000000000..16e8aee0a --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestXor.smali @@ -0,0 +1,50 @@ +.class public LTestXor; +.super Ljava/lang/Object; + + +# direct methods +.method public constructor ()V + .locals 0 + + .line 9 + invoke-direct {p0}, Ljava/lang/Object;->()V + + return-void +.end method + + +# virtual methods +.method public test()Z + .locals 1 + + .line 20 + const/4 v0, 0x1 + + return v0 +.end method + +.method public test1()Z + .locals 1 + + .line 12 + invoke-virtual {p0}, Lcom/example/myapplication/MainActivity;->test()Z + + move-result v0 + + xor-int/lit8 v0, v0, 0x1 + + return v0 +.end method + +.method public test2()Z + .locals 1 + + .line 16 + invoke-virtual {p0}, Lcom/example/myapplication/MainActivity;->test()Z + + move-result v0 + + xor-int/lit8 v0, v0, 0x0 + + return v0 +.end method