smali代码插入和调试

来源:互联网 发布:如何查询淘宝信用 编辑:程序博客网 时间:2024/05/21 17:47

转自:http://blog.sina.com.cn/s/blog_5674d18801019i89.html   MIUI V4移植经验分享(三)----Smali代码注入

       总结了一些Smali代码移植时可能遇到的编译错误:   

 1.函数调用(invoke-virtual等指令)的参数只能使用v0~v15,使用超过v15的变量会报错。修复这个问题有两种方法:

    A.使用invoke-virtual/range {p1 .. p1}指令,但是这里要求变量名称需要连续。

    B.增加move-object/from16 v0, v18类似指令,调整变量名,使之小于等于v15。

  2.函数调用中p0相当于函数可用变量值+1,pN相当于函数可用变量值+N。例如函数.local值为16,表明函数可用变量值为v0~v15,则p0相当于v16,p1相当于v17。

例如,下图左侧蓝框所在代码编译不过,后来检查了代码所在的函数.local为33,p0相当于v33,所以编译不过,修改为右侧绿框才正常。

3.跳转标号重叠。

  这里主要是指出现了两个相同的标号的情况,例如cond_11等,导致无法编译过。解决方法就是修改冲突的标号以及相关跳转语句。其实这个标号叫什么都无所谓,你甚至可以叫ABCD_XXX,只要可以与对应的goto语句呼应即可。

  4.使用没有定义的变量

  每个函数可以使多少变量都在函数体内的第一句.local中声明,例如.local 30表明这个函数可以使用v0~v29,如果使用v30就会编译错误。

        调试smali代码:

 调试Smali代码主要任务是解决注入代码后导致的运行时错误。具体的说,就是使注入后的Smali代码通过dalvik虚拟机的字节码校验。获取错误的方法相对简单,使用下面两条命令即可:

  adb logcat | grep dalvikvm

  adb logcat | grep VFY

  其中VFY的信息会给出Smali代码出错的文件、函数以及错误原因,dalvikvm的信息可以给出调用栈,以及上下文执行过程,都比较贴心。

 

  这里总结一下主要的运行时错误:

  1.函数变量列表与声明不同,这个主要体现在下面两个方面:

    A.函数调用的变量类型与函数声明不同。

      通过追踪变量在上下文的赋值动作来解决。

    B.函数变量列表中变量少于或者多于函数声明的变量。

      通过核对函数声明来解决。

  2.函数调用方式不正确。

  例如:public和包访问函数使用invoke-virtual调用,private函数使用invoke-director调用,接口函数使用invoke-interface调用。如果使用错误,会导致运行时错误。需要调整相关的Smali代码。

  3.类接口没有实现。

  主要是由于增加了新的子类没有实现原有父类接口导致的,只需增加空实现即可修复。

  4.签名不正确。

  可以通过adb logcat | grep mismatch命令确认哪个package签名不正确。只需对签名不正确的包重新签名即可。当然如果有很多签名不一致的错误,建议大家对所有的APK重新签名。

  5.资源找不到。

  这个问题的原因有很多种,我这里列举一些常见的原因:

  A.系统资源文件签名不正确,导致没有加载系统资源,进而无法找到相应的资源。其中,系统资源文件是指system/framework/目录下的apk文件。

  B.Smali代码中的资源ID移植错误,无法在系统资源中找到对应的资源。

  C.资源相关的类移植存在问题,导致无法加载相关资源。

 

  另外,调试时,大家可能需要要追踪代码执行路径,但又苦于无法Debug。我这里分享一些简单的追踪方法,希望对大家有用。

  1.增加简单的Smali日志信息:

    A.修改函数的.local变量,在原来基础上增加两个变量,例如v11,v12。

    B.在需要打印日志的地方增加如下Smali代码

    const-string v11, "@@@@"

    const-string v12, "interceptPowerKeyDown enter"

    invoke-static {v11, v12}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

    如果增加的变量为v28和v29,则需要使用下面的语句。

    invoke-static/range {v28 .. v29}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

  2.打印程序调用栈的方法:

    A.修改函数的.local变量,在原来基础上增加一个变量,例如v11。

    B.在需要打印调用栈的地方增加如下Smali代码

    new-instance v1 Ljava/lang/Exception;

    invoke-direct {v1, Ljava/lang/Exception;-><init>()V

    invoke-virtual {v1, Ljava/lang/Exception;->printStackTrace()V


原创粉丝点击