From 8a6cdec796b140f0b7b7e8c2bd07cd80cb7418f5 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 14 Feb 2015 16:38:01 +0300 Subject: [PATCH] core: refactor fill-array instruction processing and constants replace (fix #48) --- .../main/java/jadx/core/codegen/InsnGen.java | 108 ++------- .../main/java/jadx/core/codegen/NameGen.java | 4 +- .../core/dex/instructions/FillArrayNode.java | 35 +++ .../dex/instructions/FilledNewArrayNode.java | 39 +++ .../core/dex/instructions/InsnDecoder.java | 22 +- .../jadx/core/dex/visitors/ModVisitor.java | 222 +++++++++++------- .../jadx/core/dex/visitors/ReSugarCode.java | 5 +- .../blocksmaker/BlockExceptionHandler.java | 12 - .../arrays/TestArrayFillConstReplace.java | 28 +++ .../tests/integration/arrays/TestArrays2.java | 42 ++++ .../fallback/TestFallbackMode.java | 2 +- .../java/jadx/tests/smali/TestArithConst.java | 21 ++ jadx-core/src/test/smali/TestArithConst.smali | 12 + 13 files changed, 347 insertions(+), 205 deletions(-) create mode 100644 jadx-core/src/main/java/jadx/core/dex/instructions/FilledNewArrayNode.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFillConstReplace.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays2.java create mode 100644 jadx-core/src/test/java/jadx/tests/smali/TestArithConst.java create mode 100644 jadx-core/src/test/smali/TestArithConst.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 fcbb67ac..b677bdcb 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 jadx.core.dex.instructions.ArithOp; 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.GotoNode; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.IndexInsnNode; @@ -34,14 +35,13 @@ import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; -import jadx.core.utils.ErrorsCounter; -import jadx.core.utils.InsnUtils; import jadx.core.utils.RegionUtils; import jadx.core.utils.StringUtils; import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.JadxRuntimeException; import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; @@ -359,12 +359,8 @@ public class InsnGen { code.add(".length"); break; - case FILL_ARRAY: - fillArray((FillArrayNode) insn, code); - break; - case FILLED_NEW_ARRAY: - filledNewArray(insn, code); + filledNewArray((FilledNewArrayNode) insn, code); break; case AGET: @@ -490,6 +486,25 @@ public class InsnGen { code.startLine('}'); break; + case FILL_ARRAY: + assert isFallback(); + FillArrayNode arrayNode = (FillArrayNode) insn; + Object data = arrayNode.getData(); + String arrStr; + if (data instanceof int[]) { + arrStr = Arrays.toString((int[]) data); + } else if (data instanceof short[]) { + arrStr = Arrays.toString((short[]) data); + } else if (data instanceof byte[]) { + arrStr = Arrays.toString((byte[]) data); + } else if (data instanceof long[]) { + arrStr = Arrays.toString((long[]) data); + } else { + arrStr = "?"; + } + code.add('{').add(arrStr.substring(1, arrStr.length() - 1)).add('}'); + break; + case NEW_INSTANCE: // only fallback - make new instance in constructor invoke assert isFallback(); @@ -501,11 +516,11 @@ public class InsnGen { } } - private void filledNewArray(InsnNode insn, CodeWriter code) throws CodegenException { - int c = insn.getArgsCount(); + private void filledNewArray(FilledNewArrayNode insn, CodeWriter code) throws CodegenException { code.add("new "); - useType(code, insn.getResult().getType()); + useType(code, insn.getArrayType()); code.add('{'); + int c = insn.getArgsCount(); for (int i = 0; i < c; i++) { addArg(code, insn.getArg(i), false); if (i + 1 < c) { @@ -515,76 +530,6 @@ public class InsnGen { code.add('}'); } - private void fillArray(FillArrayNode insn, CodeWriter code) throws CodegenException { - String filledArray = makeArrayElements(insn); - code.add("new "); - useType(code, insn.getElementType()); - code.add("[]{").add(filledArray).add('}'); - } - - private String makeArrayElements(FillArrayNode insn) throws CodegenException { - ArgType insnArrayType = insn.getResult().getType(); - ArgType insnElementType = insnArrayType.getArrayElement(); - ArgType elType = insn.getElementType(); - if (!elType.equals(insnElementType) && !insnArrayType.equals(ArgType.OBJECT)) { - ErrorsCounter.methodError(mth, - "Incorrect type for fill-array insn " + InsnUtils.formatOffset(insn.getOffset()) - + ", element type: " + elType + ", insn element type: " + insnElementType - ); - } - if (!elType.isTypeKnown()) { - LOG.warn("Unknown array element type: {} in mth: {}", elType, mth); - elType = insnElementType.isTypeKnown() ? insnElementType : elType.selectFirst(); - if (elType == null) { - throw new JadxRuntimeException("Null array element type"); - } - } - insn.mergeElementType(elType); - - StringBuilder str = new StringBuilder(); - Object data = insn.getData(); - switch (elType.getPrimitiveType()) { - case BOOLEAN: - case BYTE: - byte[] array = (byte[]) data; - for (byte b : array) { - str.append(TypeGen.literalToString(b, elType)); - str.append(", "); - } - break; - case SHORT: - case CHAR: - short[] sarray = (short[]) data; - for (short b : sarray) { - str.append(TypeGen.literalToString(b, elType)); - str.append(", "); - } - break; - case INT: - case FLOAT: - int[] iarray = (int[]) data; - for (int b : iarray) { - str.append(TypeGen.literalToString(b, elType)); - str.append(", "); - } - break; - case LONG: - case DOUBLE: - long[] larray = (long[]) data; - for (long b : larray) { - str.append(TypeGen.literalToString(b, elType)); - str.append(", "); - } - break; - - default: - throw new CodegenException(mth, "Unknown type: " + elType); - } - int len = str.length(); - str.delete(len - 2, len); - return str.toString(); - } - private void makeConstructor(ConstructorInsn insn, CodeWriter code) throws CodegenException { ClassNode cls = mth.dex().resolveClass(insn.getClassType()); @@ -734,9 +679,6 @@ public class InsnGen { } } return true; - } else if (insn.getType() == InsnType.FILL_ARRAY) { - code.add(makeArrayElements((FillArrayNode) insn)); - return true; } return false; } diff --git a/jadx-core/src/main/java/jadx/core/codegen/NameGen.java b/jadx-core/src/main/java/jadx/core/codegen/NameGen.java index 1b4473c4..2adc509b 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/NameGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/NameGen.java @@ -115,9 +115,7 @@ public class NameGen { } private String getFallbackName(RegisterArg arg) { - String name = arg.getName(); - String base = "r" + arg.getRegNum(); - return name != null ? base + "_" + name : base; + return "r" + arg.getRegNum(); } private static String makeNameForType(ArgType type) { diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java index 2bf0a1fd..ab821f86 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java @@ -2,15 +2,20 @@ package jadx.core.dex.instructions; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; +import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.nodes.InsnNode; import jadx.core.utils.exceptions.JadxRuntimeException; +import java.util.ArrayList; +import java.util.List; + import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction; public final class FillArrayNode extends InsnNode { private final Object data; + private final int size; private ArgType elemType; public FillArrayNode(int resReg, FillArrayDataPayloadDecodedInstruction payload) { @@ -36,6 +41,7 @@ public final class FillArrayNode extends InsnNode { setResult(InsnArg.reg(resReg, ArgType.array(elType))); this.data = payload.getData(); + this.size = payload.getSize(); this.elemType = elType; } @@ -43,6 +49,10 @@ public final class FillArrayNode extends InsnNode { return data; } + public int getSize() { + return size; + } + public ArgType getElementType() { return elemType; } @@ -54,6 +64,31 @@ public final class FillArrayNode extends InsnNode { } } + public List getLiteralArgs() { + List list = new ArrayList(size); + Object array = data; + if (array instanceof int[]) { + for (int b : (int[]) array) { + list.add(InsnArg.lit(b, elemType)); + } + } else if (array instanceof byte[]) { + for (byte b : (byte[]) array) { + list.add(InsnArg.lit(b, elemType)); + } + } else if (array instanceof short[]) { + for (short b : (short[]) array) { + list.add(InsnArg.lit(b, elemType)); + } + } else if (array instanceof long[]) { + for (long b : (long[]) array) { + list.add(InsnArg.lit(b, elemType)); + } + } else { + throw new JadxRuntimeException("Unknown type: " + data.getClass() + ", expected: " + elemType); + } + return list; + } + @Override public boolean isSame(InsnNode obj) { if (this == obj) { diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/FilledNewArrayNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/FilledNewArrayNode.java new file mode 100644 index 00000000..58d6cd06 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/FilledNewArrayNode.java @@ -0,0 +1,39 @@ +package jadx.core.dex.instructions; + +import jadx.core.dex.instructions.args.ArgType; +import jadx.core.dex.nodes.InsnNode; + +public class FilledNewArrayNode extends InsnNode { + + private final ArgType elemType; + + public FilledNewArrayNode(ArgType elemType, int size) { + super(InsnType.FILLED_NEW_ARRAY, size); + this.elemType = elemType; + } + + public ArgType getElemType() { + return elemType; + } + + public ArgType getArrayType() { + return ArgType.array(elemType); + } + + @Override + public boolean isSame(InsnNode obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof FilledNewArrayNode) || !super.isSame(obj)) { + return false; + } + FilledNewArrayNode other = (FilledNewArrayNode) obj; + return elemType == other.elemType; + } + + @Override + public String toString() { + return super.toString() + " elemType: " + elemType; + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java index fbd9cf48..68ca3da9 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java @@ -620,9 +620,14 @@ public class InsnDecoder { regs[i] = InsnArg.reg(regNum, elType, typeImmutable); } } - return insn(InsnType.FILLED_NEW_ARRAY, - resReg == -1 ? null : InsnArg.reg(resReg, arrType), - regs); + InsnNode node = new FilledNewArrayNode(elType, regs == null ? 0 : regs.length); + node.setResult(resReg == -1 ? null : InsnArg.reg(resReg, arrType)); + if (regs != null) { + for (InsnArg arg : regs) { + node.addArg(arg); + } + } + return node; } private InsnNode cmp(DecodedInstruction insn, InsnType itype, ArgType argType) { @@ -690,17 +695,6 @@ public class InsnDecoder { return node; } - private InsnNode insn(InsnType type, RegisterArg res, InsnArg... args) { - InsnNode node = new InsnNode(type, args == null ? 0 : args.length); - node.setResult(res); - if (args != null) { - for (InsnArg arg : args) { - node.addArg(arg); - } - } - return node; - } - private int getMoveResultRegister(DecodedInstruction[] insnArr, int offset) { int nextOffset = getNextInsnOffset(insnArr, offset); if (nextOffset >= 0) { 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 d094ac68..fbd5a961 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 @@ -4,9 +4,11 @@ import jadx.core.codegen.TypeGen; import jadx.core.deobf.NameMapper; import jadx.core.dex.attributes.AType; import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.instructions.ArithNode; 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.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InvokeNode; @@ -25,9 +27,13 @@ import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.trycatch.ExcHandlerAttr; import jadx.core.dex.trycatch.ExceptionHandler; +import jadx.core.utils.ErrorsCounter; +import jadx.core.utils.InsnUtils; import jadx.core.utils.InstructionRemover; +import jadx.core.utils.exceptions.JadxRuntimeException; import java.util.ArrayList; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,20 +101,64 @@ public class ModVisitor extends AbstractVisitor { } break; - case RETURN: - if (insn.getArgsCount() > 0 && insn.getArg(0).isLiteral()) { - LiteralArg arg = (LiteralArg) insn.getArg(0); - FieldNode f = parentClass.getConstFieldByLiteralArg(arg); - if (f != null) { - arg.wrapInstruction(new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0)); + case NEW_ARRAY: + // create array in 'fill-array' instruction + int next = i + 1; + if (next < size) { + InsnNode ni = block.getInstructions().get(next); + if (ni.getType() == InsnType.FILL_ARRAY) { + ni.getResult().merge(insn.getResult()); + ((FillArrayNode) ni).mergeElementType(insn.getResult().getType().getArrayElement()); + remover.add(insn); } } break; + case FILL_ARRAY: + InsnNode filledArr = makeFilledArrayInsn(mth, (FillArrayNode) insn); + replaceInsn(block, i, filledArr); + break; + case MOVE_EXCEPTION: processMoveException(mth, block, insn, remover); break; + case ARITH: + ArithNode arithNode = (ArithNode) insn; + if (arithNode.getArgsCount() == 2) { + InsnArg litArg = arithNode.getArg(1); + if (litArg.isLiteral()) { + FieldNode f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg); + if (f != null) { + InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); + insn.replaceArg(litArg, InsnArg.wrapArg(fGet)); + } + } + } + break; + + default: + break; + } + } + remover.perform(); + } + } + + /** + * Remove unnecessary instructions + */ + private static void removeStep(MethodNode mth, InstructionRemover remover) { + for (BlockNode block : mth.getBasicBlocks()) { + remover.setBlock(block); + for (InsnNode insn : block.getInstructions()) { + switch (insn.getType()) { + case NOP: + case GOTO: + case NEW_INSTANCE: + remover.add(insn); + break; + default: break; } @@ -122,50 +172,51 @@ public class ModVisitor extends AbstractVisitor { InsnNode insn = block.getInstructions().get(insnNumber); InvokeNode inv = (InvokeNode) insn; MethodInfo callMth = inv.getCallMth(); - if (callMth.isConstructor()) { - InsnNode instArgAssignInsn = ((RegisterArg) inv.getArg(0)).getAssignInsn(); - ConstructorInsn co = new ConstructorInsn(mth, inv); - boolean remove = false; - if (co.isSuper() && (co.getArgsCount() == 0 || parentClass.isEnum())) { - remove = true; - } else if (co.isThis() && co.getArgsCount() == 0) { - MethodNode defCo = parentClass.searchMethodByName(callMth.getShortId()); - if (defCo == null || defCo.isNoCode()) { - // default constructor not implemented - remove = true; - } - } - // remove super() call in instance initializer - if (parentClass.isAnonymous() && mth.isDefaultConstructor() && co.isSuper()) { + if (!callMth.isConstructor()) { + return; + } + InsnNode instArgAssignInsn = ((RegisterArg) inv.getArg(0)).getAssignInsn(); + ConstructorInsn co = new ConstructorInsn(mth, inv); + boolean remove = false; + if (co.isSuper() && (co.getArgsCount() == 0 || parentClass.isEnum())) { + remove = true; + } else if (co.isThis() && co.getArgsCount() == 0) { + MethodNode defCo = parentClass.searchMethodByName(callMth.getShortId()); + if (defCo == null || defCo.isNoCode()) { + // default constructor not implemented remove = true; } - if (remove) { - remover.add(insn); - } else { - replaceInsn(block, insnNumber, co); - if (co.isNewInstance()) { - InsnNode newInstInsn = removeAssignChain(instArgAssignInsn, remover, InsnType.NEW_INSTANCE); - if (newInstInsn != null) { - RegisterArg instArg = newInstInsn.getResult(); - RegisterArg resultArg = co.getResult(); - if (!resultArg.equals(instArg)) { - // replace all usages of 'instArg' with result of this constructor instruction - for (RegisterArg useArg : new ArrayList(instArg.getSVar().getUseList())) { - RegisterArg dup = resultArg.duplicate(); - InsnNode parentInsn = useArg.getParentInsn(); - parentInsn.replaceArg(useArg, dup); - dup.setParentInsn(parentInsn); - resultArg.getSVar().use(dup); - } - } + } + // remove super() call in instance initializer + if (parentClass.isAnonymous() && mth.isDefaultConstructor() && co.isSuper()) { + remove = true; + } + if (remove) { + remover.add(insn); + return; + } + replaceInsn(block, insnNumber, co); + if (co.isNewInstance()) { + InsnNode newInstInsn = removeAssignChain(instArgAssignInsn, remover, InsnType.NEW_INSTANCE); + if (newInstInsn != null) { + RegisterArg instArg = newInstInsn.getResult(); + RegisterArg resultArg = co.getResult(); + if (!resultArg.equals(instArg)) { + // replace all usages of 'instArg' with result of this constructor instruction + for (RegisterArg useArg : new ArrayList(instArg.getSVar().getUseList())) { + RegisterArg dup = resultArg.duplicate(); + InsnNode parentInsn = useArg.getParentInsn(); + parentInsn.replaceArg(useArg, dup); + dup.setParentInsn(parentInsn); + resultArg.getSVar().use(dup); } } - ConstructorInsn replace = processConstructor(mth, co); - if (replace != null) { - replaceInsn(block, insnNumber, replace); - } } } + ConstructorInsn replace = processConstructor(mth, co); + if (replace != null) { + replaceInsn(block, insnNumber, replace); + } } /** @@ -193,6 +244,41 @@ public class ModVisitor extends AbstractVisitor { return newInsn; } + private static InsnNode makeFilledArrayInsn(MethodNode mth, FillArrayNode insn) { + ArgType insnArrayType = insn.getResult().getType(); + ArgType insnElementType = insnArrayType.getArrayElement(); + ArgType elType = insn.getElementType(); + if (!elType.equals(insnElementType) && !insnArrayType.equals(ArgType.OBJECT)) { + ErrorsCounter.methodError(mth, + "Incorrect type for fill-array insn " + InsnUtils.formatOffset(insn.getOffset()) + + ", element type: " + elType + ", insn element type: " + insnElementType + ); + } + if (!elType.isTypeKnown()) { + LOG.warn("Unknown array element type: {} in mth: {}", elType, mth); + elType = insnElementType.isTypeKnown() ? insnElementType : elType.selectFirst(); + if (elType == null) { + throw new JadxRuntimeException("Null array element type"); + } + } + insn.mergeElementType(elType); + elType = insn.getElementType(); + + List list = insn.getLiteralArgs(); + InsnNode filledArr = new FilledNewArrayNode(elType, list.size()); + filledArr.setResult(insn.getResult()); + for (LiteralArg arg : list) { + FieldNode f = mth.getParentClass().getConstFieldByLiteralArg(arg); + if (f != null) { + InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); + filledArr.addArg(InsnArg.wrapArg(fGet)); + } else { + filledArr.addArg(arg); + } + } + return filledArr; + } + private static boolean allArgsNull(InsnNode insn) { for (InsnArg insnArg : insn.getArguments()) { if (insnArg.isLiteral()) { @@ -226,53 +312,6 @@ public class ModVisitor extends AbstractVisitor { return null; } - /** - * Remove unnecessary instructions - */ - private static void removeStep(MethodNode mth, InstructionRemover remover) { - for (BlockNode block : mth.getBasicBlocks()) { - remover.setBlock(block); - int size = block.getInstructions().size(); - for (int i = 0; i < size; i++) { - InsnNode insn = block.getInstructions().get(i); - switch (insn.getType()) { - case NOP: - case GOTO: - case NEW_INSTANCE: - remover.add(insn); - break; - - case NEW_ARRAY: - // create array in 'fill-array' instruction - int next = i + 1; - if (next < size) { - InsnNode ni = block.getInstructions().get(next); - if (ni.getType() == InsnType.FILL_ARRAY) { - ni.getResult().merge(insn.getResult()); - ((FillArrayNode) ni).mergeElementType(insn.getResult().getType().getArrayElement()); - remover.add(insn); - } - } - break; - - case RETURN: - if (insn.getArgsCount() == 0) { - if (mth.getBasicBlocks().size() == 1 && i == size - 1) { - remover.add(insn); - } else if (mth.getMethodInfo().isClassInit()) { - remover.add(insn); - } - } - break; - - default: - break; - } - } - remover.perform(); - } - } - private static void processMoveException(MethodNode mth, BlockNode block, InsnNode insn, InstructionRemover remover) { ExcHandlerAttr excHandlerAttr = block.get(AType.EXC_HANDLER); @@ -310,6 +349,7 @@ public class ModVisitor extends AbstractVisitor { private static void replaceInsn(BlockNode block, int i, InsnNode insn) { InsnNode prevInsn = block.getInstructions().get(i); insn.copyAttributesFrom(prevInsn); + insn.setSourceLine(prevInsn.getSourceLine()); block.getInstructions().set(i, insn); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java index 07ba7292..44fd2f1b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java @@ -5,10 +5,12 @@ import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.EnumMapAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.FieldInfo; +import jadx.core.dex.instructions.FilledNewArrayNode; import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InvokeNode; import jadx.core.dex.instructions.SwitchNode; +import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.args.LiteralArg; @@ -78,7 +80,8 @@ public class ReSugarCode extends AbstractVisitor { if (len <= 0 || i + len >= size || instructions.get(i + len).getType() != InsnType.APUT) { return null; } - InsnNode filledArr = new InsnNode(InsnType.FILLED_NEW_ARRAY, len); + ArgType arrType = insn.getResult().getType(); + InsnNode filledArr = new FilledNewArrayNode(arrType.getArrayElement(), len); filledArr.setResult(insn.getResult()); for (int j = 0; j < len; j++) { InsnNode put = instructions.get(i + 1 + j); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockExceptionHandler.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockExceptionHandler.java index 6d7c0657..e92be623 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockExceptionHandler.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockExceptionHandler.java @@ -17,8 +17,6 @@ import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.utils.BlockUtils; import jadx.core.utils.InstructionRemover; -import java.util.Iterator; - public class BlockExceptionHandler extends AbstractVisitor { @Override @@ -38,16 +36,6 @@ public class BlockExceptionHandler extends AbstractVisitor { for (BlockNode block : mth.getBasicBlocks()) { processTryCatchBlocks(mth, block); } - - for (BlockNode block : mth.getBasicBlocks()) { - Iterator it = block.getInstructions().iterator(); - while (it.hasNext()) { - InsnNode insn = it.next(); - if (insn.getType() == InsnType.NOP) { - it.remove(); - } - } - } } /** diff --git a/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFillConstReplace.java b/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFillConstReplace.java new file mode 100644 index 00000000..7ed380e5 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFillConstReplace.java @@ -0,0 +1,28 @@ +package jadx.tests.integration.arrays; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestArrayFillConstReplace extends IntegrationTest { + + public static class TestCls { + public static final int CONST_INT = 0xffff; + + public int[] test() { + return new int[]{127, 129, CONST_INT}; + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("return new int[]{127, 129, CONST_INT};")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays2.java b/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays2.java new file mode 100644 index 00000000..79672f09 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays2.java @@ -0,0 +1,42 @@ +package jadx.tests.integration.arrays; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +public class TestArrays2 extends IntegrationTest { + public static class TestCls { + + private static Object test4(int type) { + if (type == 1) { + return new int[]{1, 2}; + } else if (type == 2) { + return new float[]{1, 2}; + } else if (type == 3) { + return new short[]{1, 2}; + } else if (type == 4) { + return new byte[]{1, 2}; + } else { + return null; + } + } + + public void check() { + assertThat(test4(4), instanceOf(byte[].class)); + } + } + + @Test + public void test() { + noDebugInfo(); + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("new int[]{1, 2}")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java b/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java index 19ca1527..b3d1ccfd 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java +++ b/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java @@ -30,7 +30,7 @@ public class TestFallbackMode extends IntegrationTest { String code = cls.getCode().toString(); assertThat(code, containsString("public int test(int r2) {")); - assertThat(code, containsString("r1_this = this;")); + assertThat(code, containsString("r1 = this;")); assertThat(code, containsString("L_0x0004:")); assertThat(code, not(containsString("throw new UnsupportedOperationException"))); } diff --git a/jadx-core/src/test/java/jadx/tests/smali/TestArithConst.java b/jadx-core/src/test/java/jadx/tests/smali/TestArithConst.java new file mode 100644 index 00000000..87be64cc --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/smali/TestArithConst.java @@ -0,0 +1,21 @@ +package jadx.tests.smali; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestArithConst extends SmaliTest { + + @Test + public void test() { + noDebugInfo(); + ClassNode cls = getClassNodeFromSmali("TestArithConst"); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("return i + CONST_INT;")); + } +} diff --git a/jadx-core/src/test/smali/TestArithConst.smali b/jadx-core/src/test/smali/TestArithConst.smali new file mode 100644 index 00000000..36fce2e0 --- /dev/null +++ b/jadx-core/src/test/smali/TestArithConst.smali @@ -0,0 +1,12 @@ +.class public LTestArithConst; +.super Ljava/lang/Object; + +.field public static final CONST_INT:I = 0xff + +.method private test(I)I + .registers 2 + + add-int/lit16 v0, p1, 0xff + + return v0 +.end method -- GitLab