本帖最后由 rong 于 2021-04-11 17:30 编辑
得物NewSign分析过程目的: 分析NewSign算法使用到工具jadx frida ida
该app很恶心,有些同学设置了https证书和代{过}{滤}理后,都无法抓包,是因为它在调用okhttp3的时候设置了 NO_PROXY模式 所以需要先把它干掉,不然我们抓不到包,话不多说,直接上脚本try {
var URL = Java.use('java.net.URL')
URL.openConnection.overload('java.net.Proxy').implementation = function (
arg1
) {
return this.openConnection()
}
} catch (e) {
console.log('' + e)
}
try {
var Builder = Java.use('okhttp3.OkHttpClient$Builder')
var mybuilder = Builder.$new()
Builder.proxy.overload('java.net.Proxy').implementation = function (arg1) {
return mybuilder
}
} catch (e) {
console.log('' + e)
}
然后我们就可以欢快的抓包了 很好,我们抓到包了. 我们大概看一下结构 header部分我们暂时不用管.只需要注意timestamp. 我们看postdata部分 newSign 这是我们今天的主角..... 返回内容是明文,我们没什么好研究的.
我们先看下这个东西怎么来了. 把得物.apk拖入jadx先分析 搜索字符串 "newSign"
看到有5个地方 咱们从第一个开始,进入后看到
newSign是从 RequestUtils.c(hashMap2, currentTimeMillis) 来的 先看看hashMap2 是什么
发现hashMap2只是一个 HashMap 字典. currentTimeMillis 就是一个时间戳,做了一个运算,减去一个超时时间,在实际使用中 直接传当前时间戳-1000 就可以有效了. 然后我们进 RequestUtils.c 看看是什么
该函数分解 在我们传进来的字典中添加 uuid, platform, v, loginToken, timestamp 然后对字典的所有key 进行升序排序 接下来生成一个新的字符串 比如hashMap 是 {"c": 1, "a": 2} 那么经过上面的过程生成的新字符串是: a2c1 然后最后返回是 a(AESEncrypt.b(DuHttpConfig.c, sb2)); 我们继续先进到 AESEncrypt.b 看看
拆解b干了些啥 先调用 getByteValues 获取值 然后将该值就行反转,所谓反转的意思是 0变1 非0变0 如: 1ac100 反转后 结果是 000011 因为非0 都是0 0是1 然后调用 encodeByte 就行计算并返回 然后 getByteValues encodeByte 都是so里面的函数,我们拉到上面可以看到
这两个函数都是 JNIEncrypt 这个so文件的 (不会有人不会提取吧,好吧.把.apk文件改成.rar,然后打开,在lib里面找.全名是 lib + 引用库名 + .so, 上面的结果就应该是 libJNIEncrypt.so) 现在就需要上我们的ida了
直接看到了 java函数和so函数的对应关系 getByteValues -> get_bytes encodeByte -> encode 我们先进入 get_bytes 看看
我的天啊 一堆字符拼接,要取这里的内容 可以直接用frida调用一次就出来了.不用深究.我们看 encode 发现关键点了. AES ECB PKCS5PADDING 我们看看 这个函数是干嘛的 进去以后看到各种算法,在最后返回了一个base64 我们猜测这个就是加密的关键函数,但是我们没有明文和密钥. 现在我们就来取一下看看 先看改函数的声明如下:
有两个参数,我们用frida直接hook它 看看能得到什么? 直接上脚本 var AESBase = Module.findExportByName("libJNIEncrypt.so", "AES_128_ECB_PKCS5Padding_Encrypt")
console.log(AESBase);
Interceptor.attach(AESBase, {
onEnter: function(args){
console.log("-------------参数 1-------------");
console.log(args[0].readUtf8String())
console.log("-------------参数 2-------------");
console.log(args[1].readUtf8String());
},
onLeave: function(retValue){
console.log("-------------返回-------------");
console.log(retValue.readUtf8String());
}
})
通过以上返回结合我们抓包时提交和上面看到的hashmap处理方式 我们可以基本断定 16个X 就是aes加密的key 到此 encodeByte 分析完毕 接下来回到java代码中,因为aes后还有一个 a 函数的调用 我们进到a函数.... 好吧 就是一个MD5,非魔改的md5..... 结论newSign = MD5(aes_ecb_pk5padding(排序拼接成的字符, 16个x)) 感谢各位...... 写教程不易,请不要吝啬各位的免费积分.再次感谢各位.
|