文章总结: 文章详细演示了使用算法助手与Frida框架对某银行APP进行逆向分析的过程。首先通过KitsuneMask获取Root权限并安装LSPosed框架,利用算法助手定位环境检测弹窗触发点AlertMessageDialog,随后编写Frida脚本Hookandroid.app.Dialog.show方法实现弹窗拦截。进一步通过算法助手抓取加密调用栈,分析出用户名采用RSA直接加密,密码则使用AES加密后再用RSA加密密钥的混合加密方案。最后提供完整Frida脚本实现RSAUtils和AESUtils的延迟Hook策略,成功绕过环境检测并获取明文加密数据,为渗透测试人员提供了完整的移动端逆向分析实战案例。
综合评分: 82
文章分类: 移动安全,逆向分析,渗透测试,安全工具,实战经验
【银行逆向百例】16Android逆向之算法助手+frida绕过环境检测分析加密算法
原创
挖个洞先
挖个洞先
挖个洞先
2026年2月10日 09:16
北京
“ 你打算怎么活,今后,在我死之后,你打算过怎样的生活,托尔芬。——《冰海战记》S1E24 ”
01
—
环境版本
环境:
电脑,Windows 11 专业版 23H2
https://github.com/JiaoSuInfoSec/JiaoSuInfoSec_T00ls_Win11
软件:
MuMu模拟器,5.3.4
https://mumu.163.com/download/
Kitsune Mask,27.2
https://github.com/1q23lyc45/KitsuneMagisk/releases
算法助手,1.0.9
https://www.123865.com/s/7G8aTd-bKH4H
LSPosed,1.9.2
https://github.com/LSPosed/LSPosed/releases/tag/v1.9.2
brook,20230606.5
https://github.com/txthinking/brook
frida-server,16.1.8
https://github.com/frida/frida/releases/tag/16.1.8
burpsuite,2025.1
https://portswigger.net/burp/releases
Charles,5.0.2
https://www.charlesproxy.com/download/
02
—
操作步骤
1、弹窗提示设备环境风险,点击确定自动退出APP
2、可写系统盘
https://mumu.163.com/help/20240202/35044_1136675.html
3、安装KitsuneMagisk
https://github.com/1q23lyc45/KitsuneMagisk/releases
4、安装算法助手
https://www.123865.com/s/7G8aTd-bKH4H
5、下载LSPosed-v1.9.2-7024-zygisk-release
https://github.com/LSPosed/LSPosed/releases/tag/v1.9.2
6、允许root权限
7、安装
8、直接安装
9、开启Zygisk
10、关闭模拟器
11、模块安装LSPosed-v1.9.2-7024-zygisk-release
12、关闭模拟器
13、下拉进入LSPosed
14、模块启用算法助手
15、启用模块后关闭模拟器
16、算法助手勾选目标APP
17、弹窗定位,启动APP
18、查看日志
19、复制调用堆栈
20、分析日志,最后调用了AlertMessageDialog.showIosAlert
21、启动frida-server
https://github.com/frida/frida/releases/tag/16.1.8
adb push .\frida-server-16.1.8-android-x86_64 /data/local/tmpadb shellsucd /data/local/tmpchmod +x frida-server-16.1.8-android-x86_64./frida-server-16.1.8-android-x86_64
22、获取包名
frida-ps -Uai
23、hook弹窗通用方法Dialog.show,如果调用堆栈包含AlertMessageDialog关键字就返回空,成功绕过弹窗
Java.perform(function() { var Dialog = Java.use("android.app.Dialog"); Dialog.show.implementation = function() { if (Java.use("java.lang.Thread").currentThread().getStackTrace().toString().indexOf("AlertMessageDialog") !== -1) { console.log("[+] 拦截环境检测弹窗"); return; } return this.show(); };});
24、网络环境勾选
25、抓包请求加密
https://xz.aliyun.com/news/11263
26、算法助手勾选算法分析
27、复制调用堆栈日志
28、分析调用堆栈
用户名,调用 RSAUtils.IdNoEncrypt() → 内部调用 RSAUtils.encrypt() 进行 RSA 加密
com.xxx.utils.keyboardutil.RSAUtils.encryptcom.xxx.utils.keyboardutil.RSAUtils.IdNoEncrypt
密码,调用 RSAUtils.PwdRandomRsaEncrypt() → 内部先用 AESUtils.encrypt() 加密密码,再用 RSA 加密 AES 密钥
com.xxx.utils.keyboardutil.AESUtils.encryptcom.xxx.utils.keyboardutil.AESUtils.encryptcom.xxx.utils.keyboardutil.RSAUtils.PwdRandomRsaEncrypt
29、hook.js
Java.perform(function() { console.log("[*] Frida Hook已启动 - 延迟Hook策略"); // 字节转Hex function bytesToHex(bytes) { if (!bytes) return "null"; var result = ""; for (var i = 0; i < bytes.length; i++) { result += ("0" + (bytes[i] & 0xFF).toString(16)).slice(-2); } return result; } // 打印调用堆栈 function printStackTrace() { console.log("[调用堆栈]"); var traces = Java.use("java.lang.Thread").currentThread().getStackTrace(); for (var i = 0; i < traces.length && i < 10; i++) { var line = traces[i].toString(); if (line.indexOf("cn.com.xxx") !== -1 || line.indexOf("xxx") !== -1) { console.log(" at " + line); } } } // ==================== 弹窗拦截 ==================== try { var Dialog = Java.use("android.app.Dialog"); Dialog.show.implementation = function() { try { if (Java.use("java.lang.Thread").currentThread().getStackTrace().toString().indexOf("AlertMessageDialog") !== -1) { console.log("[+] 拦截环境检测弹窗"); return; } } catch(e) {} return this.show(); }; console.log("[+] 弹窗拦截已启用"); } catch(e) {} // ==================== 延迟Hook目标类 ==================== var rsaHooked = false; var aesHooked = false; var hookAttempts = 0; var maxAttempts = 30; function tryHookTargetClasses() { hookAttempts++; // 尝试Hook RSAUtils if (!rsaHooked) { try { var RSAUtils = Java.use("com.xxx.utils.keyboardutil.RSAUtils"); console.log("[+] RSAUtils 类已加载,开始Hook..."); // Hook encrypt (String, Key) try { RSAUtils.encrypt.overload('java.lang.String', 'java.security.Key').implementation = function(data, key) { console.log("\n================ RSAUtils.encrypt ================"); console.log("[输入] " + data); var result = this.encrypt(data, key); console.log("[输出Hex] " + bytesToHex(result)); printStackTrace(); console.log("=================================================="); return result; }; } catch(e) {} // Hook IdNoEncrypt try { RSAUtils.IdNoEncrypt.implementation = function(idNo) { console.log("\n================ RSAUtils.IdNoEncrypt ================"); console.log("[输入数据] " + idNo); var result = this.IdNoEncrypt(idNo); console.log("[加密结果] " + result); printStackTrace(); console.log("======================================================"); return result; }; } catch(e) {} // Hook PwdRandomRsaEncrypt try { RSAUtils.PwdRandomRsaEncrypt.implementation = function(pwd, randomKey) { console.log("\n================ RSAUtils.PwdRandomRsaEncrypt ================"); console.log("[AES随机密钥] " + pwd); console.log("[明文密码] " + randomKey); var result = this.PwdRandomRsaEncrypt(pwd, randomKey); console.log("[加密结果] " + result); printStackTrace(); console.log("=============================================================="); return result; }; } catch(e) {} rsaHooked = true; console.log("[+] RSAUtils Hook完成"); } catch(e) {} } // 尝试Hook AESUtils if (!aesHooked) { try { var AESUtils = Java.use("com.xxx.utils.keyboardutil.AESUtils"); console.log("[+] AESUtils 类已加载,开始Hook..."); try { AESUtils.encrypt.overload('java.lang.String', 'java.lang.String').implementation = function(data, key) { console.log("\n================ AESUtils.encrypt ================"); console.log("[随机密钥] " + data); console.log("[用户输入] " + key); var result = this.encrypt(data, key); console.log("[AES密文] " + result); printStackTrace(); console.log("=================================================="); return result; }; } catch(e) {} aesHooked = true; console.log("[+] AESUtils Hook完成"); } catch(e) {} } // 如果还有类未Hook成功,继续尝试 if ((!rsaHooked || !aesHooked) && hookAttempts < maxAttempts) { setTimeout(tryHookTargetClasses, 300); } else if (rsaHooked && aesHooked) { console.log("[*] 所有目标类Hook完成"); } } // 开始尝试Hook setTimeout(tryHookTargetClasses, 1000); console.log("[*] Hook设置完成,请操作APP进行登录");});
30、输出日志与数据包一致
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:挖个洞先 挖个洞先
挖个洞先《【银行逆向百例】16Android逆向之算法助手+frida绕过环境检测分析加密算法》