作者: mutepig
预估稿费:300RMB(不服你也来投稿啊!)
投稿方式:发送邮件至 linwei#360.cn ,或登陆 网页版 在线投稿
0x01 smali生成
使用apktool反编译apk后,会在反编译工程目录下生成一个smali文件夹
其中android下存放所调用库的smali文件,com才是我们自己写的代码的smali文件。
0x02 基础语法
a.文件基本格式
基本信息
.class <访问权限> <类名> .super <父类名> .source <源文件名> # eg. .class public Lcom/reoky/crackme/challengeone/activities/ChallengeActivity; .super Landroid/support/v4/app/FragmentActivity; .source "ChallengeActivity.java" //经过混淆后这项可能为空
类变量声明
.field <访问权限> <变量名>:<变量类型> # eg. .field actionBar:Landroid/app/ActionBar; <=对应源码=> ActionBar actionBar; 局部变量声明: .local <初始值>,<变量名>:<变量类型> #eg .local v0, "ans":Ljava/lang/String; <=对应源码=> String ans="";
类方法声明
.method <访问权限> <方法名>(参数原型) <方法原型> [.prologue] // 指定代码开始位置 [.param] // 指定方法参数 [.line] // 指定代码在源代码中的行数,混淆后可能不存在 [.locals] // 使用的局部变量个数 <代码体> .end method # eg .method public onTabReselected(Landroid/app/ActionBar$Tab;Landroid/app/FragmentTransaction;)V .locals 0 .param p1, "tab" # Landroid/app/ActionBar$Tab; .param p2, "fragmentTransaction" # Landroid/app/FragmentTransaction; .prologue .line 55 //可能经过混淆后不存在 return-void .end method <=对应源码=> public void onTabReselected(ActionBar$Tab tab, FragmentTransaction fragmentTransaction){ }
b.原始类型
B—byte C—char D—double F—float I—int J—long S—short V—void Z—boolean [XXX—array Lpackage/name/ObjName—object // 前面表示对象所在包路径
c.寄存器操作
传入的参数寄存器由p表示,而函数内的本地寄存器则由v表示,多个的话则在后面加上0,1,2...
需要注意的是,在非static函数中,p0表示`this`,p1才表示第一个参数。
常量赋值
主要是各种const const v0, 0x7F030018 # R.layout.activity_challenge #从R中取出静态值 const/4 v3, 0x2 #4也可以换成16或者high16,表示取整数值 const-string v2, "Challenge" # 取字符串 const-class v2, Context #把类对象取出
变量间赋值
move vx,vy # 将vy的值赋值给vx,也可以是move-object等 move-result vx # 将上个方法调用后的结果赋值给vx,也可以是move-result-object return-object vx # 将vx的对象作为函数返回值 new-instance v0, ChallengePagerAdapter # 实例化一个对象存入v0中
对象赋值
iput-object a,(this),b 将a的值给b,一般用于b的初始化 iget-object a,(this),b 将b的值给a,一般用于获取b的地址,接着调用它 # eg. iput-object v0, p0, ChallengeActivity->actionBar:ActionBar iget-object v0, p0, ChallengeActivity->actionBar:ActionBar
d.函数操作
最基础的函数操作一般有以下四个:
1.private:invoke-direct 2.public|protected: invoke-virtual 3.static:invoke-static 4.parent: invoke-super 基本调用形式:invoke-xxx {参数},类;->函数(参数原型) # eg. invoke-super {p0, p1}, Landroid/support/v4/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V <=对应源码=> super.onCreate(savedInstanceState); // 其中p0是this,其父类是FragmentActivity,p1,是savedInstanceState,其原型是Bundle;即调用p0->onCreate(p1)
0x03 程序语句相关语法
这里列举以下常见程序语句对应的smali语句,并与Android源码相比较分析
a.判断语句
if-eq vA, vB, :cond_X 如果vA等于vB则跳转到:cond_X if-ne vA, vB, :cond_X 如果vA不等于vB则跳转到:cond_X if-lt vA, vB, :cond_X 如果vA小于vB则跳转到:cond_X if-ge vA, vB, :cond_X 如果vA大于等于vB则跳转到:cond_X if-gt vA, vB, :cond_X 如果vA大于vB则跳转到:cond_X if-le vA, vB, :cond_X 如果vA小于等于vB则跳转到:cond_X if-eqz vA, :cond_X 如果vA等于0则跳转到:cond_X if-nez vA, :cond_X 如果vA不等于0则跳转到:cond_X if-ltz vA, :cond_X 如果vA小于0则跳转到:cond_X if-gez vA, :cond_X 如果vA大于等于0则跳转到:cond_X if-gtz vA, :cond_X 如果vA大于0则跳转到:cond_X if-lez vA, :cond_X 如果vA小于等于0则跳转到:cond_X
下面列出一个简单的for循环,其他也差不多
public void encrypt(String str) { String ans = ""; for (int i = 0 ; i < str.length();i++){ ans += str.charAt(i); } Log.e("ans:",ans); } <=对应smali=> # public void encrypt(String str) { .method public encrypt(Ljava/lang/String;)V .locals 4 .param p1, "str"# Ljava/lang/String; .prologue # String ans = ""; const-string v0, "" .local v0, "ans":Ljava/lang/String; # for (int i 0 ; i < str.length();i++){ # int i=0 =>v1 const/4 v1, 0x0 .local v1, "i":I :goto_0# for_start_place # str.length()=>v2 invoke-virtual {p1}, Ljava/lang/String;->length()I move-result v2 # i<str.length() if-ge v1, v2, :cond_0 # ans += str.charAt(i); # str.charAt(i) => v2 new-instance v2, Ljava/lang/StringBuilder; invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v2 #str.charAt(i) => v3 invoke-virtual {p1, v1}, Ljava/lang/String;->charAt(I)C move-result v3 # ans += v3 =>v0 invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v0 # i++ add-int/lit8 v1, v1, 0x1 goto :goto_0 # Log.e("ans:",ans); :cond_0 const-string v2, "ans:" invoke-static {v2, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I return-void .end method
c.switch语句
public void encrypt(int flag) { String ans = null; switch (flag){ case 0: ans = "ans is 0"; break; default: ans = "noans"; break; } Log.v("ans:",ans); } <=对应smali=> #public void encrypt(int flag) { .method public encrypt(I)V .locals 2 .param p1, "flag" # I .prologue #String ans = null; const/4 v0, 0x0 .local v0, "ans":Ljava/lang/String; #switch (flag){ packed-switch p1, :pswitch_data_0 # pswitch_data_0指定case区域的开头及结尾 #default: ans="noans" const-string v0, "noans" #Log.v("ans:",ans) :goto_0 const-string v1, "ans:" invoke-static {v1, v0}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I return-void #case 0: ans="ans is 0" :pswitch_0 #pswitch_<case的值> const-string v0, "ans is 0" goto :goto_0 # break nop :pswitch_data_0 #case区域的结束 .packed-switch 0x0 #定义case的情况 :pswitch_0 #case 0 .end packed-switch .end method
其中case定义情况有两种:
1.从0开始递增 packed-switch p1, :pswitch_data_0 ... :pswitch_data_0 .packed-switch 0x0 :pswitch_0 :pswitch_1 2.无规则switch sparse-switch p1,:sswitch_data_0 ... sswitch_data_0 .sparse-switch 0xa -> : sswitch_0 0xb -> : sswitch_1 # 字符会转化成数组
d.try-catch语句
public void encrypt(int flag) { String ans = null; try { ans = "ok!"; } catch (Exception e){ ans = e.toString(); } Log.d("error",ans); } <=对应smali=> #public void encrypt(int flag) { .method public encrypt(I)V .locals 3 .param p1, "flag" # I .prologue #String ans = null; const/4 v0, 0x0 .line 20 .local v0, "ans":Ljava/lang/String; #try { ans="ok!"; } :try_start_0 # 第一个try开始, const-string v0, "ok!" :try_end_0 # 第一个try结束(主要是可能有多个try) .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0 #Log.d("error",ans); :goto_0 const-string v2, "error" invoke-static {v2, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I return-void #catch (Exception e){ans = e.toString();} :catch_0 #第一个catch move-exception v1 .local v1, "e":Ljava/lang/Exception; invoke-virtual {v1}, Ljava/lang/Exception;->toString()Ljava/lang/String; move-result-object v0 goto :goto_0 .end method
0x04 参考资料
http://blog.csdn.net/qq_24349189/article/details/52300419
http://lib.csdn.net/article/android/7043
http://devxeo.lofter.com/post/2da37d_cd7c69
http://www.blogjava.net/midea0978/archive/2012/01/04/367847.html
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/3241.html