作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除!
前言:本人也是android逆向新手,本文主要记录和回顾整理一些分析过程,因此并不能做到每处细节详解,主要为同样入门学习的朋友提供些思路和案例,高手大佬也还请多指教。
过frida反调试
首先写个测试脚本然后frida spwan方式注入看看是否存在注入检测
functionhook_test() {Java.perform(function () {console.log("hook test called"); });}可以看到app启动后弹出弹窗但是进程并没有杀死,应该是存在frida检测。

之前学习frida检测的案例时候,大多都是杀掉进程,这里有些不一样。

也尝试过通过pthread_create、clone等寻找检测点,但是没有成功待以后技术有所提升或有相关思路在进行分析吧。目前还是换个思路找弹窗的触发时机并hook拦截,经验证该方法可行,因为不杀掉进程不影响后续分析。

可以看到成功拦截弹窗了,hook_dialog.js脚本如下:
Java.perform(function () {constDialog = Java.use('android.app.Dialog');constLog = Java.use('android.util.Log');constException = Java.use('java.lang.Exception');Dialog.show.implementation = function () {const stack = Log.getStackTraceString(Exception.$new());if (stack.indexOf('injectmonitor') !== -1) {console.log('\n[!!!] Inject monitor dialog triggered!');console.log(stack);// 这里可以直接阻断return; }returnthis.show(); };});抓包
接下来就是抓包,有抓包检测。如图

这里需要绕过SSL pinning,成功后抓到包了。

脱壳
然后打开jadx静态分析下,搜索PostData,因为加固的原因应该是搜索不到有用的信息的。

需要脱壳处理,首先整体脱下,我是通过hook ClassLinker:DefineClass。hook_define_class.js脚本
functionhook_define_class() {var module_name = "libart.so";var target_module = Process.findModuleByName(module_name);if (!target_module) {console.log("[-] 未找到 " + module_name);return; }// var dump_dir = "/sdcard/dex_dump";var dump_dir="/data/data/包名/cache"var symbols = target_module.enumerateSymbols();var target_addr = null;for (var i = 0; i < symbols.length; i++) {var name = symbols[i].name;if (name.indexOf("ClassLinker") !== -1 && name.indexOf("DefineClass") !== -1) {if (name.indexOf("Thread") !== -1 && name.indexOf("DexFile") !== -1) { target_addr = symbols[i].address;break; } } }if (!target_addr) {console.log("[-] 未能定位到 ClassLinker::DefineClass 函数");return; }console.log("[*] 成功hook DefineClass,准备本地 Dump...");var dumped_dex = {};Interceptor.attach(target_addr, {onEnter: function (args) {try {var className = Memory.readUtf8String(args[2]);var dex_file_ptr = args[5];if (dex_file_ptr.isNull()) return;var base = null;var size = 0;for (var offset = 1; offset <= 3; offset++) {try {var maybe_base = dex_file_ptr.add(offset * Process.pointerSize).readPointer();var magic = Memory.readUtf8String(maybe_base, 4);if (magic === "dex\n") { base = maybe_base; size = dex_file_ptr.add((offset + 1) * Process.pointerSize).readPointer().toInt32();break; } } catch (e) {} }// 3. 执行本地写入if (base && size > 0) {var base_str = base.toString();if (!dumped_dex[base_str]) { dumped_dex[base_str] = true;// 构造文件名:以十六进制基址和大小命名var file_path = dump_dir + "/" + base_str + "_" + size + ".dex";console.log("\n[+] 发现新 DEX (来自类: " + className + ")");console.log(" 尝试保存至: " + file_path);try {// 写入手机本地var file = newFile(file_path, "wb"); file.write(base.readByteArray(size)); file.flush(); file.close();console.log(" [✓] Dump 成功!大小: " + size + " 字节"); } catch (file_err) {console.log(" [✗] 写入失败。原因可能为权限不足(Android 12 分区存储限制)");console.log(" 错误详情: " + file_err); } } } } catch (err) {} } });}hook_define_class();一共20多个dex文件,然后mt修复下dex

再次jadx打开,基本就能看到包结构了,再搜索下参数PostData。

但是经过测试登录时候并没有走这里,而是makeRequestParam,这里函数应该是被抽取了。

后来又通过主动调用尝试脱下壳得到如下结果

最终可以自己据此动态分析或利用jadx-ai-mcp分析,找到加密逻辑。我这里最终复现看是标准SM4-CBC然后标准base64,并且是在java层的。

结尾:总的来说有很多待提升的地方,要学会波浪式前进多实战和复盘,此次分析也参考了看雪的大佬文章https://bbs.kanxue.com/thread-290187-5.htm
夜雨聆风