mirror of
https://github.com/revanced/smali.git
synced 2025-05-29 12:20:11 +02:00
Handle a rare case where deodexing an instruction invalidates a previously deodexed instruction somewhere else because of the new register information available
git-svn-id: https://smali.googlecode.com/svn/trunk@448 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
8b260a1d81
commit
726d88404d
@ -195,26 +195,21 @@ public class DeodexUtil {
|
|||||||
public List<Instruction> deodexerizeCode(CodeItem codeItem) {
|
public List<Instruction> deodexerizeCode(CodeItem codeItem) {
|
||||||
List<insn> insns = makeInsnList(codeItem);
|
List<insn> insns = makeInsnList(codeItem);
|
||||||
|
|
||||||
byte[] encodedInstructions = codeItem.getEncodedInstructions().clone();
|
|
||||||
|
|
||||||
boolean didSomething;
|
boolean didSomething;
|
||||||
boolean somethingLeftToDo;
|
boolean somethingLeftToDo;
|
||||||
do {
|
do {
|
||||||
int offset = 0;
|
|
||||||
didSomething = false;
|
didSomething = false;
|
||||||
somethingLeftToDo = false;
|
somethingLeftToDo = false;
|
||||||
for (insn i: insns) {
|
for (insn i: insns) {
|
||||||
if (i.instruction.opcode.odexOnly && i.fixedInstruction == null) {
|
if (i.instruction.opcode.odexOnly && i.fixedInstruction == null) {
|
||||||
if (deodexInstruction(i, offset, encodedInstructions)) {
|
if (deodexInstruction(i)) {
|
||||||
didSomething = true;
|
didSomething = true;
|
||||||
} else {
|
} else {
|
||||||
somethingLeftToDo = true;
|
somethingLeftToDo = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += i.instruction.getSize()/2;
|
|
||||||
}
|
}
|
||||||
} while (didSomething && somethingLeftToDo);
|
} while (didSomething);
|
||||||
if (somethingLeftToDo) {
|
if (somethingLeftToDo) {
|
||||||
System.err.println("warning: could not fully deodex the method " +
|
System.err.println("warning: could not fully deodex the method " +
|
||||||
codeItem.getParent().method.getContainingClass().getTypeDescriptor() + "->" +
|
codeItem.getParent().method.getContainingClass().getTypeDescriptor() + "->" +
|
||||||
@ -234,7 +229,7 @@ public class DeodexUtil {
|
|||||||
return instructions;
|
return instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean deodexInstruction(insn i, int offset, byte[] encodedInstructions) {
|
private boolean deodexInstruction(insn i) {
|
||||||
switch (i.instruction.opcode) {
|
switch (i.instruction.opcode) {
|
||||||
case INVOKE_EXECUTE_INLINE:
|
case INVOKE_EXECUTE_INLINE:
|
||||||
{
|
{
|
||||||
@ -838,6 +833,12 @@ public class DeodexUtil {
|
|||||||
*/
|
*/
|
||||||
public Instruction fixedInstruction;
|
public Instruction fixedInstruction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is only used for odexed instructions, and should contain the register num of the object reference
|
||||||
|
* that the instruction acts on. More specifically, it's only for odexed instructions that require the
|
||||||
|
* type of the object register in order to look up the correct information.
|
||||||
|
*/
|
||||||
|
public int objectRegisterNum = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this instruction can be the first instruction to successfully execute. This could be the first
|
* Whether this instruction can be the first instruction to successfully execute. This could be the first
|
||||||
@ -864,6 +865,29 @@ public class DeodexUtil {
|
|||||||
this.canThrow = DeodexUtil.instructionThrowTable.get(instruction.opcode.value & 0xFF);
|
this.canThrow = DeodexUtil.instructionThrowTable.get(instruction.opcode.value & 0xFF);
|
||||||
this.insnsMap = insnsMap;
|
this.insnsMap = insnsMap;
|
||||||
|
|
||||||
|
if (instruction.opcode.odexOnly) {
|
||||||
|
switch (instruction.opcode) {
|
||||||
|
case IGET_QUICK:
|
||||||
|
case IGET_WIDE_QUICK:
|
||||||
|
case IGET_OBJECT_QUICK:
|
||||||
|
case IPUT_QUICK:
|
||||||
|
case IPUT_WIDE_QUICK:
|
||||||
|
case IPUT_OBJECT_QUICK:
|
||||||
|
objectRegisterNum = ((Instruction22cs)instruction).getRegisterB();
|
||||||
|
break;
|
||||||
|
case INVOKE_VIRTUAL_QUICK:
|
||||||
|
case INVOKE_SUPER_QUICK:
|
||||||
|
objectRegisterNum = ((Instruction35ms)instruction).getRegisterD();
|
||||||
|
break;
|
||||||
|
case INVOKE_VIRTUAL_RANGE_QUICK:
|
||||||
|
case INVOKE_SUPER_RANGE_QUICK:
|
||||||
|
objectRegisterNum = ((Instruction3rms)instruction).getStartRegister();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
registerMap = new RegisterType[codeItem.getRegisterCount()];
|
registerMap = new RegisterType[codeItem.getRegisterCount()];
|
||||||
registerTypes = new TypeIdItem[codeItem.getRegisterCount()];
|
registerTypes = new TypeIdItem[codeItem.getRegisterCount()];
|
||||||
|
|
||||||
@ -1348,6 +1372,13 @@ public class DeodexUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if the next instruction is an odexed instruction and requires the type of it's object
|
||||||
|
//register to figure out the correct method/field to use, then objectRegisterNum will
|
||||||
|
//be set to the register number containing the object reference that it uses.
|
||||||
|
//if that instruction has already been fixed, but we have newer information and update
|
||||||
|
//the register type, we need to clear out the fixed instruction, so it gets re-fixed,
|
||||||
|
//with the new register information
|
||||||
|
|
||||||
for (insn nextInsn: successors) {
|
for (insn nextInsn: successors) {
|
||||||
boolean somethingChanged = false;
|
boolean somethingChanged = false;
|
||||||
|
|
||||||
@ -1367,6 +1398,10 @@ public class DeodexUtil {
|
|||||||
TypeIdItem regReferenceType = findCommonSuperclass(registerTypes[i],
|
TypeIdItem regReferenceType = findCommonSuperclass(registerTypes[i],
|
||||||
nextInsn.registerTypes[i]);
|
nextInsn.registerTypes[i]);
|
||||||
if (regReferenceType != nextInsn.registerTypes[i]) {
|
if (regReferenceType != nextInsn.registerTypes[i]) {
|
||||||
|
//see comment above for loop
|
||||||
|
if (i == nextInsn.objectRegisterNum) {
|
||||||
|
nextInsn.fixedInstruction = null;
|
||||||
|
}
|
||||||
somethingChanged = true;
|
somethingChanged = true;
|
||||||
nextInsn.registerTypes[i] = regReferenceType;
|
nextInsn.registerTypes[i] = regReferenceType;
|
||||||
}
|
}
|
||||||
@ -1382,12 +1417,22 @@ public class DeodexUtil {
|
|||||||
if (registerType == RegisterType.Reference) {
|
if (registerType == RegisterType.Reference) {
|
||||||
if (registerReferenceType != null) {
|
if (registerReferenceType != null) {
|
||||||
if (nextInsn.registerTypes[registerNum] != registerReferenceType) {
|
if (nextInsn.registerTypes[registerNum] != registerReferenceType) {
|
||||||
|
//see comment above for loop
|
||||||
|
if (registerNum == nextInsn.objectRegisterNum) {
|
||||||
|
nextInsn.fixedInstruction = null;
|
||||||
|
}
|
||||||
|
|
||||||
somethingChanged = true;
|
somethingChanged = true;
|
||||||
nextInsn.registerTypes[registerNum] = registerReferenceType;
|
nextInsn.registerTypes[registerNum] = registerReferenceType;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TypeIdItem type = destRegisterType();
|
TypeIdItem type = destRegisterType();
|
||||||
if (type != nextInsn.registerTypes[registerNum]) {
|
if (type != nextInsn.registerTypes[registerNum]) {
|
||||||
|
//see comment above for loop
|
||||||
|
if (registerNum == nextInsn.objectRegisterNum) {
|
||||||
|
nextInsn.fixedInstruction = null;
|
||||||
|
}
|
||||||
|
|
||||||
somethingChanged = true;
|
somethingChanged = true;
|
||||||
nextInsn.registerTypes[registerNum] = type;
|
nextInsn.registerTypes[registerNum] = type;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user