第一章:撕开应用的面具 —— APK逆向与代码审计实战
本文介绍了安卓APK文件的安全分析方法,主要包括静态分析和动态修改两部分。通过JADX-GUI和Apktool工具,可以反编译APK查看源代码和资源文件,寻找硬编码密钥、权限泄露等漏洞。文章演示了如何绕过Root检测和利用电商App的价格篡改漏洞,并给出防御建议:代码混淆、避免硬编码密钥、服务器端参数校验等。这些技术既可用于安全测试,也能帮助开发者提高应用安全性。
1. 为什么我们要“拆”APK?
在安卓系统中,应用(App)是以 APK(Android Package) 格式分发的。你可以把它想象成一个压缩包(类似ZIP),里面装满了应用运行所需的代码、图片和配置。
渗透测试员的逻辑:
开发者写的代码是“防御工事”。如果我们能看懂工事的设计图(源代码),就能找到没锁门的窗户(硬编码密钥)或脆弱的墙角(逻辑漏洞)。
实例场景:
某银行APP在登录时,声称对密码进行了高强度加密。作为安全测试员,我们需要验证它是否真的加密,还是只是“假装加密”(比如用Base64编码冒充AES加密)。
2. 工欲善其事:工具准备
在这一章,我们主要用到两个工具:
-
JADX-GUI:一个能将APK反编译成近乎原始Java代码的工具。它是我们的“透视镜”。
-
Apktool:一个能解析APK资源文件(如布局、菜单)并反编译
AndroidManifest.xml的工具。它是我们的“拆解刀”。
3. 第一步:静态分析(不运行App,只看代码)
3.1 查看“身份证”:AndroidManifest.xml
每个安卓应用都有一个“身份证”,即 AndroidManifest.xml。它告诉系统这个App需要什么权限,有哪些页面(Activity)。
实战操作:
使用 Apktool 反编译 APK:
apktool d target_app.apk -o output_folder
打开 AndroidManifest.xml,我们通常会寻找以下内容:
-
权限泄露:
<uses-permission android:name="android.permission.READ_SMS" />(一个手电筒App申请读取短信权限?可疑!) -
暴露的组件:
android:exported="true"。如果一个登录页面(Activity)被设置为exported=true,意味着其他App可以不经过授权直接启动它,从而绕过锁屏密码验证。
3.2 寻找“藏宝图”:反编译DEX代码
APK里最核心的是 classes.dex文件,这是Dalvik虚拟机执行的字节码。我们用 JADX-GUI 打开APK。
实例:寻找硬编码密钥
很多初级开发者会把加密密钥直接写在代码里。
原始代码(开发者视角):
public class CryptoUtil {
// 千万别像我这样写!
private static final String AES_KEY = "MySuperSecretKey123";
}
反编译后(测试员视角):
在JADX的搜索框中输入 key、password、secret、token。
瞬间,我们发现了 AES_KEY = "MySuperSecretKey123"。
后果:攻击者可以用这个密钥解密APP传输的所有加密数据,所谓的“端到端加密”形同虚设。
4. 第二步:修改与重打包(动态篡改)
有时候,光看不行,我们还需要“动手”。比如,我们要绕过App的“强制更新”弹窗,或者绕过“越狱/Root检测”。
4.1 实例:绕过Root检测
很多金融App如果发现手机被Root了,会直接闪退。其代码逻辑通常是这样的:
if (isDeviceRooted()) {
Toast.makeText(this, "检测到Root,应用即将退出", Toast.LENGTH_LONG).show();
finish(); // 关闭应用
}
渗透手法(Smali修改):
-
使用 Apktool 反编译得到
smali代码(Dalvik汇编语言,比Java更底层但可读)。 -
搜索
isDeviceRooted方法的调用处。 -
修改逻辑:把
if-eqz(如果等于0则跳转)改为if-nez(如果不等于0则跳转),或者直接删除finish()这一行代码。 -
使用
apktool b重新打包,并使用jarsigner重新签名。
结果:
App 再也检测不到 Root 了,我们就可以在 Root 环境下使用 Frida 等工具进行更深度的注入了。
5. 第三步:实例演练 —— 某电商App的“低价购买”漏洞
这是一个经典的代码审计案例。
背景:
某电商App在确认订单页面,显示商品价格为 1000元。
审计过程:
-
用 JADX 打开 App,定位到“创建订单”的代码。
-
发现代码逻辑如下:
// 前端代码 double price = getIntent().getDoubleExtra("price", 0.0); // ... 显示价格 ... createOrder(price); -
漏洞点:App 直接从 Intent(页面跳转的数据载体)里获取价格,并没有去服务器校验这个价格是否真实。
攻击复现:
我们不需要修改App代码,只需要写一个攻击用的App(或一行ADB命令):
Intent intent = new Intent();
intent.setClassName("com.target.shop", "com.target.shop.OrderActivity");
intent.putExtra("price", 0.01); // 把价格篡改为0.01元
startActivity(intent);
结果:
点击下单,服务器可能真的收到了 0.01 元的支付请求。这就是典型的客户端信任漏洞。
6. 防御视角的加固建议
作为开发者,看完上面的攻击手段,应该如何防御?
-
代码混淆:使用 ProGuard 或 R8。让反编译出来的代码变量名变成
a,b,c,增加阅读难度(但无法完全阻止)。 -
移除硬编码:绝对不要把密钥写在代码里,使用 Android Keystore System 来存储密钥。
-
参数校验:永远不要相信客户端传来的数据。价格、数量等关键参数必须由服务器端生成和校验。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)