声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请后台私信作者删除
目标版本:3.1.7
包名:com.maihan.tredian
加固状态:梆梆加固(自行脱壳)
逆向参数:sign
reqable抓包分析
打开 app,在首页进行刷新
tzrd
tzrd是AES/CBC/PKCS5Padding加密 用Java层自吐算法跑一下就行,这里就不多赘述了
key = "PeMBjWOVbrMgElXO" # 16字符密钥
iv = "VTToNCiifIJ9c2co" # 16字符IV
脱壳后直接搜sign,也可以用frida进行hook
其中SignUtil.sign函数就是我们生成处,可以使用 frida 代码验证位置是否正确,鼠标放到 sign 右键复制 frida 代码:
function hook_sign() {
Java.perform(function () {
let SignUtil = Java.use("com.maihan.tredian.util.SignUtil");
SignUtil["sign"].implementation = function (params) {
console.log(`SignUtil.sign is called: params=${params}`);
let result = this["sign"](params);
console.log(`SignUtil.sign result=${result}`);
return result;
};
})
}
发现结果一致,我们继续向下分析,点进去这个函数,最后定位到 native层加密,并加载sign.so文件:
so 层分析
从apk拿到libsign.so 文件,文件在 lib 目录下:

将该so文件放到ida进行分析,看是否是静态注册的,可以看到是的:
点进sign函数:
可以看到很明显的sha1算法字样
主动调用一下,发现不是标准的sha1
function tao_zui_hook() {
Java.perform(function () {
let SignUtil = Java.use("com.maihan.tredian.util.SignUtil");
let str = "app_ver=137&nonce=dfnz0j1750166051745×tamp=1750166051&tzrd=qbGdG/Y4/KQicYpcNFlQbh1CWCHVag9sTUlQphlzFE27gbOT+dnKwohF0cxXSGUqEVm7NUMK6fphCqPqFhrMSEN32TdrUXISmmltsBOnUbgJKcCGim1GPS6FF1CKPlTlzuKwCPedDm1WxpsqMQigDUfxnnjMFnlHH8whlrhNrRw/er6dJIjdlh4I56GlUqL+2M9ni0t38BdF9pGor6SpRpVbW96g8OFTYlCjZU1tEd0uMa4U2VYnnE2294D1fcITjJhWhWL8y5iE5thQwTxUiULny9MJpdtisG9qd/Ht0FQyB9rmcyetxp25r72wZXTUpImq5WJp8YrE5/Rc7cQtcELfWAqHW95aYADprTcRT/ZiwQSBB4VNsXwhAl4pD/pimMPQYzXUT2qj0wXm3Gwf7TLGAzf3495fFUb50zD5DBA=";
console.log('str: ' + str);
let result = SignUtil.sign(str);
console.log('result:' + result);
return result;
})
}
可以看到,计算结果不一致。继续向下分析,找到了一个关键函数:base64_encode_new。这个函数对拼接后的字符串进行Base64编码,结果放在v9,点进该函数:
看起来像是在做 base64 编码,并把第二个参数当作返回值返回,我们使用 frida hook这个函数,按 tab 键,找到该函数的地址:
hook代码:
let so_addr = Module.findBaseAddress("libsign.so");
let sub_107C_addr = so_addr.add(0x107C);
Interceptor.attach(sub_107C_addr, {
onEnter: function (args) {
this.arg2 = args[1];
console.log("sub_107C_addr is called! args[0]: ", args[0].readCString());
},
onLeave: function (retval) {
console.log("sub_107C_addr is called! args[1]: ", this.arg2.readCString());
console.log("sub_107C_addr retval:", retval);
}
})
观察打印日志,可以看到在查询参数后面加上了一段字符,然后在进行 base64 编码
经测试,sha1和base64为标准的加密算法。
结果
