From c134329ce99ec6a7fa5fd9461cd6a6a8d47a72c0 Mon Sep 17 00:00:00 2001 From: Ahmed Ashour Date: Sat, 20 Apr 2019 19:29:41 +0300 Subject: [PATCH] fix: cast of int-to-(number) when int is boolean (#596) (PR #602) --- .../main/java/jadx/core/codegen/InsnGen.java | 8 +++++ .../jadx/core/dex/visitors/ModVisitor.java | 25 ++++++++++++++-- .../conditions/TestBooleanToByte.java | 30 +++++++++++++++++++ .../conditions/TestBooleanToChar.java | 30 +++++++++++++++++++ .../conditions/TestBooleanToDouble.java | 30 +++++++++++++++++++ .../conditions/TestBooleanToFloat.java | 30 +++++++++++++++++++ .../conditions/TestBooleanToLong.java | 30 +++++++++++++++++++ .../conditions/TestBooleanToShort.java | 30 +++++++++++++++++++ .../smali/conditions/TestBooleanToByte.smali | 22 ++++++++++++++ .../smali/conditions/TestBooleanToChar.smali | 22 ++++++++++++++ .../conditions/TestBooleanToDouble.smali | 22 ++++++++++++++ .../smali/conditions/TestBooleanToFloat.smali | 22 ++++++++++++++ .../smali/conditions/TestBooleanToLong.smali | 22 ++++++++++++++ .../smali/conditions/TestBooleanToShort.smali | 22 ++++++++++++++ 14 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToDouble.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToFloat.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToByte.smali create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToChar.smali create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToDouble.smali create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToFloat.smali create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToLong.smali create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToShort.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 4125dafc0..5ad108b12 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -13,6 +13,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.core.Consts; +import jadx.core.deobf.NameMapper; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.FieldReplaceAttr; @@ -888,6 +889,13 @@ public class InsnGen { && lit2 != Short.MAX_VALUE && lit2 != Short.MIN_VALUE) { code.add("(short) "); } + } else if (first.getType() == ArgType.CHAR) { + long lit1 = ((LiteralArg) first).getLiteral(); + long lit2 = ((LiteralArg) second).getLiteral(); + if (!NameMapper.isPrintableChar((char) (lit1)) + && !NameMapper.isPrintableChar((char) (lit2))) { + code.add("(char) "); + } } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java index 8d08a131a..f89193fa3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java @@ -1,5 +1,7 @@ package jadx.core.dex.visitors; +import static jadx.core.utils.BlockUtils.replaceInsn; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -18,6 +20,8 @@ import jadx.core.dex.instructions.ConstClassNode; import jadx.core.dex.instructions.ConstStringNode; import jadx.core.dex.instructions.FillArrayNode; import jadx.core.dex.instructions.FilledNewArrayNode; +import jadx.core.dex.instructions.IfNode; +import jadx.core.dex.instructions.IfOp; import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.NewArrayNode; @@ -29,11 +33,13 @@ import jadx.core.dex.instructions.args.NamedArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.instructions.mods.ConstructorInsn; +import jadx.core.dex.instructions.mods.TernaryInsn; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; +import jadx.core.dex.regions.conditions.IfCondition; import jadx.core.dex.trycatch.ExcHandlerAttr; import jadx.core.dex.trycatch.ExceptionHandler; import jadx.core.dex.visitors.shrink.CodeShrinkVisitor; @@ -42,8 +48,6 @@ import jadx.core.utils.InsnRemover; import jadx.core.utils.InsnUtils; import jadx.core.utils.exceptions.JadxRuntimeException; -import static jadx.core.utils.BlockUtils.replaceInsn; - /** * Visitor for modify method instructions * (remove, replace, process exception handlers) @@ -155,6 +159,23 @@ public class ModVisitor extends AbstractVisitor { } break; + case CAST: + // replace boolean to (byte/char/short/long/double/float) cast with ternary + if (insn.getArg(0).getType() == ArgType.BOOLEAN) { + ArgType type = insn.getResult().getType(); + if (type.isPrimitive()) { + IfNode ifNode = new IfNode(IfOp.EQ, -1, insn.getArg(0), LiteralArg.TRUE); + IfCondition condition = IfCondition.fromIfNode(ifNode); + InsnArg zero = new LiteralArg(0, type); + InsnArg one = new LiteralArg( + type == ArgType.DOUBLE ? Double.doubleToLongBits(1) : + type == ArgType.FLOAT ? Float.floatToIntBits(1) : 1, type); + TernaryInsn ternary = new TernaryInsn(condition, insn.getResult(), one, zero); + replaceInsn(block, i, ternary); + } + } + break; + default: break; } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java new file mode 100644 index 000000000..952f9eb51 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java @@ -0,0 +1,30 @@ +package jadx.tests.integration.conditions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +public class TestBooleanToByte extends SmaliTest { + + /** + private boolean showConsent; + + public void write(byte b) { + } + + public void writeToParcel(TestBooleanToByte testBooleanToByte) { + testBooleanToByte.write(this.showConsent ? (byte) 1 : 0); + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToByte"); + String code = cls.getCode().toString(); + + assertThat(code, containsString("write(this.showConsent ? (byte) 1 : 0);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java new file mode 100644 index 000000000..ed972dbbb --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java @@ -0,0 +1,30 @@ +package jadx.tests.integration.conditions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +public class TestBooleanToChar extends SmaliTest { + + /** + private boolean showConsent; + + public void write(char b) { + } + + public void writeToParcel(TestBooleanToChar testBooleanToChar) { + testBooleanToChar.write(this.showConsent ? (char) 1 : 0); + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToChar"); + String code = cls.getCode().toString(); + + assertThat(code, containsString("write(this.showConsent ? (char) 1 : 0);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToDouble.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToDouble.java new file mode 100644 index 000000000..93ea13556 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToDouble.java @@ -0,0 +1,30 @@ +package jadx.tests.integration.conditions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +public class TestBooleanToDouble extends SmaliTest { + + /** + private boolean showConsent; + + public void write(double d) { + } + + public void writeToParcel(TestBooleanToDouble testBooleanToDouble) { + testBooleanToDouble.write(this.showConsent ? 1 : 0); + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToDouble"); + String code = cls.getCode().toString(); + + assertThat(code, containsString("write(this.showConsent ? 1.0d : 0.0d);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToFloat.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToFloat.java new file mode 100644 index 000000000..1ba74e92f --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToFloat.java @@ -0,0 +1,30 @@ +package jadx.tests.integration.conditions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +public class TestBooleanToFloat extends SmaliTest { + + /** + private boolean showConsent; + + public void write(float f) { + } + + public void writeToParcel(TestBooleanToFloat testBooleanToFloat) { + testBooleanToFloat.write(this.showConsent ? 1 : 0); + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToFloat"); + String code = cls.getCode().toString(); + + assertThat(code, containsString("write(this.showConsent ? 1.0f : 0.0f);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java new file mode 100644 index 000000000..7e557c4bf --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java @@ -0,0 +1,30 @@ +package jadx.tests.integration.conditions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +public class TestBooleanToLong extends SmaliTest { + + /** + private boolean showConsent; + + public void write(long j) { + } + + public void writeToParcel(TestBooleanToLong testBooleanToLong) { + testBooleanToLong.write(this.showConsent ? 1 : 0); + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToLong"); + String code = cls.getCode().toString(); + + assertThat(code, containsString("write(this.showConsent ? 1 : 0);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java new file mode 100644 index 000000000..80a211727 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java @@ -0,0 +1,30 @@ +package jadx.tests.integration.conditions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +public class TestBooleanToShort extends SmaliTest { + + /** + private boolean showConsent; + + public void write(short b) { + } + + public void writeToParcel(TestBooleanToShort testBooleanToShort) { + testBooleanToShort.write(this.showConsent ? (short) 1 : 0); + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToShort"); + String code = cls.getCode().toString(); + + assertThat(code, containsString("write(this.showConsent ? (short) 1 : 0);")); + } +} diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToByte.smali b/jadx-core/src/test/smali/conditions/TestBooleanToByte.smali new file mode 100644 index 000000000..b1ec3d236 --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToByte.smali @@ -0,0 +1,22 @@ +.class public LTestBooleanToByte; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToByte;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToByte;->showConsent:Z + + int-to-byte p1, p1 + + invoke-virtual {p0, p1}, LTestBooleanToByte;->write(B)V + + return-void +.end method + +.method public write(B)V + .locals 0 + + return-void +.end method diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToChar.smali b/jadx-core/src/test/smali/conditions/TestBooleanToChar.smali new file mode 100644 index 000000000..5564b58f5 --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToChar.smali @@ -0,0 +1,22 @@ +.class public LTestBooleanToChar; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToChar;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToChar;->showConsent:Z + + int-to-char p1, p1 + + invoke-virtual {p0, p1}, LTestBooleanToChar;->write(C)V + + return-void +.end method + +.method public write(C)V + .locals 0 + + return-void +.end method diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToDouble.smali b/jadx-core/src/test/smali/conditions/TestBooleanToDouble.smali new file mode 100644 index 000000000..2006cec2e --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToDouble.smali @@ -0,0 +1,22 @@ +.class public LTestBooleanToDouble; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToDouble;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToDouble;->showConsent:Z + + int-to-double p1, p1 + + invoke-virtual {p0, p1}, LTestBooleanToDouble;->write(D)V + + return-void +.end method + +.method public write(D)V + .locals 0 + + return-void +.end method diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToFloat.smali b/jadx-core/src/test/smali/conditions/TestBooleanToFloat.smali new file mode 100644 index 000000000..268e3984b --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToFloat.smali @@ -0,0 +1,22 @@ +.class public LTestBooleanToFloat; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToFloat;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToFloat;->showConsent:Z + + int-to-float p1, p1 + + invoke-virtual {p0, p1}, LTestBooleanToFloat;->write(F)V + + return-void +.end method + +.method public write(F)V + .locals 0 + + return-void +.end method diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToLong.smali b/jadx-core/src/test/smali/conditions/TestBooleanToLong.smali new file mode 100644 index 000000000..f997fd49a --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToLong.smali @@ -0,0 +1,22 @@ +.class public LTestBooleanToLong; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToLong;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToLong;->showConsent:Z + + int-to-long p1, p1 + + invoke-virtual {p0, p1}, LTestBooleanToLong;->write(J)V + + return-void +.end method + +.method public write(J)V + .locals 0 + + return-void +.end method diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToShort.smali b/jadx-core/src/test/smali/conditions/TestBooleanToShort.smali new file mode 100644 index 000000000..901f8e4f0 --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToShort.smali @@ -0,0 +1,22 @@ +.class public LTestBooleanToShort; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToShort;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToShort;->showConsent:Z + + int-to-short p1, p1 + + invoke-virtual {p0, p1}, LTestBooleanToShort;->write(S)V + + return-void +.end method + +.method public write(S)V + .locals 0 + + return-void +.end method