Android逆向学习笔记(六)
目录
smali及其语法
数据类型
| Java类型 | Smali表示 | 说明 |
|---|---|---|
| byte | B | 字节型 |
| char | C | 字符型 |
| short | S | 短整型 |
| int | I | 整型 |
| long | J | 长整型 |
| float | F | 单精度浮点 |
| double | D | 双精度浮点 |
| boolean | Z | 布尔型 |
| void | V | 无返回值 |
常量
| const/4 v0,0x1 | 4位常量:v0=1 |
|---|---|
| const/16 v0,0x100 | 16位常量:v0=256 |
| const v0, 0x12345678 | 32位常量 |
| const-wide/16 v0, 0x100 | 宽(64位)常量 |
| const-string v0, “hello” | 字符串常量 |
| const-class v0, Ljava/lang/String; | 类常量 |
算数运算指令
| add-int v0, v1, v2 | v0 = v1 + v2 (int) |
|---|---|
| sub-int v0, v1, v2 | v0 = v1 - v2 |
| mul-int v0, v1, v2 | v0 = v1 * v2 |
| div-int v0, v1, v2 | v0 = v1 / v2 |
| rem-int v0, v1, v2 | v0 = v1 % v2 |
条件控制指令
| 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 | 获取寄存器数据 |
寄存器
在smali里的所有操作都必须经过寄存器来进行:
本地寄存器 用v开头数字结尾的符号来表示,如v0、 v1、v2。
参数寄存器 则使用p开头数字结尾的符号来表示,如p0、p1、p2。
特别注意的是,p0不一定是函数中的第一个参数,在非static函数中,p0代指“this”,p1表示函数的第一个 参数,p2代表函数中的第二个参数。而在static函数中p0才对应第一个参数(因为Java的static方法中没有this方法)
demo3作业
首先下载核心破解,下载好之后会有弹窗显示权限问题,点击弹窗
下载好这个软件之后,即使我们的签名不一致也可以重新安装。
打开这个demo看看关键词是什么
可以看到是请先充值大会员
在开始破解之前,我们需要知道代码的逻辑是什么
将apk文件拖入jadx中查看java源与smali代码
逻辑很简单:
- 当金币数量小于10时,提醒先获得10个硬币
- 当不是会员时提醒先充值会员
(smali码太长不再展示,由于jadx无法加注释,看unicode码很难受,我就使用了Androidkiller来进行反编译,这样得到的unicode可以看见中文,比较方便)
破解逻辑:
- 修改跳转条件,使得能执行会员逻辑
- 使用goto直接跳转
- 修改寄存器内的值
修改跳转条件
用MT管理器打开demo后,定位到我们要改的地方(可以直接搜索:大会员)
1 | const/4 p5, 0x1 |
代码如上
这一段就是先判断金币够不够10,如果够10的话,跳转到cond_15(下一个if语句),那么要想改变这个逻辑,使得如果不够也要跳转,就将if-ge 改成if-le。
这段就是判断p0是否等于0,如果等于0的话跳转到cond_43(请充值会员这里),如果想直接往下运行,不进行跳转,可以直接将这个跳转语句注释掉(往前加#即可)。
使用goto直接跳转
我们可以直接跳过中间的if判断,直接进行goto跳转
加完goto之后,直接改变了我们的控制流
改完之后,保存,成功!
修改寄存器的值
到这里其实根据修改寄存器的值也能明显知道怎么修改,我们会跳转就是因为不满足条件,那我们直接将寄存器改了让它满足条件不就好了?
首先是这里,我想让它跳转到cond_15,但是必须满足p0>=v0才可以,这里的v0=10,那直接将v0改成0,不管p0等于多少都是大于等于的。
代码向下执行时,会进入isvip()这个函数,将返回值赋给p0,这里的move-result:
当你调用一个方法后(使用 invoke-* 指令),该方法的返回值会存储在一个特殊的寄存器中,你需要使用 move-result 或 move-result-wide 将其移动到指定的寄存器中才能使用。
再往下看,如果po=0就跳转到cond_43,这里同样不能跳转,那就要修改isvip()的返回值,我们跟进isvip()这个函数。
这里的返回值是v0,我们将v0改成1就可以了。保存,成功!
流程可以简单总结一下:
- 根据关键词查到相关函数。
- 修改函数逻辑(改变执行流或者改变寄存器值)