mirror of
https://github.com/revanced/smali.git
synced 2025-05-08 18:34:32 +02:00
Handle unresolvable instructions in a more intellegent manner
Don't replace an unresolvable instruction with replacement instruction(s) that are larger, to avoid inserting extra bytes, and possibly moving jump type instructions too far from their targets. git-svn-id: https://smali.googlecode.com/svn/trunk@497 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
b6ce091ae3
commit
e24e70f9ad
@ -34,6 +34,16 @@ import org.antlr.stringtemplate.StringTemplateGroup;
|
|||||||
import org.antlr.stringtemplate.StringTemplate;
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
|
||||||
public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem<UnresolvedNullReference> {
|
public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem<UnresolvedNullReference> {
|
||||||
|
private boolean isLastInstruction;
|
||||||
|
|
||||||
|
public boolean getIsLastInstruction() {
|
||||||
|
return isLastInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsLastInstruction(boolean isLastInstruction) {
|
||||||
|
this.isLastInstruction = isLastInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg,
|
public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg,
|
||||||
UnresolvedNullReference instruction) {
|
UnresolvedNullReference instruction) {
|
||||||
super(codeItem, offset, stg, instruction);
|
super(codeItem, offset, stg, instruction);
|
||||||
@ -41,5 +51,15 @@ public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodIt
|
|||||||
|
|
||||||
protected void setAttributes(StringTemplate template) {
|
protected void setAttributes(StringTemplate template) {
|
||||||
template.setAttribute("Register", formatRegister(instruction.ObjectRegisterNum));
|
template.setAttribute("Register", formatRegister(instruction.ObjectRegisterNum));
|
||||||
|
switch (instruction.OriginalInstruction.opcode)
|
||||||
|
{
|
||||||
|
case INVOKE_VIRTUAL_RANGE_QUICK:
|
||||||
|
case INVOKE_SUPER_RANGE_QUICK:
|
||||||
|
template.setAttribute("UseInvokeRange", 1);
|
||||||
|
if (isLastInstruction) {
|
||||||
|
template.setAttribute("AddGoto", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,6 +227,23 @@ public class MethodDefinition {
|
|||||||
|
|
||||||
offset += instruction.getSize()/2;
|
offset += instruction.getSize()/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for the last uncommented instruction. If it is an UnresolvedNullReference,
|
||||||
|
* then set IsLastInstruction, so a goto will be added after it, to avoid validation
|
||||||
|
* issues
|
||||||
|
*/
|
||||||
|
for (int i=this.instructions.size()-1; i>=0; i--) {
|
||||||
|
MethodItem ins = this.instructions.get(i);
|
||||||
|
if (ins instanceof UnresolvedNullReferenceMethodItem) {
|
||||||
|
((UnresolvedNullReferenceMethodItem)ins).setIsLastInstruction(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ins instanceof CommentedOutMethodItem)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
final byte[] encodedInstructions = codeItem.getEncodedInstructions();
|
final byte[] encodedInstructions = codeItem.getEncodedInstructions();
|
||||||
|
|
||||||
@ -543,7 +560,7 @@ public class MethodDefinition {
|
|||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = (index * -1) - 1;
|
index = (index * -1) - 1;
|
||||||
}
|
}
|
||||||
//index should never by 0, so this should be safe
|
//index should never be 0, so this should be safe
|
||||||
if (index == instructions.size()) {
|
if (index == instructions.size()) {
|
||||||
//if the end address is the same as the address of the last instruction, then
|
//if the end address is the same as the address of the last instruction, then
|
||||||
//this try item ends at the next to last instruction.
|
//this try item ends at the next to last instruction.
|
||||||
|
@ -288,16 +288,20 @@ CommentedOutMethodItem(MethodItem) ::=
|
|||||||
#<MethodItem>
|
#<MethodItem>
|
||||||
>>
|
>>
|
||||||
|
|
||||||
UnresolvedNullReference(Opcode, Register) ::=
|
UnresolvedNullReference(Opcode, Register, UseInvokeRange, AddGoto) ::=
|
||||||
<<
|
<<
|
||||||
#Couldn't resolve optimized instruction while deodexing, due to the object register
|
<if(UseInvokeRange)>
|
||||||
#always being null. Replaced with generic method call
|
#Replaced unresolvable optimized invoke-*-range-quick instruction
|
||||||
|
#with a generic method call that will throw a NullPointerException
|
||||||
invoke-virtual/range {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
|
invoke-virtual/range {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
|
||||||
goto/32 0
|
<if(AddGoto)>goto/32 0<endif>
|
||||||
|
<else>
|
||||||
|
#Replaced unresolvable optimized instruction with a throw
|
||||||
|
throw <Register>
|
||||||
|
<endif>
|
||||||
>>
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ArrayData(Opcode, ElementWidth, Values) ::=
|
ArrayData(Opcode, ElementWidth, Values) ::=
|
||||||
<<
|
<<
|
||||||
.array-data <ElementWidth>
|
.array-data <ElementWidth>
|
||||||
|
@ -72,3 +72,39 @@
|
|||||||
|
|
||||||
return-void
|
return-void
|
||||||
.end method
|
.end method
|
||||||
|
|
||||||
|
.method public static UnresolvedInstructionTest1()Lsuperclass;
|
||||||
|
.registers 2
|
||||||
|
const v0, 0
|
||||||
|
|
||||||
|
#this is an unresolvable instruction, due to v0 always being null
|
||||||
|
#this instruction should be replaced with "throw v0", followed by
|
||||||
|
#a "goto/32 0", since it would otherwise be the last instruction
|
||||||
|
#in the method, which isn't allowed
|
||||||
|
invoke-virtual/range {v0 .. v0}, Lrandomclass;->getSuperclass()Lsuperclass;
|
||||||
|
|
||||||
|
#the following instructions should be commented out
|
||||||
|
move-result-object v1
|
||||||
|
return-object v1
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public static UnresolvedInstructionTest2()Lsuperclass;
|
||||||
|
.registers 2
|
||||||
|
const v0, 0
|
||||||
|
|
||||||
|
if-eqz v0, :here
|
||||||
|
|
||||||
|
#this is an unresolvable instruction, due to v0 always being null
|
||||||
|
#this instruction should be replaced with "throw v0". There shouldn't
|
||||||
|
#be a "goto/32 0" afterwards, since it won't be the last instruction
|
||||||
|
#in the method.
|
||||||
|
invoke-virtual/range {v0 .. v0}, Lrandomclass;->getSuperclass()Lsuperclass;
|
||||||
|
|
||||||
|
#the following instructions should be commented out
|
||||||
|
move-result-object v1
|
||||||
|
return-object v1
|
||||||
|
|
||||||
|
#and now back to our normal programming
|
||||||
|
:here
|
||||||
|
return-object v0
|
||||||
|
.end method
|
Loading…
x
Reference in New Issue
Block a user