Android逆向,理解反汇编得到的smali文件格式 
 
 
AndroidMenifest.xml   AndroidMenifest.xml极其重要,记录着软件的包名、运行的系统版本、用到的组件等基本信息
intent-filter指定Activity启动意图; 
android.intent.action.MAIN表示这个activity为程序的主Activity(没有指定则LAUNCHER无法匹配主Activity,程序没有图标) 
android.intent.category.LAUNCHER表示这个Activity可以通过LAUNCHER启动(如果所有的activity都没添加,程序将在程序列表不可见) 
 
  重点在Application类 ,主要用于在组件间传递全局变量或Activity启动前做初始化工作.由于Applicaion类比程序中其他类都启动的早,一些商业软件将授权验证代码转移到此类中。
smali文件格式 内部类   baksmali反编译dex文件时,会为每个类单独生成一个smali文件。反编译的smali代码中产生了诸如MainActivity$SNChecker.smali的文件,这是内部类文件名的格式”[外部类]$[内部类].smali”。
  比如MainActivity$SNChecker.smali便是MainActivty的一个内部类SNChecker,而MainActivity$1.smali被称作MainActivity的一个示例,在下文将会看到
注解类   Android注解包有两个,抛开不对外开放的dalvik.annotation不谈,另一个是android.annotation.
  在反汇编的smali中很多地方都使用了注解类,这里做一下分类说明.
MemberClasses MemberClasses注解是编译时自动加上的,是一个系统注解,为父类提供一个MemberClasses列表,子类成员集合,或者说是内部类列表。 在MainActivity.smali中的片段:
1 2 3 4 5 6 # annotations .annotation system Ldalvik/annotation/MemberClasses;     value = {         Lcom/droider/crackme0502/MainActivity$SNChecker;     } .end annotation 
 
可以看到的是SNChecker内部类
Enclossing Enclossing注解用来说明作用范围 EnclossingMethord表明作用于一个方法,value表明位置 如MainActivity$1.smali中的一段:
1 2 3 4 # annotations .annotation system Ldalvik/annotation/EnclosingMethod;     value = Lcom/droider/crackme0502/MainActivity;->onCreate(Landroid/os/Bundle;)V .end annotation 
 
作用于MainActivity的onCreate方法
相似的,EnclossingClass表明作用于一个类,value表明作用类。
MainActivity$SNChecker.smali中的一段:
1 2 3 4 5 6 7 8 9 # annotations .annotation system Ldalvik/annotation/EnclosingClass;     value = Lcom/droider/crackme0502/MainActivity; .end annotation .annotation system Ldalvik/annotation/InnerClass;     accessFlags = 0x1     name = "SNChecker" .end annotation 
 
可以看到,作用于MainAcitivity类,后面还有一个InnerClass注解;
InnerClass注解,表示是内部类,accessFlags访问标志,枚举值:
1 2 3 4 5 enum{     kDexVisibilityBuild = 0x00,     kDexVisibilityRuntime = 0x01,     kDexVisibilitySytem = 0x2, } 
 
name是名字
监听器 监听器设置的流程:
新建MainActivity$1实例具体可以在MainActivity$1.smali看到; 
初始化MainActivity$1示例; 
invoke设置按钮点击事件监听器 
 
如下例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 .line 32 iget-object v0, p0, Lcom/droider/crackme0502/MainActivity;->btnAnno:Landroid/widget/Button;  #获取button对象 new-instance v1, Lcom/droider/crackme0502/MainActivity$1;#新建MainActivity$1实例 invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity$1;-><init>(Lcom/droider/crackme0502/MainActivity;)V #初始化MainActivity$1实例 invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V #设置按钮点击事件监听器 .line 40 iget-object v0, p0, Lcom/droider/crackme0502/MainActivity;->btnCheckSN:Landroid/widget/Button; new-instance v1, Lcom/droider/crackme0502/MainActivity$2; invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity$2;-><init>(Lcom/droider/crackme0502/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V 
 
自动生成类 使用Android SDK默认生成的公工程会自动添加一些类.
R类 R类包含大量的资源类,一段R.smali示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 .class public final Lcom/droider/crackme0502/R; .super Ljava/lang/Object; .source "R.java" # annotations .annotation system Ldalvik/annotation/MemberClasses;     value = {         Lcom/droider/crackme0502/R$attr;,         Lcom/droider/crackme0502/R$dimen;,         Lcom/droider/crackme0502/R$drawable;,         Lcom/droider/crackme0502/R$id;,         Lcom/droider/crackme0502/R$layout;,         Lcom/droider/crackme0502/R$menu;,         Lcom/droider/crackme0502/R$string;,         Lcom/droider/crackme0502/R$style;     } .end annotation # direct methods .method public constructor <init>()V     .locals 0     .prologue     .line 10     invoke-direct {p0}, Ljava/lang/Object;-><init>()V     return-void .end method 
 
可以看到注解里列出了大量的子类,这些子类每个都有单独的smali文件可以查看。
BuildConfig类 只包含一个boolean类型的DEBUG字段标识程序发布的版本类型,默认为true。
注解类 没啥说的,影响不大。
java代码在smali文件中的表现 几个重要的语句结构:
循环语句 
switch语句 
try catch语句 
 
循环语句 循环主要有三种:
迭代器循环,hasNext()判断 
传统for循环 
while循环与for循环基本相同,只是判定位置不同 
 
switch语句 switch语句的结构非常清楚: xyyy-switch分支,xswitch_data_0指定case区域
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 packed-switch p1, :pswitch_data_0 .line 36 const-string v0, "she is a person" .line 39 :goto_0 return-object v0 .line 24 :pswitch_0 const-string v0, "she is a baby" .line 25 goto :goto_0 .line 27 :pswitch_1 const-string v0, "she is a girl" .line 28 goto :goto_0 .line 30 :pswitch_2 const-string v0, "she is a woman" .line 31 goto :goto_0 .line 33 :pswitch_3 const-string v0, "she is an obasan" .line 34 goto :goto_0 .line 22 nop :pswitch_data_0 .packed-switch 0x0  #case区域 从0开始递增     :pswitch_0   #case 0     :pswitch_1   #case 1     :pswitch_2   #case 2     :pswitch_3   #case 3 .end packed-switch 
 
pswitch_0pswitch_3对应case 0case 3,default分支放在第一个。
对于有规律递增的switch,结构体如下:
1 2 3 4 5 6 struct packed-switch-palyload{     ushort ident;/*值固定0x100*/     ushort size; /*case数目*/     int first_key;/*初始case的值*/     int[] targets;/*每个case相对switch指令处的偏移*/ } 
 
无规律switch,结构体如下:
1 2 3 4 5 6 struct sparse-switch-payload{     ushort ident;/*值固定为0x200*/     ushort size;/*case数目*/     int[] keys;/*每个case的值,顺序从低到高*/     int[] targets;/*每个case相对switch的偏移*/ } 
 
try/catch语句 有非常明显的标号:try_start_0以及try_end_0 和.catch。