smail语法中的疑惑与易混淆点

以下内容不保证正确,仅供参考
最近在完成移动智能终端安全的课程实验时研究了一下smali的语法,顺便记录一下几个比较具有迷惑性的地方
比如以下两行代码:

invoke-virtual {p0, v0}, Lcom/example/smali/MainActivity;->setContentView(I)V
 iput-object v0, p0, Lcom/example/smali/MainActivity;->tv:Landroid/widget/TextView;

在这两行代码中,寄存器v0和p0究竟是拿来干什么的?

我的研究方法是:先写一段java源代码,把它反编译成smali文件,研究两者对应的关系,如果有发现结果,还可以适当的更改源代码以验证自己的结论。这样的优点是结论是自己发现的,印象会更深刻;缺点是频繁的反编译比较繁琐,要是在AS上有即时的反编译插件就好了。
话不多说,源代码如下,一个按钮注册点击事件,点击后改变TextView内容的demo:

public class MainActivity extends AppCompatActivity {
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = findViewById(R.id.tv);
        Button btn = findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tv.setText("Hello Xidian!");
            }
        });
    }

对应的smali代码如下:(MarkDown不支持Smali,所以笔者尽量优化了一下阅读体验)

.class public Lcom/example/smali/MainActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "MainActivity.java"

.field tv:Landroid/widget/TextView;

.method public constructor <init>()V    #MainActivity的构造器
    .locals 0  
    invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V
    return-void
.end method

.method protected onCreate(Landroid/os/Bundle;)V	#重写的onCreate方法
    .locals 2   
    .param p1, "savedInstanceState"   
    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
    const v0, 0x7f09001c
    invoke-virtual {p0, v0}, Lcom/example/smali/MainActivity;->setContentView(I)V  	#setContentView()
    
    const v0, 0x7f07008e
    invoke-virtual {p0, v0}, Lcom/example/smali/MainActivity;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/TextView;    #强制类型转换
    iput-object v0, p0, Lcom/example/smali/MainActivity;->tv:Landroid/widget/TextView;	#tv的findViewById
    
    const v0, 0x7f070022
    invoke-virtual {p0, v0}, Lcom/example/smali/MainActivity;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/Button;	#btn的findViewById
    
    .local v0, "btn":Landroid/widget/Button;
    new-instance v1, Lcom/example/smali/MainActivity$1; 	#new了一个OnClickListener,它是一个匿名内部类
    invoke-direct {v1, p0}, Lcom/example/smali/MainActivity$1;-><init>(Lcom/example/smali/MainActivity;)V
    invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
    
    return-void
.end method

比对后得出的几个结论就直接写了,不一定正确

1.类和方法中的变量
  • 方法内的变量寄存器有两种
    • 寄存参数使用p寄存器,形如p0,p1,用.param定义,且从p1开始计数,因为p0为非静态方法自动创建的寄存器,存储着this,也就是该方法所属类的实例本身
    • 寄存方法中的内部变量使用v寄存器,形如v0,v1,用.locals表示所需v寄存器数量
  • 至于类中的域则用.field表示
2.方法调用指令的区别与后置寄存器的作用
  • invoke指令最常用的为invoke-virtualinvoke-directinvoke-staticinvoke-super
    • invoke-virtual表示android原生api,即不是你写的方法
    • invoke-direct表示因你而产生的方法,包含你定义的类的构造器
    • invoke-superinvoke-static比上述两者具有更高优先级,当属于静态或父类方法时,优先使用invoke-staticinvoke-static而非 invoke-staticinvoke-static
  • invoke-virtual {v0, p0~pn}...中,v0存有该方法所属的类,p0至pn表示该方法需要的传参,…表示v0所存类与该方法的联系
3.变量操作指令的区别与后置寄存器的作用
  • s开头的指令表示对静态变量的指令符,普通的指令符则用i开头
  • 如果iget-object v0, p0,...的源代码为a = b,则v0存有b,p0存有a所在的类的实例,…为p0到a的联系
4.内部类的特殊格式
  • 如果B为A的内部类,则B在Smali中的表示为一个单独的类文件,并且

    • 在A中B的命名方式为A$B,如果B为匿名内部类,比如OnClickListener,则B的命名方式为A$1
    • 在B中会有一个类型为A的域,A的命名方式为.field final synthetic this$0,并且在B的构造器中需传入一个A的实例,JVM用这种方法保证内部类对外部类的持有
  • 在B中调用A的外部方法,挑用指令统一采用invoke-static,方法名会采用acces$000acces$100…之类的命名形式,并且方法内的参数会默认添加一个外部类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值