记某APP登录逆向解密过程
字数 1142 2025-08-22 12:23:13
APP登录逆向解密过程教学文档
1. 逆向分析准备
1.1 环境搭建
- 测试设备:安装目标APP到测试机
- 抓包工具:Burp Suite配置
- 电脑端配置BP代理端口
- 手机端设置代理与电脑同网络
- 反编译工具:JADX用于反编译APK
- 动态分析工具:Frida用于Hook验证
1.2 基本流程
- 安装目标APP到测试设备
- 抓取登录请求包
- 识别加密字段
- 反编译APP分析代码
- 定位关键加密方法
- Hook验证加密逻辑
- 还原加密算法
2. 密码加密逆向分析
2.1 定位密码加密位置
- 搜索关键字:
login/login.ashx - 定位到
UserModel接口下的SecurityUtil.encodeMD5(str3)
2.2 MD5加密验证
- 代码分析:
SecurityUtil.encodeMD5(passwordString) - Python验证:
import hashlib md5 = hashlib.md5() md5.update(b"123456") print(md5.hexdigest()) # e10adc3949ba59abbe56e057f20f883e - 通过对比抓包数据确认是标准MD5加密
2.3 Frida Hook验证
Java.perform(function() {
var SecurityUtil = Java.use("com.example.app.util.SecurityUtil");
SecurityUtil.encodeMD5.implementation = function(str) {
console.log("MD5 input: " + str);
var result = this.encodeMD5(str);
console.log("MD5 output: " + result);
return result;
};
});
3. 签名(_sign)逆向分析
3.1 定位签名生成位置
- 搜索关键字:
_sign - 关键类:
SignManager - 关键方法:
signByType
3.2 签名生成逻辑
- 固定前缀字符串:
W@oC!AH_6Ew1f6%8 - 拼接请求参数(按字典序排序)
- 再次拼接固定后缀字符串
- 对拼接结果进行MD5加密
- 结果转为大写
3.3 Python实现
import hashlib
def generate_sign(data_dict):
data = "W@oC!AH_6Ew1f6%8"
# 按key排序拼接
result = "".join(["{}{}".format(key, data_dict[key])
for key in sorted(data_dict.keys())])
un_sign_string = f"{data}{result}{data}"
sign = hashlib.md5(un_sign_string.encode()).hexdigest().upper()
return sign
4. UDID加密分析
4.1 UDID组成
getIMEI(context) + "|" + System.nanoTime() + "|" + SPUtils.getDeviceId()
4.2 IMEI获取逻辑
- 首先尝试从SharedPreferences读取
- 若不存在则通过系统API获取:
((TelephonyManager)context.getSystemService("phone")).getDeviceId() - 若获取失败则使用WIFI MAC地址生成UUID
- 最终回退到随机UUID
4.3 3DES加密过程
- 加密方法:
SecurityUtil.encode3Des - 关键参数:
- Key:
appapiche168comappapiche168comap(前24字节有效) - IV:
appapich - 模式: CBC
- Key:
4.4 Python实现
from Crypto.Cipher import DES3
import base64
def encrypt_3des(plaintext):
BS = 8
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
key = b'appapiche168comappapiche168comap'[0:24]
iv = b'appapich'
cipher = DES3.new(key, DES3.MODE_CBC, iv)
padded_text = pad(plaintext).encode('utf-8')
encrypted = cipher.encrypt(padded_text)
return base64.b64encode(encrypted).decode()
5. 完整登录请求构造
5.1 请求参数示例
params = {
"_appid": "atc.android",
"appversion": "3.37.0",
"channelid": "csy",
"pwd": md5("123456"), # e10adc3949ba59abbe56e057f20f883e
"udid": encrypt_3des("IMEI|nanoTime|deviceId"),
"username": "13111111111"
}
5.2 签名生成
sign = generate_sign(params)
params["_sign"] = sign
6. 关键Hook点总结
6.1 MD5加密Hook
Java.use("com.example.app.util.SecurityUtil")
.encodeMD5.implementation = function(str) {
// 打印输入输出
return this.encodeMD5(str);
};
6.2 签名生成Hook
Java.use("com.example.app.manager.SignManager")
.signByType.implementation = function(type, map) {
// 打印输入参数
var result = this.signByType(type, map);
// 打印签名结果
return result;
};
6.3 3DES加密Hook
Java.use("com.example.app.util.SecurityUtil")
.encode3Des.implementation = function(context, str) {
// 打印明文和context信息
var result = this.encode3Des(context, str);
// 打印加密结果
return result;
};
7. 逆向技巧总结
- 关键字搜索:通过接口路径、参数名等快速定位关键代码
- 静态分析:结合反编译工具理清代码逻辑
- 动态验证:使用Frida Hook关键方法验证分析结果
- 算法还原:通过输入输出对比确认加密算法
- 参数追踪:对于依赖上下文(Context)的方法,注意参数来源
- JNI处理:对于so文件加密,可考虑Hook获取关键值而非直接逆向
8. 完整Python实现示例
import hashlib
from Crypto.Cipher import DES3
import base64
def md5_encrypt(text):
return hashlib.md5(text.encode()).hexdigest()
def encrypt_3des(plaintext):
BS = 8
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
key = b'appapiche168comappapiche168comap'[0:24]
iv = b'appapich'
cipher = DES3.new(key, DES3.MODE_CBC, iv)
padded_text = pad(plaintext).encode('utf-8')
encrypted = cipher.encrypt(padded_text)
return base64.b64encode(encrypted).decode()
def generate_sign(data_dict):
fixed_str = "W@oC!AH_6Ew1f6%8"
sorted_params = "".join(f"{k}{v}" for k, v in sorted(data_dict.items()))
sign_str = f"{fixed_str}{sorted_params}{fixed_str}"
return md5_encrypt(sign_str).upper()
# 构造登录请求
login_params = {
"_appid": "atc.android",
"appversion": "3.37.0",
"channelid": "csy",
"pwd": md5_encrypt("123456"),
"udid": encrypt_3des("cf15599b-5e93-3be5-a705-a39403227dfd|13359325995159|366586"),
"username": "13111111111"
}
login_params["_sign"] = generate_sign(login_params)
print("Final login params:", login_params)
通过以上步骤,我们完整还原了APP登录过程中的各个加密环节,包括密码的MD5加密、UDID的3DES加密以及请求签名的生成逻辑。