mirror of
https://github.com/revanced/smali.git
synced 2025-05-02 23:54:38 +02:00
Add better handling for various types of invalid instructions
This commit is contained in:
parent
9057764c22
commit
4f2620415d
@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
|
|||||||
import org.jf.baksmali.baksmaliOptions;
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
import org.jf.dexlib2.AccessFlags;
|
import org.jf.dexlib2.AccessFlags;
|
||||||
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.*;
|
import org.jf.dexlib2.iface.*;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||||
@ -79,8 +80,15 @@ public class ClassDefinition {
|
|||||||
case SPUT_SHORT:
|
case SPUT_SHORT:
|
||||||
case SPUT_WIDE: {
|
case SPUT_WIDE: {
|
||||||
Instruction21c ins = (Instruction21c)instruction;
|
Instruction21c ins = (Instruction21c)instruction;
|
||||||
FieldReference fieldRef = (FieldReference)ins.getReference();
|
FieldReference fieldRef = null;
|
||||||
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
try {
|
||||||
|
fieldRef = (FieldReference)ins.getReference();
|
||||||
|
} catch (InvalidItemIndex ex) {
|
||||||
|
// just ignore it for now. We'll deal with it later, when processing the instructions
|
||||||
|
// themselves
|
||||||
|
}
|
||||||
|
if (fieldRef != null &&
|
||||||
|
fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
||||||
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -29,16 +29,21 @@
|
|||||||
package org.jf.baksmali.Adaptors.Format;
|
package org.jf.baksmali.Adaptors.Format;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload;
|
||||||
import org.jf.baksmali.Adaptors.MethodItem;
|
import org.jf.baksmali.Adaptors.MethodItem;
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
|
||||||
import org.jf.baksmali.Renderers.LongRenderer;
|
import org.jf.baksmali.Renderers.LongRenderer;
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
import org.jf.dexlib2.Opcode;
|
||||||
import org.jf.dexlib2.ReferenceType;
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.VerificationError;
|
import org.jf.dexlib2.VerificationError;
|
||||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.instruction.*;
|
import org.jf.dexlib2.iface.instruction.*;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
||||||
import org.jf.dexlib2.iface.reference.Reference;
|
import org.jf.dexlib2.iface.reference.Reference;
|
||||||
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -60,29 +65,105 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isAllowedOdex(@Nonnull Opcode opcode) {
|
||||||
|
baksmaliOptions options = methodDef.classDef.options;
|
||||||
|
if (options.allowOdex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodDef.classDef.options.apiLevel >= 14) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opcode.isOdexedInstanceVolatile() || opcode.isOdexedStaticVolatile() ||
|
||||||
|
opcode == Opcode.THROW_VERIFICATION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
boolean invalidReference = false;
|
Opcode opcode = instruction.getOpcode();
|
||||||
if (instruction instanceof ReferenceInstruction) {
|
String verificationErrorName = null;
|
||||||
try {
|
String referenceString = null;
|
||||||
Reference reference = ((ReferenceInstruction)instruction).getReference();
|
|
||||||
} catch (InvalidItemIndex ex) {
|
|
||||||
invalidReference = true;
|
|
||||||
|
|
||||||
writer.write("#invalid ");
|
boolean commentOutInstruction = false;
|
||||||
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
|
|
||||||
writer.write(" index: ");
|
if (instruction instanceof Instruction20bc) {
|
||||||
writer.printSignedIntAsDec(ex.getInvalidIndex());
|
int verificationError = ((Instruction20bc)instruction).getVerificationError();
|
||||||
writer.write("\n#");
|
verificationErrorName = VerificationError.getVerificationErrorName(verificationError);
|
||||||
|
if (verificationErrorName == null) {
|
||||||
|
writer.write("#was invalid verification error type: ");
|
||||||
|
writer.printSignedIntAsDec(verificationError);
|
||||||
|
writer.write("\n");
|
||||||
|
verificationErrorName = "generic-error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instruction instanceof ReferenceInstruction) {
|
||||||
|
ReferenceInstruction referenceInstruction = (ReferenceInstruction)instruction;
|
||||||
|
try {
|
||||||
|
Reference reference = referenceInstruction.getReference();
|
||||||
|
referenceString = ReferenceUtil.getReferenceString(reference);
|
||||||
|
assert referenceString != null;
|
||||||
|
} catch (InvalidItemIndex ex) {
|
||||||
|
writer.write("#");
|
||||||
|
writer.write(ex.getMessage());
|
||||||
|
writer.write("\n");
|
||||||
|
commentOutInstruction = true;
|
||||||
|
|
||||||
|
referenceString = String.format("%s@%d",
|
||||||
|
ReferenceType.toString(referenceInstruction.getReferenceType()),
|
||||||
|
ex.getInvalidIndex());
|
||||||
|
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||||
|
writer.write("#invalid reference type: ");
|
||||||
|
writer.printSignedIntAsDec(ex.getReferenceType());
|
||||||
|
commentOutInstruction = true;
|
||||||
|
|
||||||
|
referenceString = "invalid_reference";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction instanceof Instruction31t) {
|
||||||
|
Opcode payloadOpcode;
|
||||||
|
switch (instruction.getOpcode()) {
|
||||||
|
case PACKED_SWITCH:
|
||||||
|
payloadOpcode = Opcode.PACKED_SWITCH_PAYLOAD;
|
||||||
|
break;
|
||||||
|
case SPARSE_SWITCH:
|
||||||
|
payloadOpcode = Opcode.SPARSE_SWITCH_PAYLOAD;
|
||||||
|
break;
|
||||||
|
case FILL_ARRAY_DATA:
|
||||||
|
payloadOpcode = Opcode.ARRAY_PAYLOAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Invalid 31t opcode: %s", instruction.getOpcode());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
methodDef.findSwitchPayload(this.codeAddress + ((Instruction31t)instruction).getCodeOffset(),
|
||||||
|
payloadOpcode);
|
||||||
|
} catch (InvalidSwitchPayload ex) {
|
||||||
|
writer.write("#invalid payload reference");
|
||||||
|
commentOutInstruction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode.odexOnly()) {
|
||||||
|
if (!isAllowedOdex(opcode)) {
|
||||||
|
writer.write("#disallowed odex opcode\n");
|
||||||
|
commentOutInstruction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commentOutInstruction) {
|
||||||
|
writer.write("#");
|
||||||
|
}
|
||||||
|
|
||||||
switch (instruction.getOpcode().format) {
|
switch (instruction.getOpcode().format) {
|
||||||
case Format10t:
|
case Format10t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format10x:
|
case Format10x:
|
||||||
if (instruction instanceof UnknownInstruction) {
|
if (instruction instanceof UnknownInstruction) {
|
||||||
writer.write("#unknown opcode: 0x");
|
writer.write("#unknown opcode: 0x");
|
||||||
@ -90,47 +171,47 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
return true;
|
break;
|
||||||
case Format11n:
|
case Format11n:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
return true;
|
break;
|
||||||
case Format11x:
|
case Format11x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format12x:
|
case Format12x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format20bc:
|
case Format20bc:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeVerificationErrorType(writer);
|
writer.write(verificationErrorName);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format20t:
|
case Format20t:
|
||||||
case Format30t:
|
case Format30t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format21c:
|
case Format21c:
|
||||||
case Format31c:
|
case Format31c:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format21ih:
|
case Format21ih:
|
||||||
case Format21lh:
|
case Format21lh:
|
||||||
case Format21s:
|
case Format21s:
|
||||||
@ -143,7 +224,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
if (instruction.getOpcode().setsWideRegister() == false)
|
if (instruction.getOpcode().setsWideRegister() == false)
|
||||||
writeResourceId(writer);
|
writeResourceId(writer);
|
||||||
return true;
|
break;
|
||||||
case Format21t:
|
case Format21t:
|
||||||
case Format31t:
|
case Format31t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -151,7 +232,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22b:
|
case Format22b:
|
||||||
case Format22s:
|
case Format22s:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -161,7 +242,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22c:
|
case Format22c:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -169,8 +250,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format22cs:
|
case Format22cs:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -179,7 +260,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeFieldOffset(writer);
|
writeFieldOffset(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22t:
|
case Format22t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -188,7 +269,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22x:
|
case Format22x:
|
||||||
case Format32x:
|
case Format32x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -196,7 +277,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format23x:
|
case Format23x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -205,54 +286,61 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeThirdRegister(writer);
|
writeThirdRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format35c:
|
case Format35c:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRegisters(writer);
|
writeInvokeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format35mi:
|
case Format35mi:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRegisters(writer);
|
writeInvokeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeInlineIndex(writer);
|
writeInlineIndex(writer);
|
||||||
return true;
|
break;
|
||||||
case Format35ms:
|
case Format35ms:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRegisters(writer);
|
writeInvokeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeVtableIndex(writer);
|
writeVtableIndex(writer);
|
||||||
return true;
|
break;
|
||||||
case Format3rc:
|
case Format3rc:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format3rmi:
|
case Format3rmi:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeInlineIndex(writer);
|
writeInlineIndex(writer);
|
||||||
return true;
|
break;
|
||||||
case Format3rms:
|
case Format3rms:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeVtableIndex(writer);
|
writeVtableIndex(writer);
|
||||||
return true;
|
break;
|
||||||
}
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (commentOutInstruction) {
|
||||||
|
writer.write("\nnop");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
||||||
writer.write(instruction.getOpcode().name);
|
writer.write(instruction.getOpcode().name);
|
||||||
}
|
}
|
||||||
@ -367,20 +455,4 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writer.write("vtable@");
|
writer.write("vtable@");
|
||||||
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
|
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeReference(IndentingWriter writer) throws IOException {
|
|
||||||
try {
|
|
||||||
ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType,
|
|
||||||
((ReferenceInstruction)instruction).getReference());
|
|
||||||
} catch (InvalidItemIndex ex) {
|
|
||||||
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
|
|
||||||
writer.write("@");
|
|
||||||
writer.printSignedIntAsDec(ex.getInvalidIndex());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
|
||||||
int verificationError = ((Instruction20bc)instruction).getVerificationError();
|
|
||||||
writer.write(VerificationError.getVerificationErrorName(verificationError));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import org.jf.dexlib2.ReferenceType;
|
|||||||
import org.jf.dexlib2.analysis.AnalysisException;
|
import org.jf.dexlib2.analysis.AnalysisException;
|
||||||
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
||||||
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.*;
|
import org.jf.dexlib2.iface.*;
|
||||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
@ -46,6 +47,7 @@ import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
|||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||||
import org.jf.dexlib2.util.InstructionOffsetMap;
|
import org.jf.dexlib2.util.InstructionOffsetMap;
|
||||||
|
import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
|
||||||
import org.jf.dexlib2.util.ReferenceUtil;
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
import org.jf.dexlib2.util.TypeUtils;
|
import org.jf.dexlib2.util.TypeUtils;
|
||||||
@ -92,17 +94,33 @@ public class MethodDefinition {
|
|||||||
|
|
||||||
Opcode opcode = instruction.getOpcode();
|
Opcode opcode = instruction.getOpcode();
|
||||||
if (opcode == Opcode.PACKED_SWITCH) {
|
if (opcode == Opcode.PACKED_SWITCH) {
|
||||||
|
boolean valid = true;
|
||||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
|
try {
|
||||||
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
||||||
|
} catch (InvalidSwitchPayload ex) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
packedSwitchMap.append(targetOffset, codeOffset);
|
packedSwitchMap.append(targetOffset, codeOffset);
|
||||||
|
}
|
||||||
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
||||||
|
boolean valid = true;
|
||||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
|
try {
|
||||||
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
||||||
|
} catch (InvalidSwitchPayload ex) {
|
||||||
|
valid = false;
|
||||||
|
// The offset to the payload instruction was invalid. Nothing to do, except that we won't
|
||||||
|
// add this instruction to the map.
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
sparseSwitchMap.append(targetOffset, codeOffset);
|
sparseSwitchMap.append(targetOffset, codeOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}catch (Exception ex) {
|
}catch (Exception ex) {
|
||||||
String methodString;
|
String methodString;
|
||||||
try {
|
try {
|
||||||
@ -187,8 +205,13 @@ public class MethodDefinition {
|
|||||||
writer.write(".end method\n");
|
writer.write(".end method\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findSwitchPayload(int targetOffset, Opcode type) {
|
public int findSwitchPayload(int targetOffset, Opcode type) {
|
||||||
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
int targetIndex;
|
||||||
|
try {
|
||||||
|
targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
||||||
|
} catch (InvalidInstructionOffset ex) {
|
||||||
|
throw new InvalidSwitchPayload(targetOffset);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: does dalvik let you pad with multiple nops?
|
//TODO: does dalvik let you pad with multiple nops?
|
||||||
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
||||||
@ -205,7 +228,7 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
|
throw new InvalidSwitchPayload(targetOffset);
|
||||||
} else {
|
} else {
|
||||||
return targetOffset;
|
return targetOffset;
|
||||||
}
|
}
|
||||||
@ -337,10 +360,16 @@ public class MethodDefinition {
|
|||||||
Opcode opcode = instruction.getOpcode();
|
Opcode opcode = instruction.getOpcode();
|
||||||
|
|
||||||
if (opcode.referenceType == ReferenceType.METHOD) {
|
if (opcode.referenceType == ReferenceType.METHOD) {
|
||||||
MethodReference methodReference =
|
MethodReference methodReference = null;
|
||||||
(MethodReference)((ReferenceInstruction)instruction).getReference();
|
try {
|
||||||
|
methodReference = (MethodReference)((ReferenceInstruction)instruction).getReference();
|
||||||
|
} catch (InvalidItemIndex ex) {
|
||||||
|
// just ignore it for now. We'll deal with it later, when processing the instructions
|
||||||
|
// themselves
|
||||||
|
}
|
||||||
|
|
||||||
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
if (methodReference != null &&
|
||||||
|
SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
||||||
SyntheticAccessorResolver.AccessedMember accessedMember =
|
SyntheticAccessorResolver.AccessedMember accessedMember =
|
||||||
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
||||||
if (accessedMember != null) {
|
if (accessedMember != null) {
|
||||||
@ -510,4 +539,17 @@ public class MethodDefinition {
|
|||||||
return labels.values();
|
return labels.values();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InvalidSwitchPayload extends ExceptionWithContext {
|
||||||
|
private final int payloadOffset;
|
||||||
|
|
||||||
|
public InvalidSwitchPayload(int payloadOffset) {
|
||||||
|
super("No switch payload at offset: %d", payloadOffset);
|
||||||
|
this.payloadOffset = payloadOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPayloadOffset() {
|
||||||
|
return payloadOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,9 @@ public class ReferenceFormatter {
|
|||||||
return;
|
return;
|
||||||
case ReferenceType.FIELD:
|
case ReferenceType.FIELD:
|
||||||
ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference);
|
ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown reference type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ public class baksmaliOptions {
|
|||||||
public boolean outputDebugInfo = true;
|
public boolean outputDebugInfo = true;
|
||||||
public boolean addCodeOffsets = false;
|
public boolean addCodeOffsets = false;
|
||||||
public boolean noAccessorComments = false;
|
public boolean noAccessorComments = false;
|
||||||
|
public boolean allowOdex = false;
|
||||||
public boolean deodex = false;
|
public boolean deodex = false;
|
||||||
public boolean ignoreErrors = false;
|
public boolean ignoreErrors = false;
|
||||||
public boolean checkPackagePrivateAccess = false;
|
public boolean checkPackagePrivateAccess = false;
|
||||||
|
@ -255,6 +255,7 @@ public class main {
|
|||||||
System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
|
System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
|
||||||
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
|
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
|
||||||
System.err.println("option");
|
System.err.println("option");
|
||||||
|
options.allowOdex = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
options.deodex = false;
|
options.deodex = false;
|
||||||
|
@ -34,6 +34,7 @@ package org.jf.dexlib2;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class VerificationError {
|
public class VerificationError {
|
||||||
@ -61,6 +62,7 @@ public class VerificationError {
|
|||||||
verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR);
|
verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public static String getVerificationErrorName(int verificationError) {
|
public static String getVerificationErrorName(int verificationError) {
|
||||||
switch (verificationError) {
|
switch (verificationError) {
|
||||||
case GENERIC:
|
case GENERIC:
|
||||||
|
@ -435,6 +435,14 @@ public class MutableMethodImplementation implements MethodImplementation {
|
|||||||
}
|
}
|
||||||
case SPARSE_SWITCH_PAYLOAD:
|
case SPARSE_SWITCH_PAYLOAD:
|
||||||
case PACKED_SWITCH_PAYLOAD:
|
case PACKED_SWITCH_PAYLOAD:
|
||||||
|
if (((BuilderSwitchPayload)instruction).referrer == null) {
|
||||||
|
// if the switch payload isn't referenced, just remove it
|
||||||
|
removeInstruction(index);
|
||||||
|
index--;
|
||||||
|
madeChanges = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// intentional fall-through
|
||||||
case ARRAY_PAYLOAD: {
|
case ARRAY_PAYLOAD: {
|
||||||
if ((location.codeAddress & 0x01) != 0) {
|
if ((location.codeAddress & 0x01) != 0) {
|
||||||
int previousIndex = location.index - 1;
|
int previousIndex = location.index - 1;
|
||||||
|
@ -59,7 +59,7 @@ public class InstructionOffsetMap {
|
|||||||
int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset);
|
int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
if (exact) {
|
if (exact) {
|
||||||
throw new ExceptionWithContext("No instruction at offset %d", codeOffset);
|
throw new InvalidInstructionOffset(codeOffset);
|
||||||
} else {
|
} else {
|
||||||
// This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can
|
// This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can
|
||||||
// ignore this case, because codeOffset will always be non-negative, and the code offset of the first
|
// ignore this case, because codeOffset will always be non-negative, and the code offset of the first
|
||||||
@ -72,8 +72,34 @@ public class InstructionOffsetMap {
|
|||||||
|
|
||||||
public int getInstructionCodeOffset(int index) {
|
public int getInstructionCodeOffset(int index) {
|
||||||
if (index < 0 || index >= instructionCodeOffsets.length) {
|
if (index < 0 || index >= instructionCodeOffsets.length) {
|
||||||
throw new ExceptionWithContext("Index out of bounds: %d", index);
|
throw new InvalidInstructionIndex(index);
|
||||||
}
|
}
|
||||||
return instructionCodeOffsets[index];
|
return instructionCodeOffsets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InvalidInstructionOffset extends ExceptionWithContext {
|
||||||
|
private final int instructionOffset;
|
||||||
|
|
||||||
|
public InvalidInstructionOffset(int instructionOffset) {
|
||||||
|
super("No instruction at offset %d", instructionOffset);
|
||||||
|
this.instructionOffset = instructionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInstructionOffset() {
|
||||||
|
return instructionOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvalidInstructionIndex extends ExceptionWithContext {
|
||||||
|
private final int instructionIndex;
|
||||||
|
|
||||||
|
public InvalidInstructionIndex(int instructionIndex) {
|
||||||
|
super("Instruction index out of bounds: %d", instructionIndex);
|
||||||
|
this.instructionIndex = instructionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInstructionIndex() {
|
||||||
|
return instructionIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user