From 20bf85b14dec5b86c7e1226a9346afe1799eaca4 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 27 Jan 2018 19:58:14 +0300 Subject: [PATCH] core: ignore bogus opcode decode (#214) --- .../core/dex/instructions/InsnDecoder.java | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) 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 7b0a0c5e6..5142a94f2 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 @@ -1,5 +1,19 @@ package jadx.core.dex.instructions; +import java.io.EOFException; + +import com.android.dex.Code; +import com.android.dx.io.OpcodeInfo; +import com.android.dx.io.Opcodes; +import com.android.dx.io.instructions.DecodedInstruction; +import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction; +import com.android.dx.io.instructions.PackedSwitchPayloadDecodedInstruction; +import com.android.dx.io.instructions.ShortArrayCodeInput; +import com.android.dx.io.instructions.SparseSwitchPayloadDecodedInstruction; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.instructions.args.ArgType; @@ -12,16 +26,8 @@ import jadx.core.dex.nodes.MethodNode; import jadx.core.utils.InsnUtils; import jadx.core.utils.exceptions.DecodeException; -import com.android.dex.Code; -import com.android.dx.io.OpcodeInfo; -import com.android.dx.io.Opcodes; -import com.android.dx.io.instructions.DecodedInstruction; -import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction; -import com.android.dx.io.instructions.PackedSwitchPayloadDecodedInstruction; -import com.android.dx.io.instructions.ShortArrayCodeInput; -import com.android.dx.io.instructions.SparseSwitchPayloadDecodedInstruction; - public class InsnDecoder { + private static final Logger LOG = LoggerFactory.getLogger(InsnDecoder.class); private final MethodNode method; private final DexNode dex; @@ -37,26 +43,36 @@ public class InsnDecoder { int size = encodedInstructions.length; DecodedInstruction[] decoded = new DecodedInstruction[size]; ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions); - try { while (in.hasMore()) { - decoded[in.cursor()] = DecodedInstruction.decode(in); + decoded[in.cursor()] = decodeRawInsn(in); } } catch (Exception e) { - throw new DecodeException(method, "", e); + throw new DecodeException(method, e.getMessage(), e); } insnArr = decoded; } + private DecodedInstruction decodeRawInsn(ShortArrayCodeInput in) throws EOFException { + int opcodeUnit = in.read(); + int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit); + OpcodeInfo.Info opcodeInfo; + try { + opcodeInfo = OpcodeInfo.get(opcode); + } catch (IllegalArgumentException e) { + LOG.warn("Ignore decode error: '{}', replace with NOP instruction", e.getMessage()); + opcodeInfo = OpcodeInfo.NOP; + } + return opcodeInfo.getFormat().decode(opcodeUnit, in); + } + public InsnNode[] process() throws DecodeException { InsnNode[] instructions = new InsnNode[insnArr.length]; for (int i = 0; i < insnArr.length; i++) { DecodedInstruction rawInsn = insnArr[i]; if (rawInsn != null) { InsnNode insn = decode(rawInsn, i); - if (insn != null) { - insn.setOffset(i); - } + insn.setOffset(i); instructions[i] = insn; } else { instructions[i] = null; @@ -66,15 +82,14 @@ public class InsnDecoder { return instructions; } + @NotNull private InsnNode decode(DecodedInstruction insn, int offset) throws DecodeException { switch (insn.getOpcode()) { case Opcodes.NOP: - return new InsnNode(InsnType.NOP, 0); - case Opcodes.PACKED_SWITCH_PAYLOAD: case Opcodes.SPARSE_SWITCH_PAYLOAD: case Opcodes.FILL_ARRAY_DATA_PAYLOAD: - return null; + return new InsnNode(InsnType.NOP, 0); // move-result will be process in invoke and filled-new-array instructions case Opcodes.MOVE_RESULT: @@ -565,9 +580,10 @@ public class InsnDecoder { return insn(InsnType.MONITOR_EXIT, null, InsnArg.reg(insn, 0, ArgType.UNKNOWN_OBJECT)); - } - throw new DecodeException("Unknown instruction: '" + OpcodeInfo.getName(insn.getOpcode()) + "'"); + default: + throw new DecodeException("Unknown instruction: '" + OpcodeInfo.getName(insn.getOpcode()) + "'"); + } } private InsnNode decodeSwitch(DecodedInstruction insn, int offset, boolean packed) {