APP测试0基础——APP加解密对抗
字数 1149 2025-08-29 08:30:30
APP加解密对抗实战教学文档
一、环境准备
1.1 工具安装
-
Frida框架安装:
pip install frida pip install frida-tools pip install Pyro4 -
Frida-server:
- 版本需与Python安装的frida版本一致
- 获取模拟器架构:
adb shell getprop ro.product.cpu.abi
1.2 部署Frida-server
-
上传frida-server到设备:
adb push frida-server /data/local/tmp/ -
启动frida-server:
adb root adb shell cd /data/local/tmp chmod +x frida-server ./frida-server -
验证连接:
frida-ps -U
二、目标APP分析
2.1 获取目标APP信息
frida-ps -Ua
示例输出:calm.pjtuep.zzdokmht
2.2 初步Hook测试
编写基础Hook脚本hook_key.js:
Java.perform(function () {
var StringCls = Java.use("java.lang.String");
StringCls.getBytes.overload().implementation = function () {
var result = this.getBytes();
if (this.length() > 16) {
console.log("[*] Stack trace:\n" +
Java.use("android.util.Log").getStackTraceString(
Java.use("java.lang.Exception").$new()
));
console.log("[*] getBytes() called with: " + this);
}
return result;
};
});
执行Hook:
frida -U -f "calm.pjtuep.zzdokmht" -l hook_key.js
三、加密算法分析
3.1 定位关键加密类
通过Hook输出定位到关键类:ApiEncryptUtil.java
3.2 加密算法分析
// 解密函数
public static String a(String str) {
try {
byte[] decode = Base64.decode(str, 0); // Base64解码
byte[] bytes = "0nxG8fD2kqlrEv5M".getBytes(); // AES密钥
byte[] bytes2 = "u0r3GcsdXsYmAfhT".getBytes(); // AES IV
SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(bytes2);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKeySpec, ivParameterSpec); // 2=解密模式
return new String(cipher.doFinal(decode), "UTF-8");
} catch (Exception e2) {
e2.printStackTrace();
return "";
}
}
// 加密函数
public static String b(String str) {
try {
byte[] bytes = str.getBytes();
byte[] bytes2 = "0nxG8fD2kqlrEv5M".getBytes("UTF-8"); // AES密钥
byte[] bytes3 = "u0r3GcsdXsYmAfhT".getBytes("UTF-8"); // AES IV
SecretKeySpec secretKeySpec = new SecretKeySpec(bytes2, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(bytes3);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secretKeySpec, ivParameterSpec); // 1=加密模式
return new String(Base64.encode(cipher.doFinal(bytes), 0));
} catch (Exception e2) {
e2.printStackTrace();
return "";
}
}
算法特点:
- AES-CBC模式
- PKCS5Padding填充
- 固定密钥:
0nxG8fD2kqlrEv5M - 固定IV:
u0r3GcsdXsYmAfhT - 数据先Base64编码/解码
四、高级Hook实现
4.1 加解密函数Hook
Java.perform(function(){
var targetClass = Java.use('c.h.a.m.r'); // 根据实际反编译结果填写
// Hook解密函数
targetClass.a.implementation = function(str){
console.log("解密前数据: " + str + "\n\n\n");
var result = this.a(str);
console.log('解密后数据: ' + result + "\n\n\n");
return result;
}
// Hook加密函数
targetClass.b.implementation = function(str){
console.log("加密前数据: " + str + "\n\n\n");
var result = this.b(str);
console.log('加密后数据: ' + result + "\n\n\n");
return result;
}
});
五、Burp自动加解密集成
5.1 设备准备
-
获取设备信息:
import frida frida.get_device_manager().enumerate_devices()示例输出:
Device(id="127.0.0.1:16384", name="PGBM10", type='usb') -
端口转发:
adb forward tcp:27043 tcp:27043 adb forward tcp:27042 tcp:27042
5.2 RPC Hook脚本
decrypt1.js:
Java.perform(function () {
var targetClass = Java.use('c.h.a.m.r');
rpc.exports = {
init: function () {
console.log("[Frida] rpc.exports 初始化成功!");
return "rpc.exports 已加载";
},
enc: function (str) {
try {
console.log("开始加密");
console.log("加密前数据: " + str);
var result = targetClass.b(str);
console.log("加密后数据: " + result);
return result || "防止返回 null";
} catch (e) {
console.log("[Frida] enc 方法执行出错: " + e);
return "防止卡住";
}
},
dec: function (str) {
try {
console.log("开始解密");
console.log("解密前数据: " + str);
var result = targetClass.a(str);
console.log("解密后数据: " + result);
return result || "防止返回 null";
} catch (e) {
console.log("[Frida] dec 方法执行出错: " + e);
return "防止卡住";
}
}
};
});
5.3 Burpy脚本
burpy.py:
import frida
import time
from urllib.parse import unquote, parse_qs, quote
import json
class Burpy:
def __init__(self):
device = self._get_android_usb_device()
pid = device.spawn("calm.pjtuep.zzdokmht")
self.session = device.attach(pid)
device.resume(pid)
self.rpc = self.load_rpc()
def _get_android_usb_device(self):
for x in frida.get_device_manager().enumerate_devices():
if "PGBM10" in x.name:
print(f"设备信息=====> {x}")
return x
def load_rpc(self):
with open("D:\\secTools\\BurpSuite V2023.2.2\\BurpSuite V2023.2.2\\Burpy\\js\\decrypt1.js",
encoding="utf-8", errors="ignore") as f:
script = self.session.create_script(f.read())
script.load()
self.rpc = script.exports_sync
time.sleep(3)
self.rpc.init()
return self.rpc
def convert_to_json(self, body):
try:
if body.strip().startswith('{') and body.strip().endswith('}'):
json_body = json.loads(body)
if 'data' in json_body:
return json_body['data']
else:
parsed_data = parse_qs(body)
return parsed_data['data'][0]
except Exception as e:
print(f"转换失败:{str(e)}")
return None
def rebuild_body(self, body, data):
try:
if body.strip().startswith('{') and body.strip().endswith('}'):
json_body = json.loads(body)
if 'data' in json_body:
json_body['data'] = data
return str(json_body).encode("gbk").decode("gbk")
else:
parsed_data = parse_qs(body)
string_body = "timestamp=" + str(parsed_data['timestamp'][0]) + \
"&data=" + data + \
"&sign=" + str(parsed_data['sign'][0])
return string_body
except Exception as e:
print(f"转换失败:{str(e)}")
return None
def encrypt(self, header, body):
try:
process_data = self.convert_to_json(body)
enc_data = self.rpc.enc(process_data)
body = self.rebuild_body(body, enc_data)
except Exception as e:
print(f"无法找到 enc 方法:{str(e)}")
return header, body
def decrypt(self, header, body):
try:
process_data = self.convert_to_json(body)
dec_data = self.rpc.dec(process_data)
body = self.rebuild_body(body, dec_data)
except Exception as e:
print(f"无法找到 dec 方法:{str(e)}")
return header, body
5.4 Burp配置
- 安装Burpy插件
- 配置:
- Python路径
- burpy.py脚本路径
- 勾选"Enable processor"
六、实战测试流程
- 启动frida-server
- 启动Burpy服务
- 在Burp中:
- 右键请求 -> 扩展 -> Burpy -> decrypt 查看解密内容
- 在Repeater中修改明文后发送,自动加密
- 查看响应自动解密
七、关键概念解释
7.1 Frida
- 动态插桩技术框架
- 支持多平台:Android、Windows、iOS等
- 使用Python/Node.js编写执行脚本
- 使用JavaScript编写注入代码
7.2 Hook技术
- 本质:动态代码注入或函数劫持技术
- 应用:
- 拦截系统API调用
- 修改应用逻辑
- 监视应用行为
7.3 ADB端口转发
- 目的:允许主机Frida客户端与设备frida-server通信
- 常用命令:
adb forward tcp:27042 tcp:27042 adb forward tcp:27043 tcp:27043 - 必要性:建立主机与设备间的通信通道
八、常见问题解决
-
Burp卡死:
- Python脚本出错可能导致Burp卡死
- 解决方案:关闭Burp重新启动
-
中文乱码:
- Repeater中可能出现中文乱码
- 解决方案:使用
encode("gbk").decode("gbk")转换
-
路径问题:
- Burpy脚本路径需使用绝对路径
- 确保路径中不包含中文或特殊字符