android studio逆向分析apk

android studio逆向分析apk

2018年01月12日 10:14:44 louis_老罗 阅读数:356更多

个人分类: 安全相关android开发技术相关

新版的android studio在工具栏Build>Analyze APK选择apk(或者直接将apk拖至android studio编辑区)可进入apk解析器界面。

点击classes.dex进行具体class文件的反编译:

比如我们要分析PlainWhiteboardActivity,选择后右键-->ShowByteCode可以查看到smali格式的代码:

OK,到这一步,逆向分析的重点来了,smali文件解析:

 

一、头信息——类的主体信息

在打开smali文件的时候,它的头三行描述了当前类的一些信息。

 
  1. .class <访问权限> [关键修饰字] <类名>;

  2. .super <父类名>;

  3. .source <源文件名>

 

例如:

 
  1. //===================================================================

  2. public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  3. // ......

  4. }

  5. //===================================================================

  6. # interfaces

  7. .implements Landroid/view/View$OnClickListener;

  8. //===================================================================

三、smali基本语法 

Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类型(Long/Double)用2个寄存器表示; 
Dalvik字节码有两种类型:原始类型;引用类型(包括对象和数组)

1、原始类型

 
  1. V void (只能用于返回值类型)

  2. Z boolean

  3. B byte

  4. S short

  5. C char

  6. I int

  7. J long(64位)

  8. F float

  9. D double(64位)

2、对象类型 
Lpackage/name/ObjectName; 相当于java中的package.name.ObjectName; 
L 表示这是一个对象类型 
package/name 该对象所在的包 
ObjectName 对象名称 
; 标识对象名称的结束

3、数组类型 
[I :表示一个整形的一维数组,相当于java的int[]; 
对于多维数组,只要增加[ 就行了,[[I = int[][];注:每一维最多255个;

对象数组的表示形式: 
[Ljava/lang/String 表示一个String的对象数组;

4、寄存器与变量 
android变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型,其中long和double是64为的,需要使用两个寄存器保存。 
寄存器采用v和p来命名,v表示本地寄存器,p表示参数寄存器。

例如:

 
  1. //===================================================================

  2. private void print(String string) {

  3. Log.d(TAG, string);

  4. }

  5. //===================================================================

  6. .method private print(Ljava/lang/String;)V

  7. .registers 3

  8. .param p1, "string" # Ljava/lang/String;

  9.  
  10. .prologue

  11. .line 29

  12. const-string v0, "MainActivity"

  13.  
  14. invoke-static {v0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

  15.  
  16. .line 30

  17. return-void

  18. .end method

  19. //===================================================================

.registers 3 说明该方法有三个寄存器,其中一个本地寄存器v0,两个参数寄存器p0,p1,细心的人可能会注意到没有看到p0,原因是p0存放的是this。如果是静态方法的话就只有2个寄存器了,不需要存this了。

5、基本指令 
smali字节码是类似于汇编的,如果你有汇编基础,理解起来是非常容易的。 
move v0, v3 把v3寄存器的值移动到寄存器v0上 
const-string v0, “MainActivity” 把字符串”MainActivity”赋值给v0寄存器 
invoke-super  调用父函数 
return-void  函数返回void 
new-instance  创建实例 
iput-object  对象赋值 
iget-object  调用对象 
invoke-static  调用静态函数 
invoke-direct  调用函数

例如:

 
  1. //===================================================================

  2. @Override

  3. public void onClick(View view) {

  4. String str = "Hello World!";

  5. print(str);

  6. }

  7. //===================================================================

  8. # virtual methods

  9. # 参数类型为Landroid/view/View,返回类型为V

  10. .method public onClick(Landroid/view/View;)V

  11. # 表示有三个寄存器

  12. .registers 3

  13. # 参数View类型的view变量对应的是寄存器p1

  14. .param p1, "view" # Landroid/view/View;

  15.  
  16. .prologue

  17. .line 24

  18. #将"Hello World!"字符串放到寄存器v0中

  19. const-string v0, "Hello World!"

  20.  
  21. .line 25

  22. # 定义一个Ljava/lang/String类型的str变量对应本地寄存器v0

  23. .local v0, "str":Ljava/lang/String;

  24. # 调用该类的print方法,该方法的参数类型为Ljava/lang/String,返回值为V

  25. # 调用print方法传入的参数为{p0, v0},及print(p0, v0),p0为this,v0为"Hello World!"字符串

  26. invoke-direct {p0, v0}, Ltestdemo/hpp/cn/annotationtest/MainActivity;->print(Ljava/lang/String;)V

  27.  
  28. .line 26

  29. return-void

  30. .end method

  31. //===================================================================

6、if判断语句

if判断一共有12条指令:

 
  1. if-eq vA, VB, cond_** 如果vA等于vB则跳转到cond_**。相当于if (vA==vB)

  2. if-ne vA, VB, cond_** 如果vA不等于vB则跳转到cond_**。相当于if (vA!=vB)

  3. if-lt vA, VB, cond_** 如果vA小于vB则跳转到cond_**。相当于if (vA<vB)

  4. if-le vA, VB, cond_** 如果vA小于等于vB则跳转到cond_**。相当于if (vA<=vB)

  5. if-gt vA, VB, cond_** 如果vA大于vB则跳转到cond_**。相当于if (vA>vB)

  6. if-ge vA, VB, cond_** 如果vA大于等于vB则跳转到cond_**。相当于if (vA>=vB)

  7.  
  8. if-eqz vA, :cond_** 如果vA等于0则跳转到:cond_** 相当于if (VA==0)

  9. if-nez vA, :cond_** 如果vA不等于0则跳转到:cond_**相当于if (VA!=0)

  10. if-ltz vA, :cond_** 如果vA小于0则跳转到:cond_**相当于if (VA<0)

  11. if-lez vA, :cond_** 如果vA小于等于0则跳转到:cond_**相当于if (VA<=0)

  12. if-gtz vA, :cond_** 如果vA大于0则跳转到:cond_**相当于if (VA>0)

  13. if-gez vA, :cond_** 如果vA大于等于0则跳转到:cond_**相当于if (VA>=0)

7、循环语句 
常用的循环结构有:迭代器循环,for循环,do while循环。

8、switch分支语句

9、try/catch语句

四、字段

smali文件中,字段的声明使用.field指令,字段分为静态字段和实例字段。

1、静态字段

 
  1. #static fields

  2. .field <访问权限> static [修饰关键字] <字段名>:<字段类型>

可以看到,baksmali在生成smali文件时,会在静态字段声明的起始处添加注释”static fields”,注释是以#开头。

访问权限包括:private、protected、public(三者之一) 
修饰关键字为字段的其他属性,例如,final 
字段名和类型就不用解释了

例如:

 
  1. //===================================================================

  2. private static final String TAG = "MainActivity";

  3. //===================================================================

  4. # static fields

  5. .field private static final TAG:Ljava/lang/String; = "MainActivity"

  6. //===================================================================

2、实例字段 
相比于静态自动就少了一个static的静态声明而已,其他都一样。

 
  1. #instance fields

  2. .field <访问权限> [修饰关键字] <字段名>:<字段类型>

  • 1
  • 2

例如:

 
  1. //===================================================================

  2. private Button mButton;

  3. //===================================================================

  4. # instance fields

  5. .field private mButton:Landroid/widget/Button;

  6. //===================================================================

五、方法 
smali的方法声明使用的.method指令,方法分为直接方法和虚方法两种。

1、直接方法 
直接方法指的是该类中定义的方法。

 
  1. #direct methods

  2. .method <访问权限> [修饰关键字] <方法原型>

  3. <.registers>

  4. [.param]

  5. [.prologue]

  6. [.line]

  7. <.local>

  8. <代码体>

  9. .end method

  •  
  1. #direct methods是注释,是baksmali添加的,访问权限和修饰关键字跟字段是一样的。

  2. 方法原型描述了方法的名称、参数与返回值。

  3. .registers 指令指定了方法中寄存器的总数,这个数量是参数和本地变量总和。

  4. .param表明了方法的参数,每个.param指令表示一个参数,方法使用了几个参数就有几个.parameter指令。

  5. .prologue指定了代码的开始处,混淆过的代码可能去掉了该指令。

  6. .line指明了该处代码在源代码中的行号,同样,混淆后的代码可能去掉了行号。

  7. .local 使用这个指定表明方法中非参寄存器

 
  1. //===================================================================

  2. private void print(String string) {

  3. Log.d(TAG, string);

  4. }

  5. //===================================================================

  6. .method private print(Ljava/lang/String;)V

  7. .registers 3

  8. .param p1, "string" # Ljava/lang/String;

  9.  
  10. .prologue

  11. .line 29

  12. const-string v0, "MainActivity"

  13.  
  14. invoke-static {v0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

  15.  
  16. .line 30

  17. return-void

  18. .end method

  19. //===================================================================

2、虚方法 
虚方法指的是从父类中继承的方法或者实现的接口的方法,它的声明跟直接方法相同,只是起始的初始为virtual methods

 
  1. //===================================================================

  2. @Override

  3. public void onClick(View view) {

  4. String str = "Hello World!";

  5. print(str);

  6. }

  7. //===================================================================

  8. # virtual methods

  9. .method public onClick(Landroid/view/View;)V

  10. .registers 3

  11. .param p1, "view" # Landroid/view/View;

  12.  
  13. .prologue

  14. .line 24

  15. const-string v0, "Hello World!"

  16.  
  17. .line 25

  18. .local v0, "str":Ljava/lang/String;

  19. invoke-direct {p0, v0}, Ltestdemo/hpp/cn/annotationtest/MainActivity;->print(Ljava/lang/String;)V

  20.  
  21. .line 26

  22. return-void

  23. .end method

  24. //===================================================================

3、静态方法

 
  1. //===================================================================

  2. public static void setTag(String str) {

  3. TAG = str;

  4. }

  5. //===================================================================

  6. .method public static setTag(Ljava/lang/String;)V

  7. .registers 1

  8. .param p0, "str" # Ljava/lang/String;

  9.  
  10. .prologue

  11. .line 64

  12. sput-object p0, Ltestdemo/hpp/cn/annotationtest/MainActivity;->TAG:Ljava/lang/String;

  13.  
  14. .line 65

  15. return-void

  16. .end method

  17. //===================================================================

  18.  

六、注解

如果一个类使用了注解,那么smali中会使用.annotation指令。

 
  1. #annotations

  2. .annotation [注解属性] <注解类名>

  3. [注解字段 = 值]

  4. .end annotation

注解的作用范围可以是类、方法或者字段。如果注解的作用范围是类,.annotation指令会直接定义在smali文件中,如果是方法或者字段,.annotation指令则会包含在方法或者字段的定义中。

1、注解类

 
  1. //===================================================================

  2. @BindInt(100)

  3. public class MainActivity extends AppCompatActivity {

  4.  
  5. }

  6. //===================================================================

  7. # annotations

  8. .annotation build Ltestdemo/hpp/cn/annotationtest/BindInt;

  9. value = 0x64

  10. .end annotation

  11. //===================================================================

2、注解字段

 
  1. //===================================================================

  2. @BindView(R.id.button)

  3. public Button mButton;

  4. //===================================================================

  5. # instance fields

  6. .field public mButton:Landroid/widget/Button;

  7. .annotation build Lbutterknife/BindView;

  8. value = 0x7f0c0050

  9. .end annotation

  10. .end field

  11. //===================================================================

  12.  

3、注解方法

 
  1. //===================================================================

  2. @OnClick(R.id.button)

  3. public void click() {

  4. String str = "Hello World!";

  5. print(str);

  6. }

  7. //===================================================================

  8. # virtual methods

  9. .method public click()V

  10. .registers 2

  11. .annotation build Lbutterknife/OnClick;

  12. value = {

  13. 0x7f0c0050

  14. }

  15. .end annotation

  16.  
  17. .prologue

  18. .line 29

  19. const-string v0, "Hello World!"

  20.  
  21. .line 30

  22. .local v0, "str":Ljava/lang/String;

  23. invoke-direct {p0, v0}, Ltestdemo/hpp/cn/annotationtest/MainActivity;->print(Ljava/lang/String;)V

  24.  
  25. .line 31

  26. return-void

  27. .end method

  28. //===================================================================

学会怎么看懂smali文件后,是不是迫不及待的想找个apk反编译看看呢~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值