安卓逆向这档事-第三节.初识smali,vip终结者

一、基础知识介绍

1.什么是JVM、Dalvik、ART

JVM是JAVA虚拟机,运行JAVA字节码程序
Dalvik是Google专门为Android设计的一个虚拟机,Dalvik有专属的文件执行格式dex(Dalvik executable)
Art(Android Runtime)相当于Dalvik的升级版,本质与Dalvik无异

2.smali及其语法

smali是Dalvik的寄存器语言,smali代码是dex反编译而来的。

关键字

名称 注释
.class 类名
.super 父类名,继承的上级类名名称
.source 源名
.field 变量
.method 方法名
.register 寄存器
.end method 方法名的结束
public 公有
protected 半公开,只有同一家人才能用
private 私有,只能自己使用
.parameter 方法参数
.prologue 方法开始
.line xxx 位于第xxx行

数据类型对应

smali类型 java类型 注释
V void 无返回值
Z boolean 布尔值类型,返回0或1
B byte 字节类型,返回字节
S short 短整数类型,返回数字
C char 字符类型,返回字符
I int 整数类型,返回数字
J long (64位 需要2个寄存器存储) 长整数类型,返回数字
F float 单浮点类型,返回数字
D double (64位 需要2个寄存器存储) 双浮点类型,返回数字
string String 文本类型,返回字符串
Lxxx/xxx/xxx object 对象类型,返回对象

常用指令

关键字 注释
const 重写整数属性,真假属性内容,只能是数字类型
const-string 重写字符串内容
const-wide 重写长整数类型,多用于修改到期时间。
return 返回指令
if-eq 全称equal(a=b),比较寄存器ab内容,相同则跳
if-ne 全称not equal(a!=b),ab内容不相同则跳
if-eqz 全称equal zero(a=0),z即是0的标记,a等于0则跳
if-nez 全称not equal zero(a!=0),a不等于0则跳
if-ge 全称greater equal(a>=b),a大于或等于则跳
if-le 全称little equal(a<=b),a小于或等于则跳
goto 强制跳到指定位置
switch 分支跳转,一般会有多个分支线,并根据指令跳转到适当位置
iget 获取寄存器数据

其余指令可用语法工具查询

二、快速定位、修改判断、强制跳转、修改寄存器的值

定位方法功能:搜索弹窗关键字、抓取按钮id
修改方法:修改判断、强制跳转、修改寄存器的值
Alt text

1、快速定位

查看关键值
Alt text

1.1、搜索弹窗关键字

1.1.1、使用jadx-gui逆向分析搜索快速定位

Alt text
Alt text

1.1.2、使用MT管理器逆向分析搜索快速定位

Alt text
Alt text
Alt text
Alt text
Alt text

1.2、抓取按钮id

使用开发者助手工具,进入到此关卡界面,进行界面资源分析

Alt text

复制

Alt text
Alt text
Alt text

往上翻一翻

Alt text

2、修改判断、强制跳转、修改寄存器的值

使用jadx-gui逆向Java代码中的分析
Alt text
但是MT管理器或者其他一些可反编译dex的工具都转换成了smali代码
Alt text
一下是对jadx-gui工具反编译dex之后的注注释

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//一个私有、静态、不可变的方法   方法名
.method private static final onCreate$lambda-2(Lkotlin/jvm/internal/Ref$IntRef;Lcom/zj/wuaipojie/ui/ChallengeSecond;Landroid/widget/ImageView;Landroid/widget/ImageView;Landroid/widget/ImageView;Landroid/view/View;)Z
.registers 7 // 寄存器的数量

.line 33 // 代码所在行数
iget v1, v1, Lkotlin/jvm/internal/Ref$IntRef;->element:I # field@97ee // 读取v1(第一个参数)中element的值赋值给v1(第二个参数)

const/4 v6, 0x1 // v6赋值1

const/16 v0, 0xa // v0赋值10,在16进制里a表示10

if-ge v1, v0, :cond_0015 // 判断v1的值是否大于或等于 v0的值(即v1的值是否大于等于10),如果大于或等于则跳转到:cond_0015

.line 34 // 以下是常见的Toast弹窗代码

move-object v1, v2 // 自动对象引用v1到v2

check-cast v1, Landroid/content/Context; # type@0063 // 检查Contex对象引用

const-string v0, "请先获取10个硬币哦" # string@ed09 // 弹窗文本信息,把""里的字符串数据赋值给v0

check-cast v0, Ljava/lang/CharSequence; # type@14e5 // 检查CharSequence对象引用

invoke-static {v1, v0, v6}, Landroid/widget/Toast;->makeText(Landroid/content/Context;, Ljava/lang/CharSequence;, I)Landroid/widget/Toast; # method@11ae
// 将弹窗文本、显示时间等信息传给v1

move-result-object v1 // 结果传递给v1

invoke-virtual {v1}, Landroid/widget/Toast;->show()V # method@11af // 当看到这个Toast;->show()你就应该反应过来这里是弹窗代码

.line 36

invoke-virtual {v2}, Lcom/zj/wuaipojie/ui/ChallengeSecond;->isvip()Z # method@9cc3 //判断isvip方法的返回值是否为真(即结果是否为1)

move-result v1 //结果赋值给v1

if-eqz v1, :cond_0043 //如果结果为0则跳转cond_0043地址

.line 37

check-cast v2, Landroid/content/Context; # type@0063

const-string v1, "当前已经是大会员了哦!" # string@ed00

check-cast v1, Ljava/lang/CharSequence; # type@14e5

invoke-static {v2, v1, v6}, Landroid/widget/Toast;->makeText(Landroid/content/Context;, Ljava/lang/CharSequence;, I)Landroid/widget/Toast; # method@11ae

move-result-object v1

invoke-virtual {v1}, Landroid/widget/Toast;->show()V # method@11af

const v1, 0x7f0d0018 //在arsc中的id索引,这个值可以进行查询

.line 38

invoke-virtual {v3, v1}, Landroid/widget/ImageView;->setImageResource(I)V # method@0fe1 //设置图片资源

const v1, 0x7f0d0008

.line 39

invoke-virtual {v3, v1}, Landroid/widget/ImageView;->setImageResource(I)V # method@0fe1

const v1, 0x7f0d0008

.line 40

invoke-virtual {v5, v1}, Landroid/widget/ImageView;->setImageResource(I)V # method@0fe1

.line 41

sget-object v1, Lcom/zj/wuaipojie/util/SPUtils;->INSTANCE:Lcom/zj/wuaipojie/util/SPUtils; # field@957d

const/4 v3, 0x2 //v3赋值2

const-string v4, "level" # string@b13d //sp的索引

invoke-virtual {v1, v2, v4, v3}, Lcom/zj/wuaipojie/util/SPUtils;->saveInt(Landroid/content/Context;, Ljava/lang/String;, I)V # method@9d49 //写入数据

goto :goto_0050 //跳转地址

.line 44

check-cast v2, Landroid/content/Context; # type@0063

const-string v1, "请先充值大会员哦!" # string@ed07

check-cast v1, Ljava/lang/CharSequence; # type@14e5

invoke-static {v2, v1, v6}, Landroid/widget/Toast;->makeText(Landroid/content/Context;, Ljava/lang/CharSequence;, I)Landroid/widget/Toast; # method@11ae

move-result-object v1

invoke-virtual {v1}, Landroid/widget/Toast;->show()V # method@11af

return v6 //返回V6的值

.end method //方法结束

//判断是否是大会员的方法
.method public final isvip()Z

.registers 2

const/4 v0, 0 //v0赋值0,0就是false

return v0 //返回v0的值

.end method

2.1、修改判断

这里的

1
2
const/16 v0, 0xa 
if-ge p0, v0, :cond_15

意思是v0的值为10
p0大于等于v0(10)则跳转(p0是硬币数量)
改成 if-le
p0小于于等于v0(10)则跳转(p0是硬币数量)
Alt text
Alt text
注释掉判断是否为大会员(默认为false),不让它判断跳转,直接执行后面是大会员的代码
Alt text
最终效果
Alt text

2.2、强制跳转

goto 强制跳转到制定位置
在判断硬币数量之前插入强制跳转,跳转到判断是否是大会员之后,直接执行成为大会员之后的代码
Alt text
Alt text
最终效果
Alt text

2.3、修改寄存器的值

这里是判断硬币的数量,和被比较的值,v0值为10,修改成0,0x0
Alt text
Alt text
判断是否是大会员的方法,默认为0就是false,改成1让它为true
Alt text
最终效果
Alt text

三、课后小作业

丑小鸭师傅的demo
链接:https://pan.baidu.com/s/1cUInoi 密码:07p9
Alt text
定位关键词:登录失败

Alt text
使用jadx-gui逆向分析可以直接看到账密(hfdcxy/1234)
Alt text
smali代码分析
判断输入的用户名是是否和v0的值相等,如果相等就进入密码的判断,如果密码判断成功就进入登录成功的代码里
如果有一个不相等就跳入cond_1b登录失败

Alt text
Alt text
Alt text

直接在第一次判断之前加入跳转,跳转到if-eqz v0, :cond_1b判断账密是否正确之后的代码里
Alt text
最终效果
Alt text


安卓逆向这档事-第三节.初识smali,vip终结者
http://example.com/2023/11/13/安卓逆向这档事-第三节-初识smali,vip终结者/
作者
John Doe
发布于
2023年11月13日
许可协议