4

Hi I am trying to understand how to properly increase the registers in a smali virtual method. In order to inject code which will use the new register

For reference i have already read the following: https://github.com/JesusFreke/smali/wiki/Registers

This is my java code:

    public void toastMsg(String msg) {

        Toast toast = Toast.makeText(this, msg, Toast.LENGTH_LONG);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.show();

    }

In Smali it looks like this

.method public toastMsg(Ljava/lang/String;)V
    .locals 2

    const/4 v0, 0x1

    .line 26
    invoke-static {p0, p1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object p1

    const/4 v0, 0x0

    const/16 v1, 0x11

    .line 27
    invoke-virtual {p1, v1, v0, v0}, Landroid/widget/Toast;->setGravity(III)V

    .line 28
    invoke-virtual {p1}, Landroid/widget/Toast;->show()V

    return-void
.end method

Now as far as I understand it, the above smali snippet for the toastMsg method contains in total 4 registers.

.locals = 2 + 1 for the Object(this) and 1 for the parameter(String msg) to the toastMsg method.

Therefore my registers look like this

v0 - free local register
v1 - free local register
v2 => p0 (this)
v3 => p1 (the string parameter - our msg)

Now lets say I want to inject the following logcat line but I don't have any free local registers.

const-string v3, "MYAWESOMELOG"
invoke-static {v3, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

Injecting that logcat code would now of course clobber the v3 register, it will work but the value for p1 would be lost since v3 == p1.

I want to add one extra register to the .locals so that it can hold the string. and not clobber anything. Assuming based on the reference that i can simply bump up the number on the .locals variable it should give me n more local registers to use.

So if .locals 3 the registers in this method should now look like so

v0 - free local register
v1 - free local register
v2 - new free local register ?
v3 => p0 (this)
v4 => p1 (the string parameter - our msg)

Thus local register v2 should now be brand new and free to use if i understand this correctly.

So now the following smali code for logcat i hope can use the new register v2 to store the tag, and still retain the string parameter (p1)

 const-string v2, "MYAWESOMELOG"
    invoke-static {v2, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

Thus the modifed code now looks like this

.method public toastMsg(Ljava/lang/String;)V
    .locals 3 <--- increased here by 1

    const/4 v0, 0x1

    .line 25
    invoke-static {p0, p1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object p1

    const/4 v0, 0x0

    const/16 v1, 0x11

    .line 26
    invoke-virtual {p1, v1, v0, v0}, Landroid/widget/Toast;->setGravity(III)V

    .line 27

    invoke-virtual {p1}, Landroid/widget/Toast;->show()V

    # PATCH here useing the new regiser
    const-string v2, "MYAWESOMELOG"
    invoke-static {v2, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    # END PATCH
    return-void
.end method

Unfortuantly this doesn't seem to be the case so I assume I have not understood how to modify and use the new registers correctly.

I have rebuilt and installed my example but the application force closes due to a java class verification error.

apktool d example.apk
apktool b example -o example-modified.apk
java.lang.VerifyError: Verifier rejected class
com.example.androidtest.MainActivity: void com.example.androidtest.MainActivity.toastMsg(java.lang.String) failed to 
verify: void com.example.androidtest.MainActivity.toastMsg(java.lang.String): 
[0x10] register v4 has type Reference: android.widget.Toast but expected Precise Reference: java.lang.String 
(declaration of 'com.example.androidtest.MainActivity' appears in 
/data/app/com.example.androidtest-m1NPS9_tJaTgZLY7-1Ev6w==/base.apk)

It seems that I have messed up something with the registers but i don't quite understand where the issue is. Increasing the .locals by 1 should give me an extra register and also automatically shift the parameter references down as well therefore v4 should point to p1 and be a string but instead it is pointing to android.widget.Toast.

So am I not able to increase the .locals variable in a method and use the new register? Do i have to declare the new register and initalize it in another way?

The strange thing is that there seems to some questions already that point to the answer that I should infact be able to increase the registers.

I am pretty confident that the file was not dissasembled with the -p/--no-parameter-registers option. I just used the defaults in the apktool d

Smali: Increase number of registers

This answer also states that I should be able to actually do this https://stackoverflow.com/a/12648626/2678928

So the question is why do i not have the new register v2 when I increased the .locals variable or if I do then why are the registers not shifted down? or if all that is correct, then perhapse i have not used the correct register and also not injected the patch in the right place?

Sevren
  • 301
  • 4
  • 10

2 Answers2

4

The issue was exactly what JesusFreke described but I had also patched the code in the wrong place. I was trying to call the the Log method and had failed to understand that p1's type had changed from String to android/widget/Toast by the end of the function.

The following works using the new register v2

.method public toastMsg(Ljava/lang/String;)V
    .locals 3

    const/4 v0, 0x1

    .line 26

    # PATCH HERE
    const-string v2, "MYAWESOMELOG"
    invoke-static {v2, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    # END PATH

    invoke-static {p0, p1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object p1

    const/4 v0, 0x0

    const/16 v1, 0x11

    .line 27
    invoke-virtual {p1, v1, v0, v0}, Landroid/widget/Toast;->setGravity(III)V



    .line 28
    invoke-virtual {p1}, Landroid/widget/Toast;->show()V


    return-void
.end method

Here is a more indepth explanation:

Increasing the .locals works as normal and looks like this at the begining of the toastMsg method call

v0 - free local register
v1 - free local register
v2 - free local register
v3 => p0 (this)
v4 => p1 (the string parameter - our msg)

The following lines however now changes the values in the register, observe that v4 == p1 Before these lines are executed v4(p1) points to a string object (our parameter msg)

invoke-static {p0, p1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object p1

After the move-result-object p1 in the code snippet above the value in the registers now look like this

v0 - 0x1
v1 - free local register
v2 - "MYAWESOMELOG"
v3 => p0 (this)
v4 => p1 (android/widget/Toast)

We no longer have the original string value that was passed into the toastMsg method

If i wanted to use the original p1 value I would have to use it BEFORE the move-result-object p1 line. Alternatively I could again increase the locals and copy/store the result of p1 at the beginning of the function.

Sevren
  • 301
  • 4
  • 10
2

The problem is with this instruction

invoke-static {v2, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

You're passing p1 as the second argument, but p1 still contains the toast object. The method is expecting a string object for the second argument, not a toast object.

JesusFreke
  • 19,784
  • 5
  • 65
  • 68