高中生

- 金币
- 336
- 好评
- 7
- 信誉
- 100
|
发表于
2025-11-19 17:58:35
来自手机
|
显示全部楼层
| 阅读模式
来自 广东
本帖最后由 sky.纪 于 2025-11-20 17:53 编辑
各位逆向小白们,还在为逆向不会判断而力不从心吗,看完这个教程,立马茅塞顿开!
帖子内容可能质量不高,但已经是我能写出来最好的了,勿喷!帖子仅为正规教程,无任何不良引导
一、先搞懂:安卓逆向的“代码载体”——Smali与DEX基础(类比“快递包装与运输系统”)
开发者写的Java/Kotlin代码,经编译会变成「DEX文件」(类比“快递箱”),我们逆向分析的「Smali代码」,就是“快递箱的开箱说明书”——记录代码逻辑的存放位置、组装方式、使用规则。
简单说:DEX是代码的“存储容器”,Smali是代码的“汇编语言表达”,所有跳转、引用、赋值都要按Smali语法解读,就像看说明书先认文字符号。
1.1 Smali的“变量赋值”:像给快递贴标签+分配存放位置(明确“东西是什么、放哪、归谁”)
核心逻辑:Smali赋值必须“三步走”——明确变量类型→分配内存空间→写入具体内容,就像寄快递:说清物品类型→快递员分货架→放东西贴标签,少一步都不行。
高频赋值场景
【方法声明】
.method public testAssignAll()V
解析:定义公开实例方法,方法名testAssignAll,返回值V(void无返回值)
比喻:快递站贴“临时寄件服务公告”,说明服务名称+无回执
.locals 8
解析:声明8个局部变量(索引0-7),含3个VIP相关变量,虚拟机分配栈内存
比喻:快递员加3个货架,总共8个,专门留3个放会员相关物品
逆向关键:新增变量必须同步加.locals数值,否则App崩溃
【场景1:基本类型赋值(int/boolean/long)】
const/4 v0, 0x5
解析:const/4是4字节int赋值指令(存储-8到7),给v0(货架0)赋值0x5(十进制5)
比喻:把写“5”的火柴盒放0号货架,小数值用小空间
逆向关键:常见“是否会员”(0=非会员,1=会员),改后面十六进制数即可
const/16 v1, 0x100
解析:const/16是16字节int指令(存储-32768到32767),v1(货架1)赋值0x100(256)
比喻:把写“256”的鞋盒放1号货架,中数值用中空间
逆向关键:数值超-8到7就用这个,比如改试用次数100(0x64)不能用const/4
const v2, 0x10000000
解析:const是32字节int指令(存储-2147483648到2147483647),v2赋值0x10000000(268435456)
比喻:把写“268435456”的行李箱放2号货架,大数值用大空间
逆向关键:改大额限制(如支付限额1000000)必须用这个
const-wide/16 v3, 0x20
解析:const-wide/16是16字节long指令(占8字节,需2个连续索引v3/v4),赋值0x20(32)
比喻:超大件占2个连续货架,3号+4号合放“32”
逆向关键:long类型索引必须偶数开头(v0/v1、v2/v3),否则数据错乱
【场景2:字符串赋值】
const-string v0, "会员等级:VIP"
解析:const-string创建字符串实例,存到字符串常量池,v0存实例内存地址(不是字符串本身)
比喻:邮局把信存存档区,货架放信件编号,需通过编号取信
逆向关键:修改字符串要保持长度一致,避免内存溢出
【场景3:对象赋值(含VIP核心赋值)】
new-instance v1, Lcom/example/User;
解析:new-instance创建User对象(含普通+会员属性),堆内存分配空间,v1存对象地址
比喻:买带分层的大箱子,一层装普通信息,一层装会员信息,放1号货架
invoke-direct {v1}, Lcom/example/User;->()V
解析:invoke-direct调用User无参构造方法,初始化对象(isVip默认false,vipExpireTime默认0)
比喻:打开箱子锁,普通层空,会员层贴“非会员”“到期时间:无”标签
逆向关键:改默认会员就把构造方法里isVip的0x0改成0x1,到期时间改未来时间戳
const-string v2, "张三"
invoke-virtual {v1, v2}, Lcom/example/User;->setName(Ljava/lang/String;)V
解析:给User对象的name属性赋值“张三”,invoke-virtual调用setName方法
比喻:把“张三”纸条放进箱子普通层,贴“姓名”标签
【核心:VIP身份赋值】
const/4 v5, 0x1
解析:v5(货架5)赋值0x1(true=会员),boolean本质是int(0=false,1=true)
比喻:把“是会员”红色标签放5号货架,准备贴会员层
逆向关键:原代码0x0(非会员)改成0x1即可强制会员,服务器返回的话要覆盖结果
invoke-virtual {v1, v5}, Lcom/example/User;->setIsVip(Z)V
解析:调用setIsVip方法,给User对象的isVip设为true
比喻:把5号货架的“是会员”标签贴到箱子会员层
逆向关键:无setIsVip方法就找iput-boolean指令,直接改成员变量
【核心:会员到期时间赋值】
const-wide v6, 0x18F0A3000L
解析:const-wide给v6/v7(连续索引)赋值long类型时间戳(0x18F0A3000L=2030年1月1日)
比喻:把“2030年到期”纸条放进会员层,贴“到期时间”标签
逆向关键:时间戳要转十六进制(网上搜“时间戳转十六进制”),确保是long类型(加L后缀)
invoke-virtual {v1, v6, v7}, Lcom/example/User;->setVipExpireTime(J)V
解析:调用setVipExpireTime方法,传入v6/v7的时间戳,设置会员到期时间
比喻:把“2030年到期”纸条固定在会员层,完成会员信息配置
逆向关键:如果是服务器返回的到期时间,在这行前加const-wide覆盖,实现永久会员
return-void
.end method
解析:方法执行结束,返回无值,.end method标记方法结束
比喻:快递打包完成,服务结束,无回执
1.2 赋值的“内存逻辑”:像快递的“存储规则”(逆向必懂)
- 局部变量(v0/v1...):存在栈内存,方法执行完就释放(像临时货架,用完清空)
- 对象/字符串:存在堆内存,通过变量引用(像存档区,编号对应物品)
- 成员变量(isVip、vipExpireTime):存在对象的堆内存中,随对象创建而分配(像箱子的固定分层,跟着箱子走)
二、Smali的“方法引用”:像快递的“中转流程”(明确“找谁帮忙、带什么东西”)
方法引用就是“调用其他方法帮忙”,就像寄快递时,快递员需要找仓库管理员拿货、找分拣员分类,每个环节都要明确“找谁、带什么、要什么结果”。
核心引用指令(纯文本解析,覆盖90%场景)
1. invoke-direct:调用构造方法/私有方法(像找内部员工帮忙,不对外公开)
代码示例:invoke-direct {v1}, Lcom/example/User;->()V
- 解析:{v1}是参数(要初始化的User对象),后面是“类名→方法名(参数类型)返回值”
- 比喻:快递员找内部仓库管理员(私有方法),带空箱子(v1),让管理员解锁(初始化)
- 逆向关键:构造方法是对象属性初始化的核心,改会员默认值必找这个
2. invoke-virtual:调用普通成员方法(像找外部合作商帮忙,公开可调用)
代码示例:invoke-virtual {v1, v5}, Lcom/example/User;->setIsVip(Z)V
- 解析:{v1=User对象, v5=是否会员}是参数,Z=boolean参数类型,V=无返回值
- 比喻:快递员找外部标签商(公开方法),带箱子(v1)和“是会员”标签(v5),让标签商贴标签
- 逆向关键:修改会员、权限等属性,基本都要改这个指令的参数(比如v5从0x0改成0x1)
3. invoke-static:调用静态方法(像找公共服务窗口帮忙,不用带具体物品)
代码示例:invoke-static {v0}, Lcom/example/Utils;->isVipValid(J)Z
- 解析:{v0=到期时间戳}是参数,J=long类型,Z=返回boolean(是否有效)
- 比喻:快递员找邮局公共查询窗口(静态方法),带到期时间(v0),查询会员是否有效
- 逆向关键:静态方法常做校验(会员有效性、签名验证),改返回值就能绕过校验(比如强制返回0x1=true)
4. invoke-interface:调用接口方法(像找第三方代理帮忙,按统一规则办事)
代码示例:invoke-interface {v2, v3}, Lcom/example/VipService;->checkVip(Ljava/lang/String;)Z
- 解析:{v2=VipService接口实例, v3=用户ID},调用checkVip方法校验会员
- 比喻:快递员找第三方安检代理(接口方法),带用户ID(v3),按统一规则安检
- 逆向关键:接口方法常是服务器校验入口,改参数或返回值可绕过服务器校验
方法引用的“参数传递规则”:像快递的“交接清单”
- 参数顺序:{this对象, 参数1, 参数2...}(非静态方法第一个参数是当前对象,静态方法无this)
- 类型标识:V=无返回值,Z=boolean,I=int,J=long,Ljava/lang/String;=字符串
- 逆向关键:参数类型必须和方法声明一致,比如调用setVipExpireTime(J)V,必须传2个连续long参数(v6/v7),否则App崩溃
三、Smali的“跳转逻辑”:像快递的“路线选择”(明确“走哪条路、要不要回头”)
跳转逻辑是App判断“是否会员”“是否有权限”的核心,就像快递根据地址选路线:同城走短途、异地走长途、地址错了返回,每个判断都对应不同的跳转指令。
核心跳转指令(纯文本代码+逻辑拆解)
1. if-eq:等于则跳转(像快递“地址是A城市则走A路线”)
代码示例:
const/4 v0, 0x1 # v0=1(会员标识)
if-eq v0, v1, :label_vip # 若v0 == v1,跳转到:label_vip标签
否则执行下面的代码
:label_vip
会员逻辑代码
- 解析:v0=会员标识,v1=用户当前标识,相等则跳会员逻辑,否则走普通逻辑
- 比喻:快递员看收件地址(v0)和用户填的地址(v1),相等就走会员专属配送路线
- 逆向关键:改跳转条件(比如if-eq改成if-ne,相等不跳),或改v0/v1的值,就能切换会员/普通逻辑
2. if-ne:不等于则跳转(像快递“地址不是A城市则走B路线”)
代码示例:
invoke-static {v2}, Lcom/example/Utils;->isVipValid(J)Z # 调用校验方法
move-result v3 # 接收返回值(0=无效,1=有效)
if-ne v3, 0x1, :label_not_vip # 若v3 != 1,跳非会员逻辑
会员有效逻辑
:label_not_vip
非会员逻辑
- 解析:校验会员是否有效,返回值不等于1则跳非会员,否则走会员
- 比喻:快递员查会员有效期(v3),不是有效(1)就走普通配送路线
- 逆向关键:把if-ne改成if-eq,或直接给v3赋值0x1,就能强制走会员逻辑
3. if-lt:小于则跳转(像快递“重量小于1kg则走散户路线”)
代码示例:
const/4 v4, 0x3 # v4=3(剩余试用次数)
if-lt v4, 0x1, :label_trial_end # 若v4 < 1,跳试用结束
还有试用次数,执行试用逻辑
:label_trial_end
试用结束,提示充值
- 解析:剩余试用次数小于1则跳结束逻辑,否则走试用
- 比喻:快递重量(v4)小于1kg(0x1),走散户路线,否则走批量路线
- 逆向关键:改v4的值(比如0x99=153次),或把if-lt改成if-ge(大于等于则跳),延长试用
4. if-ge:大于等于则跳转(像快递“重量大于等于10kg则走大件路线”)
代码示例:
const-wide v5, 0x18F0A3000L # v5=2030年到期时间
invoke-static {v5}, Lcom/example/Utils;->getCurrentTime()J # 获取当前时间
move-result-wide v6 # 接收当前时间(v6/v7)
if-ge v6, v5, :label_vip_expire # 若当前时间 >= 到期时间,跳会员过期
会员未过期逻辑
:label_vip_expire
会员过期逻辑
- 解析:当前时间大于等于到期时间,跳过期逻辑,否则走未过期
- 比喻:快递员看当前时间(v6)是否超过有效期(v5),超过就走过期处理路线
- 逆向关键:改v5的到期时间(设为2100年),或把if-ge改成if-lt,让会员永远不过期
5. goto:无条件跳转(像快递“不管地址在哪,都走指定路线”)
代码示例:
goto :label_vip # 无条件跳转到:label_vip标签
下面的普通逻辑永远不执行
:label_vip
会员逻辑
- 解析:不管前面什么条件,都跳指定标签,跳过中间代码
- 比喻:快递员不管收件地址,都走会员专属路线,直接配送
- 逆向关键:在普通逻辑前加goto :label_vip,强制走会员逻辑;或在会员校验后加goto,跳过校验
6. switch:多分支跳转(像快递“按地区分路线:北京→路线A、上海→路线B”)
代码示例:
const/4 v0, 0x2 # v0=2(会员等级:1=青铜,2=白银,3=黄金)
packed-switch v0, :switch_data # 按v0的值找对应跳转标签
:label_bronze # 等级1
青铜会员逻辑
goto :label_end
:label_silver # 等级2
白银会员逻辑
goto :label_end
:label_gold # 等级3
黄金会员逻辑
:label_end
:switch_data
.packed-switch 0x1 # 起始值
:label_bronze, :label_silver, :label_gold # 对应值1、2、3的标签
.end packed-switch
- 解析:v0=会员等级,按等级跳对应逻辑,0x1对应青铜,0x2对应白银,0x3对应黄金
- 比喻:快递员按收件地区(v0)分路线,北京(1)走A、上海(2)走B、广州(3)走C
- 逆向关键:改v0的值(比如0x3=黄金),或修改switch_data的标签顺序,让低等级跳高等级逻辑
跳转逻辑的“核心原则”:像快递“路线不能乱”
- 标签必须唯一:每个:label名称不能重复,否则App不知道跳哪
- 跳转不能跨方法:只能在当前方法内跳转,不能跳其他方法的标签
- 逻辑要闭环:跳转后要确保方法有返回值(return-void/return),否则App崩溃
最后学会了请支持一下,拜拜 |
-
查看全部评分
总评分:好评 +1
金币 +1
|