目的: 分析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))