App逆向流程
1.抓包
使用Charles和Postern,通過VPN代理形式進行抓包,而不是通過給WIFI設(shè)置HTTP代理的方式。使用VPN可以同時抓到Http(s)和Socket的包。
2.抓取目標用戶的用戶信息
其URL為https://yapi.haohaozhu.cn/member/getUserInfo
加密參數(shù)shawshank,打開jadx搜索shawshank,得知該參數(shù)是一個n2類里名為E的常量,接下來搜n2.E,調(diào)用的位置鎖定位置。
com.hzhu.m.f.b.d.a
關(guān)鍵代碼:
public static String a(TreeMap<String, String> treeMap) {
String replace = com.hzhu.base.f.x.a.a(com.hzhu.base.f.x.b.a(new Gson().toJson((Object) treeMap), n2.B)).replace("+", com.xiaomi.mipush.sdk.Constants.ACCEPT_TIME_SEPARATOR_SERVER).replace(com.appsflyer.share.Constants.URL_PATH_DELIMITER, "_");
StringBuilder sb = new StringBuilder();
sb.append(n2.A);
sb.append(replace);
return sb.toString();
}
使用objection動態(tài)調(diào)試下
objection -g com.hzhu.m explore
hook下上面的方法
android hooking watch class_method com.hzh
u.m.f.b.d.a --dump-args --dump-backtrace --dump-return
得到結(jié)果
(agent) Attempting to watch class com.hzhu.m.f.b.d and method a.
(agent) Hooking com.hzhu.m.f.b.d.a(java.util.TreeMap)
(agent) Hooking com.hzhu.m.f.b.d.a(boolean)
(agent) Registering job 1408148254974. Type: watch-method for: com.hzhu.m.f.b.d.a
由結(jié)果得知他有兩個重載方法。
因為通過jadx分析我們知道參數(shù)java.util.TreeMap的方法才是我們想要的。所以修改objection代碼,在需要hook的方法后面加個空格加上參數(shù)類型,可以進一步鎖定具體是那個hook方法的。
android hooking watch class_method com.hzh
u.m.f.b.d.a java.util.TreeMap --dump-args --dump-backtrace --dump-return
--dump-args:打印參數(shù)
--dump-backtrace: 打印調(diào)用棧
--dump-return:打印返回值
然后現(xiàn)在objection處于等待狀態(tài),重新點擊app上的內(nèi)容,可以得到下面的內(nèi)容,其中關(guān)鍵代碼
(agent) [0475123810009] Arguments com.hzhu.m.f.b.d.a("<instance: java.util.TreeMap>")
(agent) [0475123810009] Return Value: "qEpcsu2CCkruqxB6h.itrY2p2tx1wchcSiAE5QNgxOMAtH4yGpq4n4C9P3JM9nDz4I23igrYVBNTsiY9eVP5NvV-bE3Su6aspx_z2xZfusGGtETbuehv2g="
(agent) [1408148254974] Called com.hzhu.m.f.b.d.a(boolean)
(agent) [1408148254974] Backtrace:
com.hzhu.m.f.b.d.a(Native Method)
com.hzhu.m.f.b.d$b.intercept(HttpInit.java:3)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:10)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:1)
com.hzhu.m.f.b.c.intercept(HhzExceptionCheckInterceptor.kt:16)
.....后面的調(diào)用棧省略
通過上面的結(jié)果 我們知道了返回值
qEpcsu2CCkruqxB6h.itrY2p2tx1wchcSiAE5QNgxOMAtH4yGpq4n4C9P3JM9nDz4I23igrYVBNTsiY9eVP5NvV-bE3Su6aspx_z2xZfusGGtETbuehv2g=就是我們的目標結(jié)果,然后參數(shù)就不知道是個啥了,只知道是java.util.TreeMap實例, objection對于這種復雜的參數(shù)類型是無法打印的,這個時候我們就要借助frida了
。先用objection生成個frida代碼模版。
android hooking generate simple com.hzhu.m.f.b.d
結(jié)果
Java.perform(function() {
var clazz = Java.use('com.hzhu.m.f.b.d');
clazz.a.implementation = function() {
//
return clazz.a.apply(this, arguments);
}
});
objection只能生成一個大概的框架代碼,具體內(nèi)容還需要自己加,保存下來先運行看看。之后執(zhí)行代碼
frida -U com.hzhu.m -l crack_haohaozhu.js
得到錯誤提示,我們可以根據(jù)錯誤提示進一步優(yōu)化代碼,這里我們知道了a有兩個重載方法。
Error: a(): has more than one overload, use .overload(<signature>) to choose from:
.overload('java.util.TreeMap')
.overload('boolean')
Java.perform(function() {
const gson = Java.use('com.r0ysue.gson.Gson').$new();
var clazz = Java.use('com.hzhu.m.f.b.d');
clazz.a.overload('java.util.TreeMap').implementation = function(x) {
//
console.log("x:=",x);
const json_x=gson.toJson(x)
console.log("json_x",json_x);
return clazz.a.apply(this, arguments);
}
});
得到傳入的參數(shù)為
{"uid":"3171385"}
接下來就是找到算法的位置。將之前靜態(tài)分析的代碼簡化
String replace = com.hzhu.base.f.x.a.a(com.hzhu.base.f.x.b.a(new Gson().toJson((Object) treeMap), null)).replace("+", "-").replace("/", "_");;
首先,
com.hzhu.base.f.x.b.a(new Gson().toJson((Object) treeMap), n2.B)
我們知道他的返回值為byte[] 類型,然后看外層的com.hzhu.base.f.x.a.a
根據(jù)jadx上面的提示
/* compiled from: Base64 */
盲猜之后做了一個base64操作(后來證實確實是)。
得到結(jié)果replace之后還沒完,接下來還有個
StringBuilder sb = new StringBuilder();
sb.append(n2.A);
sb.append(replace);
return sb.toString();
查看代碼得知n2.A是qEpcsu2CCkruqxB6h.itrY2p2tx。
至此到這里就分析完了。
最終的shawshank的結(jié)果就是上面的sb.toString()的值。
簡單捋一下結(jié)果
1.傳入目標字符串{"uid":"3171385"},注意是字符串。uid就是用戶的id
2.com.hzhu.base.f.x.b.a一頓操作生成byte數(shù)組
3.然后做個base64操作,將字節(jié)數(shù)組轉(zhuǎn)成字符串。
4.在得到的結(jié)果前面拼接上n2.A,得到最終加密參數(shù)。
