Android应用逆向工程技术参考手册

⚠️ 法律与道德警告 本文档仅用于技术研究和学习目的。修改、反编译或分发受版权保护的应用程序可能违反《计算机软件保护条例》和相关法律法规。未经授权修改应用程序可能构成侵权。请仅在您拥有合法权限的应用上进行测试。
一、基础概念与工具
1.1 Smali语法基础
# 常用指令
const/4 v0, 0x1 # 将常量1赋值给寄存器v0 (4位)
const v0, 0x1 # 将常量1赋值给寄存器v0 (32位)
const-wide v0, 0x... # 赋值64位长整型
return v0 # 返回v0的值
return-void # 无返回值返回
invoke-virtual {v0}, L类名;->方法名()V # 调用实例方法
1.2 核心破解思路
- 赋值法:修改返回值使条件永远为真/假
- 跳转法:修改条件跳转逻辑
- 删除法:移除调用代码或Activity
- 替换法:替换关键字符串或资源
二、弹窗与广告去除
2.1 通用弹窗移除
# 定位弹窗显示代码
invoke-virtual {v0}, Landroid/app/AlertDialog;->show()V
# 破解方法:直接删除show()调用或在其前添加return-void
.method public showDialog()V
.registers 1
return-void # 直接返回,不执行弹窗
.end method
2.2 启动页广告跳过
方法一:直接返回
# 搜索"跳过"相关方法
.method public onCreate(Landroid/os/Bundle;)V
.registers 2
return-void # 结束广告Activity
.end method
方法二:修改启动Activity
<!-- AndroidManifest.xml中修改主入口 -->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
2.3 布局隐藏法
<!-- 在XML中隐藏广告视图 -->
android:visibility="gone" <!-- 完全隐藏 -->
android:width="0dp" <!-- 宽度设为0 -->
android:height="0dp" <!-- 高度设为0 -->
2.4 广告Activity移除
<!-- 在AndroidManifest.xml中删除以下广告Activity -->
<!-- 腾讯广告 -->
<activity android:name="com.qq.e.ads.ADActivity"/>
<!-- 百度广告 -->
<activity android:name="com.baidu.ads.ADActivity"/>
<!-- 谷歌广告 -->
<activity android:name="com.google.android.gms.ads.AdActivity"/>
<!-- 或 -->
<activity android:name="com.google.ads.ADActivity"/>
<!-- 支付宝H5支付 -->
<activity android:name="com.alipay.sdk.app.H5PayActivity"/>
三、会员与权限破解
3.1 通用会员破解(赋值法)
# 搜索方法名:isVip, getIsVip, isLogin, isPremium, isSubscribe, isBuy
# 标准破解模式
.method public isVip()Z
.registers 1
const/4 v0, 0x1 # 0x1 = true (会员)
return v0
.end method
# 去广告赋值
.method public isAdFree()Z
.registers 1
const/4 v0, 0x0 # 0x0 = false (无广告)
return v0
.end method
3.2 布尔值破解原理
# z代表布尔类型 (Z = boolean)
.field private isFlag:Z
# 0x1 = true, 0x0 = false
const/4 v0, 0x1 # 赋值为真
const/4 v0, 0x0 # 赋值为假
3.3 高级赋值示例
# 赋值会员到期时间
const-string v0, "2099-01-01"
# 赋值超长会员期限
const-wide v0, 0x1e0cb12f93dd60L # 269999年
# 赋值天数
const v0, 0x3bb2b0b # 700天
四、登录与验证绕过
4.1 登录状态破解
# 搜索方法名:isLogin, getEnable
.method public isLogin()Z
.registers 1
const/4 v0, 0x1 # 强制返回已登录
return v0
.end method
4.2 反跳转破解法
# 原代码:如果v3等于0则跳转到cond_45
if-eqz v3, :cond_45
# 破解后:如果v3不等于0则跳转(逻辑反转)
if-nez v3, :cond_45
# 或直接删除条件判断,改为无条件跳转
goto :cond_45
4.3 分支破解法
# 在验证分支顶部强制赋值
.method public checkLicense()V
.registers 2
const/4 v0, 0x1 # 强制成功
# 后续所有分支都会认为验证通过
...
.end method
五、签名验证绕过
5.1 通用签名绕过
# 搜索关键词:sign, signature, checkSign, verify, getPackageManager
# 修改getSignature方法
.method public getSignatures()Ljava/lang/String;
.registers 1
const-string v0, "testkey" # 返回测试签名
return-object v0
.end method
# 或直接返回验证成功
.method public checkSignature()I
.registers 1
const v0, 0x0 # 0 = VALID
return v0
.end method
5.2 华为签名特殊处理
# 在闪退的代码处添加
.registers 1
const v0, 0x0
return v0
六、游戏内购破解(高风险警告)
⚠️ 此部分内容涉及支付系统欺诈,仅供技术研究,严禁用于非法用途!
6.1 通用游戏支付破解
# 搜索方法名:onPayNotify, purchased, onBillingFinish
# Yodo1 SDK通用破解
# 定位到:Lcom/yodo1/android/sdk/helper/Yodo1PayHelper;->purchased(...)
# 在方法内插入:
const p1, 0x1 # 强制支付成功
6.2 各平台支付方法名
| 平台 | 关键方法名 | 破解策略 |
|---|---|---|
| 4399 | notifydelivergoods |
赋值为真 |
| VIVO | onReceiveServerCommand / paySuccessCallback |
复制成功代码到失败分支 |
| OPPO | onCallCarrierPay / onSuccess |
替换onFailure |
| 腾讯 | midaSpayCallback / onPayNotify |
删除跳转,修改switch分支 |
| 咪咕 | onResult / onChinaBillingResult |
强制成功 |
| 联通 | onPayResult / pyaResult |
修改返回值 |
| 电信 | paySuccess |
覆盖失败代码 |
| 360 | onFinished / onActivityResult |
修改支付结果 |
6.3 支付关键词搜索
成功:succeed, success, VALID, paySuccess
失败:fail, failed, INVALID, payFailed
取消:cancel, payCancel
七、正则表达式批量修改
7.1 SharedPreferences布尔值破解
# 搜索模式
ip"\s*.*\s*invoke-interface \{.*\}, Landroid/content/SharedPreferences;->getBoolean\(Ljava/lang/String;Z\)Z\s*move-result (.*)
# 替换为
$0 \n const $1, 0x1
八、资源替换技巧
8.1 水印去除
- 提取APK中的图片资源
- 使用透明PNG图片替换水印文件
- 保持文件名和路径一致
- 重新打包
8.2 强制下载软件破解
# 搜索指定软件包名,替换为已安装应用包名(如QQ)
# 原代码:
const-string v0, "com.target.app"
# 破解后:
const-string v0, "com.tencent.mobileqq"
九、常见关键词速查表
9.1 会员/付费相关
isvip, getisvip, ispremium, issubscribe, isbuy, hasbought
getenable, islogin, isunlimit, showvip
9.2 广告相关
show_ad, showdialog, mdialog, adactivity
//ad, /ad/, adview, adlayout
9.3 游戏数值相关
gold, coin, money, cash, gem, diamond
health, life, hp, mp, attack, defence
9.4 支付相关
purchase, billing, pay, order, trade
notifydelivergoods, onpaynotify, onbillingfinish
十、安全加固对抗
10.1 加固识别与修复
常见加固方案:
- 360加固
- 腾讯乐固
- 百度加固
- 网易易盾
修复教程参考:https://bbs.binmt.cc/thread-35986-1-1.html
10.2 签名校验定位
// Java层校验特征
getPackageManager()
getPackageInfo()
getSignatures()
verify()
checkSign()
signatures
十一、完整破解流程示例
案例:去广告+解锁VIP
# 1. 定位VIP检查
.method public isVip()Z
.registers 1
const/4 v0, 0x1 # 强制VIP
return v0
.end method
# 2. 定位广告显示
.method public showAd()V
.registers 1
return-void # 直接返回不显示
.end method
# 3. 修改AndroidManifest.xml
# 删除广告Activity声明
# 4. 绕过签名验证
.method public checkSignature()I
.registers 1
const v0, 0x0 # 返回验证成功
return v0
.end method
十二、重要提醒
- 备份原始APK:所有修改前务必做好备份
- 逐步测试:每次只修改一处,便于定位问题
- 权限清理:删除不必要的短信、支付权限
- 法律风险:商业软件破解可能面临法律诉讼
- 道德约束:尊重开发者劳动成果
技术无罪,但使用需负责。请将此知识用于正当目的!
十三、必备工具链推荐
13.1 核心工具
# 反编译/回编译
apktool d app.apk # 反编译
apktool b app -o new.apk # 回编译
# 签名工具
apksigner sign --ks keystore.jks new.apk
# 字节码编辑器
jadx-gui # Java代码查看
MT管理器 # 手机端Smali编辑
13.2 辅助工具
- NP管理器:MT管理器替代品,支持Dex合并
- Apktool M:在线反编译工具
- GDA Pro:强大的反编译分析工具
- Frida:动态Hook框架(无需修改APK)
十四、Smali高级指令详解
14.1 寄存器操作
# 寄存器类型
v0-v15 # 局部寄存器(16个)
p0-p3 # 参数寄存器(方法参数)
# 常用赋值
const/4 v0, 0x1 # 4位常量(-8到7)
const/16 v0, 0x10 # 16位常量
const v0, 0x1000 # 32位常量
const-wide v0, 0x100L # 64位常量(long/double)
const-string v0, "vip" # 字符串常量
# 数组操作
new-array v0, v1, [I # 创建大小为v1的int数组
fill-array-data v0, :array_0 # 填充数组数据
14.2 方法调用类型
invoke-virtual # 调用实例方法(有this)
invoke-static # 调用静态方法
invoke-direct # 调用私有/构造方法
invoke-super # 调用父类方法
invoke-interface # 调用接口方法
十五、APK结构深度解析
APK文件结构:
├── META-INF/ # 签名信息
│ ├── MANIFEST.MF
│ └── CERT.SF
├── AndroidManifest.xml # 清单文件(反编译后)
├── classes.dex # Dex字节码(可多个)
├── resources.arsc # 编译后的资源索引
├── res/ # 资源文件
│ ├── layout/ # 布局
│ ├── drawable/ # 图片
│ └── values/ # 字符串、颜色等
├── assets/ # 原始资源
└── lib/ # native库(.so)
关键文件定位技巧:
- 字符串:
res/values/strings.xml - 布局ID:在
public.xml中查找对应ID - 图片资源:根据ID在
res/drawable-*中查找
十六、代码混淆应对方案
16.1 混淆特征识别
# 混淆后的类名特征
Lcom/a/b/c/a; # 短类名
La/b/c/d/e/f; # 深层嵌套
# 字符串加密特征
invoke-static {v0}, Lcom/sdk/util;->a(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0 # 解密后的字符串
16.2 反混淆技巧
- 字符串搜索:搜索URL、类名、关键词
- API定位:搜索
Toast、AlertDialog等系统API - 资源ID跟踪:通过R$id.xxx定位代码位置
- 日志分析:搜索
Log.d/e/i找到关键代码段
十七、动态调试技术(无需修改)
17.1 Frida Hook示例
// Hook isVip方法
Java.perform(function() {
var cls = Java.use('com.app.VipManager');
cls.isVip.implementation = function() {
console.log('[*] isVip() called, returning true');
return true; // 强制返回true
};
});
17.2 Xposed模块(需Root)
// Xposed钩子
findAndHookMethod("com.app.VipManager",
lpparam.classLoader,
"isVip",
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
param.setResult(true); // 直接返回结果
}
});
十八、常见错误排查
18.1 安装失败问题
# 错误:INSTALL_PARSE_FAILED_NO_CERTIFICATES
# 解决:重新签名
apksigner sign --ks keystore.jks app.apk
# 错误:INSTALL_FAILED_INVALID_APK
# 解决:检查AndroidManifest.xml语法
# 错误:INSTALL_FAILED_UPDATE_INCOMPATIBLE
# 解决:卸载原版后安装
18.2 闪退问题排查
# 1. 检查日志
adb logcat | grep "FATAL"
# 2. 常见闪退原因
- 签名校验未绕过
- 删除了必要的方法调用
- 寄存器数量不匹配(.registers)
- 资源ID未找到
# 3. 快速修复:在onCreate首行添加
.method protected onCreate(Landroid/os/Bundle;)V
.registers 2
return-void # 直接返回测试是否还闪退
.end method
18.3 寄存器错误修复
# 错误:register v10 exceeds register count
# 解决:增加.registers数量
.method public test()V
.registers 12 # 至少要比使用的最大寄存器大1
# 使用v0-v11
.end method
十九、资源ID定位技巧
19.1 从布局到代码
<!-- res/layout/activity_main.xml -->
<Button android:id="@+id/btn_vip"/>
<!-- 反编译后ID在public.xml -->
<public type="id" name="btn_vip" id="0x7f0800a1" />
<!-- 在Smali中引用 -->
const v1, 0x7f0800a1 # 加载ID
invoke-virtual {p0, v1}, Lcom/app/MainActivity;->findViewById(I)Landroid/view/View;
19.2 快速查找工具
# 搜索资源引用
grep -r "0x7f0800a1" smali/
# 搜索字符串
grep -r "去开通VIP" smali/
二十、加固与反加固
20.1 常见加固方案
| 加固厂商 | 特征 | 脱壳工具 |
|---|---|---|
| 360加固 | libjiagu.so | BlackDex, FART |
| 腾讯乐固 | libshell.so | dexHunter |
| 百度加固 | libbaiduprotect.so | dcc工具 |
| 网易易盾 | libnesec.so | Frida脚本 |
20.2 通用脱壳步骤
- 内存Dump:在运行时从内存中Dump Dex
- 修复DEX:修复Dump出的Dex文件头
- 替换资源:将原APK中的classes.dex替换
- 重新打包:使用apktool重新编译
二十一、反破解检测绕过
21.1 常见检测项
# 1. 调试检测
invoke-static {}, Landroid/os/Debug;->isDebuggerConnected()Z
move-result v0
if-nez v0, :cond_detected # 检测到调试
# 破解:强制返回false
const/4 v0, 0x0
return v0
# 2. Root检测
invoke-static {}, Lcom/sdk/RootCheck;->isRoot()Z
# 破解同上
# 3. 模拟器检测
invoke-static {}, Lcom/sdk/EmulatorCheck;->isEmulator()Z
# 破解同上
21.2 签名校验深度绕过
# 多重校验应对方案
# 在Application的attachBaseContext中插入
.method protected attachBaseContext(Landroid/content/Context;)V
.registers 2
invoke-super {p0, p1}, Landroid/app/Application;->attachBaseContext(Landroid/content/Context;)V
return-void # 跳过所有初始化校验
.end method
二十二、实战:完整破解流程案例
案例:某视频App(VIP+去广告)
步骤1:定位VIP校验
# 搜索关键词
grep -r "isVip" smali/ | grep ".method"
# 结果:smali/com/app/UserManager.smali
步骤2:修改VIP方法
# 原代码
.method public isVip()Z
.registers 2
iget-boolean v0, p0, Lcom/app/UserManager;->vipStatus:Z
return v0
.end method
# 破解后
.method public isVip()Z
.registers 2
const/4 v0, 0x1
return v0
.end method
步骤3:移除广告Activity
<!-- AndroidManifest.xml -->
<!-- 删除 -->
<activity android:name="com.google.android.gms.ads.AdActivity"/>
步骤4:屏蔽广告加载
# 搜索showAd方法
.method public showAd()V
.registers 1
return-void # 直接返回
.end method
步骤5:绕过签名校验
# 搜索signatures
.method public getSignatures()[Landroid/content/pm/Signature;
.registers 2
const/4 v0, 0x0
return-object v0 # 返回null
.end method
步骤6:重新打包测试
apktool b app -o cracked.apk
apksigner sign --ks mykey.jks cracked.apk
adb install cracked.apk
二十三、法律与道德边界
23.1 合法使用场景
✅ 个人学习研究 ✅ 安全漏洞分析 ✅ 兼容性修改(自己设备) ✅ 开源软件修改
23.2 非法行为
❌ 破解后分发 ❌ 盗取付费内容 ❌ 绕过安全机制获利 ❌ 恶意植入代码
23.3 自我保护原则
- 不传播破解版
- 不用于商业目的
- 不侵犯隐私数据
- 保留原始版权信息
二十四、快速查询手册
24.1 修改对照表
| 目的 | 搜索关键词 | 修改方式 | Smali代码 |
|---|---|---|---|
| 解锁VIP | isVip/isLogin | 赋值 | const/4 v0, 0x1 |
| 去广告 | showAd/ADActivity | 删除/return-void | return-void |
| 绕过登录 | isLogin/getUser | 强制true | const/4 v0, 0x1 |
| 跳过启动页 | SplashActivity | 修改LAUNCHER | 修改Manifest |
| 去更新 | checkUpdate | 删除调用 | return-void |
| 无限资源 | coin/gold | 赋值最大值 | const v0, 0x7fffffff |
24.2 正则表达式集合
# 获取布尔值
invoke-interface \{.*\}, Landroid/content/SharedPreferences;->getBoolean\(.*\)Z\s*move-result (.*)
# 获取字符串
invoke-interface \{.*\}, Landroid/content/SharedPreferences;->getString\(.*\)Ljava/lang/String;\s*move-result-object (.*)
# 替换为
$0 \n const $1, 0x1 # 布尔
$0 \n const-string $1, "vip" # 字符串
二十五、结语
逆向工程是一门需要耐心和实践的技术。建议从简单的开源APK开始练习,逐步掌握Smali语法和Android运行机制。记住:
技术本身中立,但使用者的选择决定了其价值。
请始终在法律和道德框架内使用这些技术,将其用于学习、安全研究和正当的兼容性改进。
正文完