本文仅供学习交流,只提供关键思路不会给出完整代码,严禁用于非法用途,若有侵权请联系我删除!
目标app: 5ouN5ouN5Lil6YCJMy45LjY=
目标接口:aHR0cHM6Ly9hcGkubS5qZC5jb20vYXBp
一、引言
1、本篇分析某二手交易平台 pp严选关键词搜索涉及的加密 sign,body
二、抓包分析
1、安装app至模拟器上,开启Fiddler,按下图配置代理
2、成功抓到包,发现请求body中sign,body字段存在加密字符串。
三、sign参数
1、使用Jadx反编译apk,全局搜索sign。我们会发现出来太多行代码,不太好分析。推荐一个搜索小技巧,改为搜索 put("sign" ,"sign" 等字段,刷选有用信息。
调整搜索后,出来几条关键信息:
我们跟进去,定位到关键代码:
hashMap2.put("sign", xu2.b(hashMap2, "6ab527a5d7f643728bac669543b92727"));
hook验证:
function hook() {
var xu2 = Java.use("com.jd.paipai.ppershou.xu2");
xu2["b"].implementation = function (hashMap, str) {
// console.log(`xu2.b is called: hashMap=${hashMap}, str=${str}`);
console.log("hashMap: " + hashMap)
var result = this["b"](hashMap, str);
console.log("result: " + result);
return result;
};
}
hook到结果,发现和我们抓包中的sign一模一样。说明成功找到生成位置!
hashMap: {loginType=4, networkType=wifi, screen=720x1280, functionId=pp.own.channel.biz.inspect.search.list, uuid=1682eadfa03390e9, appid=ppershou, body={"query":{"latitude":"y5Oa2ZqV2qDqdXdnpqHFSA==","recheck":1,"pageNo":1,"longitude":"rvV+ggPmeJQ53yaoJh+lyQ==","key":"iPhone13","pageSize":16}}, ext={"privacyAgreed":1,"referer":"paipai\/android\/3.9.6\/SearchIndexActivity"}, t=1692082902668, build=309060, client=paipai_android, clientVersion=309060, osVersion=Android 7.1.2, partner=ppershou, channel=QIHOO}
result: 05f61ee02e05db33f4a2a6358f07a7a8668cc7992256548d23153199e1b5c83e
2、sign算法还原,观察生成代码,非常明显的HmacSHA256加密特征,遍历Map, 填充&字符后拼装在一起,做HmacSHA256加密,key是 6ab527a5d7f643728bac669543b92727。
我们将代码抠出来执行,缺啥补啥。
/**
* HmacSHA256加密
* @param hashMap 请求体中的值
* @param str 秘钥
* @return 加密后的字符串
*/
public static String b(HashMap<String, String> hashMap, String str) {
if (hashMap.isEmpty() || TextUtils.isEmpty(str)) {
return null;
}
TreeSet<String> treeSet = new TreeSet<>(hashMap.keySet());
StringBuilder stringBuffer = new StringBuilder();
for (Object o : treeSet) {
String str3 = hashMap.get(o.toString());
if (!TextUtils.isEmpty(str3)) {
stringBuffer.append(str3);
stringBuffer.append(FIELD_DELIMITER);
}
}
String stringBuffer2 = stringBuffer.toString();
if (stringBuffer2.endsWith(FIELD_DELIMITER) && stringBuffer2.length() > 1) {
stringBuffer2 = stringBuffer2.substring(0, stringBuffer2.length() - 1);
}
byte[] bytes = stringBuffer2.getBytes();
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(str.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKeySpec);
return a(mac.doFinal(bytes));
} catch (InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
直接执行,得到结果,还原成功!
四、body参数
1、body参数为如下这一串,经过我调试验证 hdid是写死的。
body={"hdid":"JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw=","ts":1692081460878,"ridx":-1,"cipher":{"body":"oyTndWVyoIS6oyTiYXHfdRVuZIS6Sxu1J2OyWxPWCxPOcWHYZQ5mcUrQU0O9FISiSxTvY2rvY2isEtOiSxLrZ2VEbyS6CImsbQ9kZ2v0dWHvStescxZWA2dxUQ1vIvO1C3vrb0feA2n5UJ09Ssmsa2V5StesaVLeb25vCJCsBMTmYWdvU2v6ZIS6CJZ9pG=="},"ciphertype":5,"version":"1.2.0","appname":"com.jd.paipai.ppershou"}
2、回到sign的位置,上面一行是body的赋值。我们可以根据这个打出堆栈往上分析。
hashMap2.put("body", new JSONObject(map).toString());
或者直接搜索JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw= 这个固定值,很快能定位到关键位置。
往上找到算法是个native方法,时间紧张,我们直接hook上层方法:
function hook9() {
var dc2 = Java.use("com.jd.paipai.ppershou.dc2");
dc2["a"].implementation = function (map) {
var jsonObj = Java.use('org.json.JSONObject').$new(map);
console.log("map : " + jsonObj.toString())
var result = this["a"](map);
console.log("result: " + result);
return result;
};
}
返回结果就是我们想要的!!!
入参:{"body":"{\"query\":{\"latitude\":\"cwLVo6aFXtB6JuOJauet+Q==\",\"recheck\":1,\"pageNo\":1,\"longitude\":\"Ex5uLAbq5hktzPkRkng\\\/vw==\",\"key\":\"小米\",\"pageSize\":16}}"}
result:{"hdid":"JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw=","ts":1691647002731,"ridx":-1,"cipher"
搭建RPC主动调用。收工收工!