app逆向java层一般步骤
0.
frida版本号14.2.2
objection==1.9.6
app版本4.22.0
1.抓包
使用Charles
和Postern
,通过VPN
代理形式进行抓包,而不是通过给WIFI
设置HTTP
代理的方式。使用VPN
可以同时抓到Http(s)
和Socket
的包。
2.抓取目标用户的用户信息
其URL
为https://yapi.haohaozhu.cn/member/getUserInfo
加密参数shawshank
,打开jadx
搜索shawshank
,得知该参数是一个n2类里名为E的常量,接下来搜n2.E
,调用的位置锁定位置。
com.hzhu.m.f.b.d.a
关健代码:
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
动态调试下
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
得到结果
(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
由结果得知他有两个重载方法。
因为通过jadx分析我们知道参数java.util.TreeMap
的方法才是我们想要的。所以修改objection代码,在需要hook的方法后面加个空格加上参数类型,可以进一步锁定具体是那个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
:打印参数
--dump-backtrace
: 打印调用栈
--dump-return
:打印返回值
然后现在objection处于等待状态,重新点击app上的内容,可以得到下面的内容,其中关键代码
(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)
.....后面的调用栈省略
通过上面的结果 我们知道了返回值
qEpcsu2CCkruqxB6h.itrY2p2tx1wchcSiAE5QNgxOMAtH4yGpq4n4C9P3JM9nDz4I23igrYVBNTsiY9eVP5NvV-bE3Su6aspx_z2xZfusGGtETbuehv2g=
就是我们的目标结果,然后参数就不知道是个啥了,只知道是java.util.TreeMap
实例, objection对于这种复杂的参数类型是无法打印的,这个时候我们就要借助frida了
。先用objection生成个frida代码模版。
android hooking generate simple com.hzhu.m.f.b.d
结果
Java.perform(function() {
var clazz = Java.use('com.hzhu.m.f.b.d');
clazz.a.implementation = function() {
//
return clazz.a.apply(this, arguments);
}
});
objection只能生成一个大概的框架代码,具体内容还需要自己加,保存下来先运行看看。之后执行代码
frida -U com.hzhu.m -l crack_haohaozhu.js
得到错误提示,我们可以根据错误提示进一步优化代码,这里我们知道了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);
}
});
得到传入的参数为
{"uid":"3171385"}
接下来就是找到算法的位置。将之前静态分析的代码简化
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
根据jadx上面的提示
/* compiled from: Base64 */
盲猜之后做了一个base64操作(后来证实确实是)。
得到结果replace之后还没完,接下来还有个
StringBuilder sb = new StringBuilder();
sb.append(n2.A);
sb.append(replace);
return sb.toString();
查看代码得知n2.A
是qEpcsu2CCkruqxB6h.itrY2p2tx。
至此到这里就分析完了。
最终的shawshank的结果就是上面的sb.toString()的值。
简单捋一下结果
1.传入目标字符串{"uid":"3171385"}
,注意是字符串。uid就是用户的id
2.com.hzhu.base.f.x.b.a
一顿操作生成byte数组
3.然后做个base64操作,将字节数组转成字符串。
4.在得到的结果前面拼接上n2.A,得到最终加密参数。