smail语法记录

# static fields             定义静态变量的标记
# instance fields        定义实例变量的标记
# direct methods       定义静态方法的标记
# virtual methods      定义非静态方法的标记
构造函数的返回类型为V,名字为<init>。
 
if-eq p1, v0, :cond_8 表示如果p1和v0相等,则执行cond_8的流程:
    :cond_8
    invoke-direct {p0}, Lcom/paul/test/a;->d()V
调用com.paul.test.a的d()方法
if-ne p1, v0, :cond_b 表示不相等则执行cond_b的流程:
    :cond_b
    const/4 v0, 0x0
    invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
    invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
    move-result v0
 

大概意思就是调用com.paul.test.a的setPressed方法,然后再调用父类View的onKeyUp方法,最后 return v0


对象的表式:

对象以Lpackage/name/ObjectName;的形式表示。

前面的L表示这是一个对象类型,package/name/是该对象所在的包,ObjectName是对象的名字,“;”表示对象名称的结束。相当于java中的package.name.ObjectName。例如:Ljava/lang/String;相当于java.lang.String


数组的表示形式
[I——表示一个整型一维数组,相当于java中的int[]。

对于多维数组,只要增加[就行了。[[I相当于int[][],[[[I相当于int[][][]。注意每一维的最多255个。
对象数组的表示:[Ljava/lang/String;表示一个String对象数组。



方法的表现形式
表示形式:Lpackage/name/ObjectName;->MethodName(III)Z
 Lpackage/name/ObjectName;表示类型,MethodName是方法名。III为参数(在此是3个整型参数),Z是返回类型(bool型)。
方法的参数是一个接一个的,中间没有隔开。
一个更复杂的例子:
method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;


字段表示形式:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
即包名,字段名和各字段类型。



举两个例子:

sget-object v5, Lcom/google/youngandroid/runtime;->Lit227:Lgnu/mapping/SimpleSymbol;
获取com.google.youngandroid.runtime中的Lit227字段存入v5寄存器,相当于
gnu.mapping.SimpleSymbol localVariable = com.google.youngandroid.runtime.Lit227;

sput-object v0, Lcom/google/youngandroid/runtime;->Lit78:Lkawa/lang/SyntaxTemplate;
Likewise, this is setting the value of a static field. i.e.
设置com.google.youngandroid.runtime.Lit78的值为v0寄存器中的kawa.lang.SyntaxTemplate类型变量的值。相当于com.google.youngandroid.runtime.Lit78 = kawa.lang.SyntaxTemplate localVariable;
剩下的比较简单你应该能明白了




调试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 | grepmismatch命令确认哪个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

 

今天先分享到这里,希望我的这些经验对大家有所帮助。


你可能感兴趣的:(smail语法记录)