Skip to content

Commit

Permalink
fix: better String constructor from byte and char arrays (#530) (PR #533
Browse files Browse the repository at this point in the history
)
  • Loading branch information
asashour authored and skylot committed Mar 31, 2019
1 parent 008216d commit ec66476
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
15 changes: 15 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ private MethodInfo(DexNode dex, int mthIndex) {
shortId = makeSignature(true);
}

private MethodInfo(ClassInfo declClass, String name, List<ArgType> args, ArgType retType) {
this.name = name;
alias = name;
aliasFromPreset = false;
this.declClass = declClass;

this.args = args;
this.retType = retType;
shortId = makeSignature(true);
}

public static MethodInfo externalMth(ClassInfo declClass, String name, List<ArgType> args, ArgType retType) {
return new MethodInfo(declClass, name, args, retType);
}

public static MethodInfo fromDex(DexNode dex, int mthIndex) {
MethodInfo mth = dex.root().getInfoStorage().getMethod(dex, mthIndex);
if (mth != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public InvokeNode(MethodInfo mth, DecodedInstruction insn, InvokeType type, bool
}
}

private InvokeNode(MethodInfo mth, InvokeType invokeType, int argsCount) {
public InvokeNode(MethodInfo mth, InvokeType invokeType, int argsCount) {
super(InsnType.INVOKE, argsCount);
this.mth = mth;
this.type = invokeType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import org.slf4j.LoggerFactory;

import jadx.core.Consts;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.ArithNode;
Expand All @@ -19,6 +21,7 @@
import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.InvokeNode;
import jadx.core.dex.instructions.InvokeType;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.FieldArg;
import jadx.core.dex.instructions.args.InsnArg;
Expand All @@ -29,6 +32,7 @@
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.regions.conditions.IfCondition;

public class SimplifyVisitor extends AbstractVisitor {
Expand Down Expand Up @@ -95,12 +99,55 @@ private static InsnNode simplifyInsn(MethodNode mth, InsnNode insn) {
}
break;

case CONSTRUCTOR:
simplfyConstructor(mth.root(), (ConstructorInsn) insn);
break;

default:
break;
}
return null;
}

private static void simplfyConstructor(RootNode root, ConstructorInsn insn) {
if (insn.getArgsCount() != 0
&& insn.getCallMth().getDeclClass().getType().equals(ArgType.STRING)) {
InsnArg arg = insn.getArg(0);
InsnNode node = arg.isInsnWrap()
? ((InsnWrapArg) arg).getWrapInsn()
: insn;
if (node.getArgsCount() != 0) {
ArgType argType = node.getArg(0).getType();
if (node.getType() == InsnType.FILLED_NEW_ARRAY
&& (argType == ArgType.BYTE || argType == ArgType.CHAR)) {
int printable = 0;
byte[] arr = new byte[node.getArgsCount()];
for (int i = 0; i < arr.length; i++) {
arr[i] = (byte) ((LiteralArg) node.getArg(i)).getLiteral();
if (NameMapper.isPrintableChar(arr[i])) {
printable++;
}
}
if (printable >= arr.length - printable) {
InsnWrapArg wa = new InsnWrapArg(new ConstStringNode(new String(arr)));
if (insn.getArgsCount() == 1) {
insn.setArg(0, wa);
} else {
MethodInfo mi = MethodInfo.externalMth(
ClassInfo.fromType(root, ArgType.STRING),
"getBytes",
Collections.emptyList(),
ArgType.array(ArgType.BYTE));
InvokeNode in = new InvokeNode(mi, InvokeType.VIRTUAL, 1);
in.addArg(wa);
insn.setArg(0, new InsnWrapArg(in));
}
}
}
}
}
}

private static InsnNode processCast(MethodNode mth, InsnNode insn) {
InsnArg castArg = insn.getArg(0);
ArgType argType = castArg.getType();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package jadx.tests.integration.others;

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

import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Test;

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

public class TestStringConstructor extends IntegrationTest {

public static class TestCls {
public String tag = new String(new byte[] {'a', 'b', 'c'});
}

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

assertThat(code, containsOne("abc"));
}

public static class TestCls2 {
public String tag = new String(new byte[] {'a', 'b', 'c'}, StandardCharsets.UTF_8);
}

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

assertThat(code, containsOne("new String(\"abc\".getBytes(), StandardCharsets.UTF_8)"));
}

public static class TestCls3 {
public String tag = new String(new byte[] {1, 2, 3, 'a', 'b', 'c'});
}

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

assertThat(code, containsOne("\\u0001\\u0002\\u0003abc"));
}

public static class TestCls4 {
public String tag = new String(new char[] {1, 2, 3, 'a', 'b', 'c'});
}

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

assertThat(code, containsOne("\\u0001\\u0002\\u0003abc"));
}

public static class TestCls5 {
public String tag = new String(new char[] {1, 2, 3, 'a', 'b'});
}

@Test
public void test5() {
ClassNode cls = getClassNode(TestCls5.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("{1, 2, 3, 'a', 'b'}"));
}

public static class TestClsNegative {
public String tag = new String();
}

@Test
public void testNegative() {
ClassNode cls = getClassNode(TestClsNegative.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("tag = new String();"));
}
}

0 comments on commit ec66476

Please sign in to comment.