安居客 app nsign 生成逻辑说明文档
本项目主要来更详细地介绍 unidbg 的使用方法,会对一些之前已经经常提到的方法省略。
1. 前提准备
逆向安居客 app nsign
参数前准备如下:
- 抓包工具
- unidbg 下载地址
java
环境:用于打 jar
包 - 配置好逆向环境的真机,本文使用的是一加
7 pro
- 安居客
app
: 任意版本即可,本文示例为 v15.28.1
2. 逆向步骤
2.1. 抓包
这里以二手房接口为例:
二手房接口示例
nsign 参数缺失结果图
注意事项:
- 最好经过多次抓包,确定变动值的参数,优先解决变动值的生成逻辑
- 用抓包工具去除一些参数并重新发包来确定某些必须生成的参数(或者使用
py
发包调试出重要参数)
然后,你就会知道:必须正常生成 nsign
验签参数,才能正常获取数据。
2.2. 查壳
由下图可知加固状态,没壳即可直接 jadx
反编译分析了。
app 查壳结果
2.3. jadx 定位
没什么好说的,直接搜索关键值 "nsign"
即可准确定位唯一处。简单的搜索定位技巧不再说了,若有多个搜索结果或不确定是否定位准确时,可通过 frida hook
确认下。
nsign 参数赋值定位
紧接着,进入这个 m52928c
详情中:
m52928c 方法详情
可以看到 getSign0
方法,同样进入其详情:
最终定位处
注意事项:
- 目前可知
getSign0
方法在 so
中实现 - 可以
hook
此处来确认下是否定位正确,看下传参格式等基本信息
2.4. frida hook
接下来 hook getSign0
方法,确认下参数格式。
| setImmediate(function () {
var Map = Java.use('java.util.HashMap');
Java.perform(function () {
var targetClass = 'com.anjuke.mobile.sign.SignUtil';
var methodName = 'getSign0';
var gclass = Java.use(targetClass);
gclass[methodName].overload('java.lang.String', 'java.lang.String', 'java.util.Map', 'java.lang.String', 'int').implementation = function (arg0, arg1, arg2, arg3, arg4) {
console.log('\n[Hook getSign0(java.lang.String,java.lang.String,java.util.Map,java.lang.String,int)]' + '\n\targ0 = ' + arg0 + '\n\targ1 = ' + arg1 + '\n\targ2 = ' + arg2 + '\n\targ3 = ' + arg3 + '\n\targ4 = ' + arg4);
var i = this[methodName](arg0, arg1, arg2, arg3, arg4);
console.log('\treturn ' + i);
console.log("aaaaa", Object.keys(arg2))
console.log("bbbbb", Object.values(arg2))
console.log("ccccc", JSON.stringify(Object.entries(arg2), null, 2))
var args_x = Java.cast(arg2, Map);
console.log("ddddd", args_x.toString())
return i;
}
})
})
|
frida hook 代码示例
frida hook 代码结果上
frida hook 代码结果下
一些提示
- 请自己搜索
frida
如何打印 map object
的方法,懒得搜,后面再补充吧,不影响分析流程。后面考虑直接使用大佬封装好的脚本。 - 这里请自行与抓包结果对照,正常会一致的。
2.5. unidbg 的解决方式
定位到参数生成位置后,就可以考虑如何实现 so
中的方法。算法还原,unidbg
运行 so
还是 rpc
调用呢。这里以 unidbg
为例,毕竟为什么要硬刚呢,以后再考虑添加算法还原的文章。
跳过了 so
文件定位,自己去 hook
定位,定位方法也不止 hook
。直接告诉你,unidbg
示例中也有。接下来运行 libsignutil
的 so 文件即可。
这里添加一个参数示例:
| Map<String, String> paramMap = new HashMap<String, String>() {{
put("map_type", "google");
put("entry", "14");
put("with_broker_recommend", "0");
put("offset", "25");
put("identity", "ce04bfea-954b-4e37-b0c8-835bba810e56");
put("limit", "25");
put("page", "2");
put("city_id", "12");
put("origin_mac", "");
put("app", "a-ajk");
put("_pid", "27472");
put("_guid", "5669139a-22a6-48ae-97a0-e4e5c2489627");
put("macid", "1e95310b70647c7d");
put("version_code", "322132");
put("i", "1e95310b70647c7d");
put("m", "Android-GM1910");
put("uuid", "23e7a068-2ae1-4730-9b11-7778da683893");
put("manufacturer", "OnePlus");
put("o", "OnePlus7Pro-user 9 PKQ1.190110.001 1907281556 release-keys");
put("qtime", "20220303095943");
put("cv", "15.28.1");
put("origin_imei", "");
put("v", "9");
put("ajk_city_id", "12");
put("from", "mobile");
put("pm", "b310");
put("androidid", "1e95310b70647c7d");
put("_chat_id", "");
put("oaid", "");
put("cid", "");
}};
System.out.println(paramMap);
String p1 = "/mobile/v5/recommend/sale/list/history";
String p2 = "d41d8cd98f00b204e9800998ecf8427e";
String p3 = "3daf556e-0ea1-47f2-b43e-5cb384f1b4cc";
int i = 0;
|
2.6. 测试参数
将生成的参数在请求中测试,或者和抓包中的数据对照,成功请求即为正确。
参数生成结果测试
3. 部署方式
unidbg 部署方式
- 一般直接将程序打成
jar
包,其它语言即可调用。 - 也可以使用
unidbg-server
: springboot
运行 unidbg
的方式部署。
3.1. 打包 jar
idea 打包方法网上教程很多了,这里说下注意事项:
maven
版本尽量新,下面会说明配置详情 build
时提示 java: 程序包 sun.security.pkcs 不存在
时,记得切换 idea
中 java
配置
idea 中 maven 配置
build 提示有问题时优先切换 java 版本
环境变量配置一
环境变量配置二
idea
打成 jar
包后就可以用各种语言调用了,这里放个示例图,自己去实现吧。
这里就不再放具体的运行图了,具体执行方法示例请在 unidbg 模拟执行 so 文档中查看,不废话了。
4. 参考文档