diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java index aea5f7be..002cf4d0 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java @@ -34,6 +34,16 @@ import org.antlr.stringtemplate.StringTemplateGroup; import org.antlr.stringtemplate.StringTemplate; public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem { + private boolean isLastInstruction; + + public boolean getIsLastInstruction() { + return isLastInstruction; + } + + public void setIsLastInstruction(boolean isLastInstruction) { + this.isLastInstruction = isLastInstruction; + } + public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, UnresolvedNullReference instruction) { super(codeItem, offset, stg, instruction); @@ -41,5 +51,15 @@ public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodIt protected void setAttributes(StringTemplate template) { 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); + } + } + } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java index 2119b5ca..d1c31578 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -227,6 +227,23 @@ public class MethodDefinition { 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 { final byte[] encodedInstructions = codeItem.getEncodedInstructions(); @@ -543,7 +560,7 @@ public class MethodDefinition { if (index < 0) { 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 the end address is the same as the address of the last instruction, then //this try item ends at the next to last instruction. diff --git a/baksmali/src/main/resources/templates/templates/baksmali.stg b/baksmali/src/main/resources/templates/templates/baksmali.stg index 26cf0927..12355355 100644 --- a/baksmali/src/main/resources/templates/templates/baksmali.stg +++ b/baksmali/src/main/resources/templates/templates/baksmali.stg @@ -288,16 +288,20 @@ CommentedOutMethodItem(MethodItem) ::= # >> -UnresolvedNullReference(Opcode, Register) ::= +UnresolvedNullReference(Opcode, Register, UseInvokeRange, AddGoto) ::= << -#Couldn't resolve optimized instruction while deodexing, due to the object register -#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 { .. }, Ljava/lang/Object;->hashCode()I -goto/32 0 +goto/32 0 + +#Replaced unresolvable optimized instruction with a throw +throw + >> - ArrayData(Opcode, ElementWidth, Values) ::= << .array-data diff --git a/baksmali/src/test/smali/deodex_test1/main.smali b/baksmali/src/test/smali/deodex_test1/main.smali index 946b8a4e..99ffecad 100644 --- a/baksmali/src/test/smali/deodex_test1/main.smali +++ b/baksmali/src/test/smali/deodex_test1/main.smali @@ -71,4 +71,40 @@ return-void +.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 \ No newline at end of file