一、目标
今天的目标是这个sign和appcode
二、步骤
Jadx没法上了
app加了某梆的企业版,Jadx表示无能为力了。
FRIDA-DEXDump
DexDump出来,木有找到有效的信息。
Wallbreaker
葫芦娃的Wallbreaker可以做些带壳分析,不过这个样本,用Frida的Spawn模式可以载入,Attach模式会失败。而直接用Objection确无法载入。导致用不了Wallbreaker。
r0tracer
今天的新朋友是肉丝大佬的 r0tracer
r0tracer可以根据黑白名单批量追踪类的所有方法。 我们来尝试追踪一下包含 sign 的类或者方法
function main() { Java.perform(function () { console.Purple("r0tracer begin ... !") /* //以下三种模式,取消注释某一行以开启 */ //A. 简易trace单个函数 // traceClass("javax.crypto.Cipher") //B. 黑白名单trace多个函数,第一个参数是白名单(包含关键字),第二个参数是黑名单(不包含的关键字) // hook("javax.crypto.Cipher", "$"); hook("sign", "$"); //C. 报某个类找不到时,将某个类名填写到第三个参数,比如找不到com.roysue.check类。(前两个参数依旧是黑白名单) // hook("com.roysue.check"," ","com.roysue.check"); }) }
Spawn模式启动App
$ frida -U -f com.platexx.boxxoota -l r0tracer.js --no-pause -o saveLog1.txt
输出
Spawned `com.platexx.boxxoota`. Resuming main thread! [MI NOTE Pro::com.platexx.boxxoota]-> r0tracer begin ... ! start Begin Search Class... Found Class => Tracing Method : com.wxxotel.app.service.signservice.OpenSignService.execute [1 overload(s)] Tracing Method : com.wxxotel.app.service.signservice.OpenSignService.getPath [1 overload(s)] Tracing Method : com.wxxotel.app.service.signservice.OpenSignService.$init [1 overload(s)]
木有啥有用的信息,咱们换个 试试 Sign
输出,然后,然后就挂了……
Spawned `com.platexx.boxxoota`. Resuming main thread! [MI NOTE Pro::com.platexx.boxxoota]-> r0tracer begin ... ! start Begin Search Class... Found Class => Tracing Method : libcore.reflect.GenericSignatureParser.isStopSymbol [1 overload(s)] Tracing Method : libcore.reflect.GenericSignatureParser.expect [1 overload(s)] Tracing Method : libcore.reflect.GenericSignatureParser.parseClassSignature [1 overload(s)] Tracing Method : libcore.reflect.GenericSignatureParser.parseClassTypeSignature [1 overload(s)] Tracing Method : libcore.reflect.GenericSignatureParser.parseFieldTypeSignature [1 overload(s)] Tracing Method : libcore.reflect.GenericSignatureParser.parseForClass [1 overload(s)]
这个 libcore.XXXX类,一看就不像是咱们的菜,过滤掉它再试试。
hook("Sign", "libcore");
啊哈,这下看上去很拉风的样,貌似有戏。
翻了翻输出,
com.besxxxhotel.app.whnetcomponent.utils.SignUtil.getAppCode [1 overload(s)] com.besxxxhotel.app.whnetcomponent.utils.SignUtil.getSignString [1 overload(s)]
这两兄弟相当可疑,我们这次追踪下 SignUtil
hook("SignUtil", "$");
*** entered com.platexx.boxxoota.app.whnetcomponent.utils.SignUtil.getSignString arg[0]: 0 => "0" arg[1]: vadjlr4k3o;qj4io23ug9034uji5rjn34io5u83490u5903huq => "vadjlr4k3o;qj4io23ug9034uji5rjn34io5u83490u5903huq" arg[2]: 00000000-7e21-1806-0000-00000033c587 => "00000000-7e21-1806-0000-00000033c587" arg[3]: 1622430128929 => "1622430128929" arg[4]: 0,0 => "0,0" arg[5]: 6698 => "6698" java.lang.Throwable at com.besxxxhotel.app.whnetcomponent.utils.SignUtil.getSignString(Native Method) at com.besxxxhotel.app.whnetcomponent.net.JJSignInterceptor.handlerRequest(JJSignInterceptor.java:114) at com.besxxxhotel.app.whnetcomponent.net.JJSignInterceptor.intercept(JJSignInterceptor.java:38) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:760) ======================================================================================================================================================================================================== retval: C5F29B0EF472EDA271313155307E8077 => "C5F29B0EF472EDA271313155307E8077" *** exiting com.besxxxhotel.app.whnetcomponent.utils.SignUtil.getSignString
- 参数 0 1 是固定值
- 参数 2 应该是 did
- 参数 3 是当前时间戳
- 参数 4 也是固定值
- 参数 5 就比较奇怪了, 在日志里面搜索一下,发现 5是 函数 decodeASCII 的返回值, 它的入参是一个 java.util.Map。
在117行微调一下,打印下这个map
var strType = JSON.stringify(arguments[j]); // console.log(strType); if(strType.indexOf('HashMap') > 0){ console.log(arguments[j].entrySet().toArray()); }
就知道是本次请求的内容。
systemVersion=7.0,sid=306267,userId=0,clientVersion=5.2.9,deviceType=MI NOTE Pro,did=174670d6754469115964f1387aed0a96,appId=105,deviceCode=,os=android
搞定,收工……
三、总结
趁手的工具多搞几个,技多不压身。
r0tracer的名称过滤,搞成正则表达式会不会更帅?
壳还是要搞一下的,如果把壳脱了,这个App就没啥难度了。
当你走上了不一样的道路,你才有可能看到和别人不一样的风景
TIP: 本文的目的只有一个就是学习更多的逆向技巧和思路,如果有人利用本文技术去进行非法商业获取利益带来的法律责任都是操作者自己承担,和本文以及作者没关系,本文涉及到的代码项目可以去 奋飞的朋友们 知识星球自取,欢迎加入知识星球一起学习探讨技术。有问题可以加我wx: fenfei331 讨论下。
关注微信公众号: 奋飞安全,最新技术干货实时推送