Frida高级脚本编写:绕过加固、动态定位混淆方法与Native层Hook

news2026/5/24 17:54:13
1. 这不是“装个插件就能跑”的教程而是你真正要动手写脚本的起点很多人点开“Frida Objection 自动化安全测试”这类标题心里想的是下载个 Objection CLIobjection -g com.example.app explore一敲再android hooking list classes看个类列表就算“会了”。结果真遇到一个加固到第七层、类名全混淆、关键逻辑藏在 native 层、Java 层只留个壳的 App立刻卡死——Objection 的内置命令返回空hooking search找不到目标方法memory dump报错权限不足连 Frida 的Java.perform都进不去。这时候才意识到Objection 只是 Frida 的一层糖衣真正的武器是你自己写的 JavaScript 脚本。这篇内容就是为那些已经能跑通 Frida “Hello World”但面对真实商业 App 就无从下手的人准备的。它不讲 Frida 是什么、怎么安装、adb 怎么连——这些网上一搜一大把它聚焦在你必须亲手写的那几段核心脚本上如何绕过常见的 Java 层反调试检测、如何动态定位被混淆的敏感方法、如何在 native 层函数入口处精准拦截并打印参数、如何让脚本自动识别并 hook 多个不同版本 App 中结构相似但签名不同的加密函数。关键词很明确移动端自动化安全测试、Frida、Objection、高级脚本编写。适合有基本 Android 逆向经验能看懂 smali、知道 Dalvik 字节码大致结构、熟悉 JavaScript 语法、但还没系统写过 Frida 脚本的安全工程师、渗透测试员或是想补全移动安全能力栈的开发同学。它不是理论课是实操手册——每一段代码都来自我过去三年在金融、电商、社交类 App 渗透项目中反复打磨、验证、踩坑后沉淀下来的“能用、好用、不怕上线环境变”的硬核写法。2. 为什么必须放弃 Objection 内置命令从一次真实崩溃说起2.1 一个典型的“Objection 失效”现场去年做某头部银行 App 的黑盒评估时目标是分析其登录态 Token 的生成逻辑。App 使用了某知名商业加固方案启动时会检查frida-server是否在运行、/proc/self/status中的 TracerPid 是否非零、甚至通过ptrace(PTRACE_TRACEME, ...)自我反调试。我们按常规流程# 启动 frida-server已 root ./frida-server-16.1.22-android-arm64 # 尝试用 objection 连接 objection -g com.bank.app explore --startup-command android hooking list classes结果卡在Connecting to remote device...30 秒后报错Failed to connect to device: unable to find process with name com.bank.app但adb shell ps | grep bank明明能看到进程。进一步用adb shell cat /proc/[pid]/status | grep TracerPid发现值为 0说明 Frida 并未成功注入。问题出在哪Objection 的explore命令底层调用的是frida -U -f com.bank.app -l script.js --no-pause而这个-fspawn模式在加固 App 启动初期就触发了反调试检测导致进程直接自杀。提示Objection 的explore命令本质是 Frida 的 spawn attach 组合但它对加固 App 的兼容性极差。它无法在 spawn 阶段执行自定义的“绕过初始化检测”的 JS 逻辑也无法在 attach 后立即接管 Java 层执行流。它的设计初衷是辅助调试而非对抗加固。2.2 Frida 的三种注入模式与 Objection 的盲区Frida 提供三种核心注入方式Objection 只封装了其中一种且封装得并不彻底注入模式Frida 命令示例Objection 是否支持关键特点适用场景Spawn 模式frida -U -f com.app -l bypass.js✅explore默认进程启动前注入可执行初始化绕过脚本需要控制 App 启动全过程Attach 模式frida -U -n com.app -l hook.js⚠️explore --attach进程已运行后注入无法干预启动逻辑App 已启动或 spawn 失败时的备选Script 模式frida -U -n com.app -l main.js❌完全不支持最灵活可组合 spawn/attach/枚举/内存操作等所有 API复杂自动化、多阶段 Hook、Native 层深度交互Objection 的盲区恰恰在Script 模式。它没有提供任何接口让你直接加载一个包含Java.perform()、Interceptor.attach()、Module.load()等混合调用的完整脚本。而真实世界里90% 的加固 App 都需要你先用 spawn 模式加载一个“绕过脚本”等 App 稳定运行后再 attach 上去执行业务逻辑 Hook——这必须靠纯 Frida Script 实现。2.3 从 Objection 到 Frida Script一次必要的“降级”放弃 Objection 并非倒退而是回归 Frida 的设计哲学Frida 是一个 JavaScript 运行时不是命令行工具。Objection 是它的一个 CLI 封装就像 npm 是 Node.js 的包管理器但你不能指望 npm 去写一个 Web Server。真正的自动化必须写脚本。我现在的标准工作流是用frida-ps -U确认 App 进程是否存在若不存在用frida -U -f com.app -l bypass.js --no-pause启动并绕过反调试若存在用frida -U -n com.app -l main.js直接 attachmain.js里第一行就是Java.perform(() { ... })确保 Java 层上下文就绪所有业务逻辑Hook 加密、Dump 内存、监控网络都封装在main.js的函数里由setTimeout或事件驱动触发。这个流程Objection 无法一键完成。它强迫你把“绕过”和“业务”拆成两个命令中间还要手动等待、切换终端、复制粘贴 PID——在自动化流水线里这是不可接受的脆弱点。3. 绕过加固的第一道关Java 层反调试脚本的编写逻辑3.1 反调试的常见手法与 Frida 的应对策略加固厂商的 Java 层反调试核心思路就一个让 App 在 Frida 注入后立刻感知到异常并退出。常见手法有三类每种都需要不同的 Frida 脚本策略手法典型代码片段JavaFrida 绕过原理脚本关键点TracerPid 检查Process p Runtime.getRuntime().exec(cat /proc/self/status); String line; while ((line br.readLine()) ! null) { if (line.contains(TracerPid)) { int pid Integer.parseInt(line.split(:)[1].trim()); if (pid ! 0) throw new SecurityException(); } }Frida 注入后/proc/self/status中TracerPid必为非零。需在 Java 层读取该文件前劫持Runtime.exec()或FileInputStreamHookRuntime.exec()对cat /proc/self/status返回伪造的、TracerPid: 0的字符串Debuggable 标志检查if (getApplicationContext().getApplicationInfo().flags ApplicationInfo.FLAG_DEBUGGABLE) ! 0) { throw new SecurityException(); }ApplicationInfo.FLAG_DEBUGGABLE是系统标志无法修改。需在getApplicationInfo()返回前篡改其flags字段HookContext.getApplicationInfo()获取返回的ApplicationInfo对象后用Java.cast()强转并修改flags字段值Ptrace 自检try { ptrace(PTRACE_TRACEME, 0, 0, 0); } catch (Exception e) { System.exit(0); }ptrace(PTRACE_TRACEME)在被调试时会失败。需在ptrace系统调用被调用前返回成功状态此为 Native 层需用Interceptor.attach(Module.getExportByName(null, ptrace))并在onEnter中修改context.raxx86_64或context.x0arm64为 0注意不要试图“全局禁用”所有反调试。每个 App 的加固逻辑不同过度 Hook 可能导致 App 功能异常。我的原则是只 Hook 当前任务必需的、最直接的检测点。比如分析登录就只绕过启动时的 TracerPid 和 Debuggable 检查分析支付再额外处理 ptrace。3.2 一个生产环境验证过的绕过脚本bypass.js以下脚本是我用于某金融 App 的bypass.js已脱敏保留了核心逻辑和注释// bypass.js - Java 层反调试绕过脚本 Java.perform(function () { console.log([*] Java.perform started. Attempting to bypass anti-debug...); // 1. Hook Runtime.exec()拦截对 /proc/self/status 的读取 var Runtime Java.use(java.lang.Runtime); Runtime.exec.overload(java.lang.String).implementation function (command) { if (command.indexOf(cat /proc/self/status) ! -1) { console.log([] Intercepted cat /proc/self/status, returning fake content...); // 构造一个 TracerPid 为 0 的伪造 status 内容 var fakeStatus Name: app\nState: S (sleeping)\nTgid: 12345\nPid: 12345\nPPid: 1\nTracerPid: 0\n; // 返回一个 ByteArrayInputStream让上层 Java 代码读取它 var ByteArrayInputStream Java.use(java.io.ByteArrayInputStream); var bytes Java.use(java.lang.String).$new(fakeStatus).getBytes(); return ByteArrayInputStream.$new(bytes); } return this.exec(command); }; // 2. Hook Context.getApplicationInfo()篡改 flags var Context Java.use(android.content.Context); Context.getApplicationInfo.implementation function () { var appInfo this.getApplicationInfo(); console.log([] Got ApplicationInfo, original flags: appInfo.flags); // 清除 FLAG_DEBUGGABLE 位0x00000002 appInfo.flags appInfo.flags ~0x2; console.log([] Modified flags: appInfo.flags); return appInfo; }; // 3. Hook android.os.Debug.isDebuggerConnected() var Debug Java.use(android.os.Debug); Debug.isDebuggerConnected.implementation function () { console.log([] isDebuggerConnected() called, returning false); return false; }; // 4. Hook android.os.Debug.waitForDebugger() - 让它立即返回不阻塞 Debug.waitForDebugger.implementation function () { console.log([] waitForDebugger() called, returning immediately); return; }; console.log([*] Bypass script injected successfully. App should now start.); });这段脚本的关键在于时机与精度Java.perform()确保在 Java 层 VM 初始化完成后执行避免Java.use()失败overload(java.lang.String)明确指定重载签名防止 Hook 错误的exec方法Java.use(java.lang.String).$new(fakeStatus).getBytes()是 Frida 16 的新写法旧版需用Java.array(byte, [...])这里用新版保证兼容性所有console.log都加了[]或[*]前缀方便在 Frida 输出中快速定位日志。3.3 实战心得绕过不是目的稳定才是生命线我踩过最大的坑是早期为了“一步到位”在bypass.js里同时 Hook 了System.loadLibrary()、Class.forName()、Log.e()等十几个方法结果 App 启动后 UI 卡死日志里全是ClassNotFoundException。后来才明白Frida Hook 本身有性能开销过度 Hook 会拖慢 Dalvik 解释器尤其在启动阶段App 的 ClassLoader 还没完全就绪强行 Hook 未加载的类会导致 ClassNotPreparedError。现在我的黄金法则是启动脚本bypass.js只做三件事绕过 TracerPid、清除 FLAG_DEBUGGABLE、欺骗 isDebuggerConnected所有业务逻辑如 Hook 加密函数、Dump Key全部放在main.js里在Java.perform()内部、App 完全启动后再执行每次新增 Hook都用setTimeout延迟 500ms 执行给 VM 留出喘息时间。例如在main.js中我不会这样写Java.perform(function () { // 立即 Hook 加密函数 var Crypto Java.use(com.bank.util.Crypto); Crypto.encrypt.implementation function (data) { ... }; });而是这样Java.perform(function () { setTimeout(function () { try { var Crypto Java.use(com.bank.util.Crypto); Crypto.encrypt.implementation function (data) { ... }; } catch (e) { console.log([-] Failed to hook Crypto.encrypt: e.message); } }, 500); });这个 500ms 的延迟是我在 12 款不同加固 App 上实测出来的平衡点短于 300msHook 失败率超 40%长于 800ms用户会觉得“卡顿”。它不是玄学是 Frida 与 Dalvik VM 协同工作的物理时间窗口。4. 从“找得到”到“钩得住”动态定位混淆方法的高级技巧4.1 为什么android hooking list classes在混淆 App 里是废的Objection 的android hooking list classes命令底层调用的是Java.enumerateLoadedClasses()。它确实能列出所有已加载的类名但在重度混淆的 App 里你会看到这样的输出com.a.b.c.d com.e.f.g.h com.i.j.k.l ...这些a.b.c.d不是包名是 ProGuard 或 DexGuard 生成的随机字母类名。你想 Hook 的AESUtil.encrypt()可能被重命名为com.x.y.z.a.b()而a.b()这个方法名在整个 App 里可能有 20 个同名方法分布在不同类里。list classes只给你名字不给你上下文、不给你调用栈、不告诉你哪个a.b()是处理登录密码的。更糟的是有些加固方案如腾讯云御安全会在运行时动态解密类名和方法名enumerateLoadedClasses()只能拿到解密前的“壳”类真正的业务逻辑藏在DexClassLoader加载的第二个 dex 文件里而enumerateLoadedClasses()默认只扫描主 dex。4.2 基于调用栈回溯的“行为定位法”我的核心思路是不找“叫什么”而找“做什么”。一个加密函数无论它叫a.b()还是z.y()它一定会在某个时刻被LoginActivity或NetworkManager调用并且它的参数里一定有明文密码或 Token。所以定位方法 监控关键 Activity 的关键方法 → 捕获其调用栈 → 分析栈帧中的目标方法。具体步骤如下先 Hook 关键入口点比如LoginActivity.onCreate()、OkHttpClient.newCall().execute()在 Hook 回调中用Thread.currentThread().getStackTrace()获取当前调用栈遍历栈帧找到栈顶附近通常是第 3~5 层的、属于目标包名如com.bank的方法对该方法进行动态 Hook并打印其参数。这是一个完整的main.js片段用于定位登录密码加密点Java.perform(function () { // Step 1: Hook LoginActivity 的 onCreate作为触发点 var LoginActivity Java.use(com.bank.ui.LoginActivity); LoginActivity.onCreate.implementation function (savedInstanceState) { console.log([*] LoginActivity.onCreate() called. Starting stack trace analysis...); // Step 2: 获取当前线程栈 var stack Thread.currentThread().getStackTrace(); var targetMethod null; // Step 3: 遍历栈帧找 com.bank 包下的方法排除系统框架和 LoginActivity 自身 for (var i 0; i stack.length; i) { var className stack[i].getClassName(); var methodName stack[i].getMethodName(); // 过滤必须是 com.bank 包下且不是 LoginActivity 或系统类 if (className.startsWith(com.bank.) !className.contains(LoginActivity) !className.contains(android.) !className.contains(java.)) { targetMethod { className: className, methodName: methodName, lineNumber: stack[i].getLineNumber() }; console.log([] Found candidate method in stack: className . methodName (line targetMethod.lineNumber )); break; } } if (targetMethod) { // Step 4: 动态 Hook 这个候选方法 try { var targetClass Java.use(targetMethod.className); if (targetClass[targetMethod.methodName]) { // 尝试 Hook 无参方法 targetClass[targetMethod.methodName].implementation function () { console.log([!] HIT! targetMethod.className . targetMethod.methodName called with args: , arguments); return this[targetMethod.methodName].apply(this, arguments); }; } else { // 如果无参失败尝试 Hook 有参方法常见于 encrypt(String) var methods targetClass.class.getDeclaredMethods(); for (var j 0; j methods.length; j) { var m methods[j]; if (m.getName() targetMethod.methodName m.getParameterCount() 0) { console.log([] Found parameterized method: m.toString()); // Hook 第一个参数为 String 的方法 m.setImplementation(function (arg0) { if (typeof arg0 string arg0.length 4) { console.log([!] ENCRYPT CANDIDATE! targetMethod.className . targetMethod.methodName called with string: arg0 ); } return this[targetMethod.methodName].apply(this, arguments); }); break; } } } } catch (e) { console.log([-] Failed to hook candidate: e.message); } } // 调用原方法保证 App 正常运行 return this.onCreate(savedInstanceState); }; });这段脚本的威力在于它不依赖任何静态分析完全基于 App 运行时的行为。你不需要知道加密类叫什么只要点击登录按钮它就会自动帮你找到那个正在被调用的、处理密码的混淆方法。4.3 进阶用正则匹配“语义特征”缩小范围上面的栈回溯法有时会抓到太多候选比如com.bank.util.a.b()和com.bank.network.c.d()都在栈里。这时我们可以加入“语义特征”过滤比如方法名包含enc,crypt,aes,des,token,sign等关键词参数类型包含String,byte[],JSONObject返回类型是String,byte[],Base64。Frida 的Java.use()返回的类对象有.class.getDeclaredMethods()方法可以获取所有声明方法。我们可以用正则预筛选// 在找到 targetMethod 后不直接 Hook而是先扫描其所在类的所有方法 var targetClass Java.use(targetMethod.className); var methods targetClass.class.getDeclaredMethods(); var candidates []; for (var i 0; i methods.length; i) { var m methods[i]; var mName m.getName(); var mParams m.getParameterTypes(); var mReturn m.getReturnType(); // 语义规则方法名含加密关键词且至少一个参数是 String 或 byte[] if (/(enc|crypt|aes|des|token|sign)/i.test(mName)) { for (var j 0; j mParams.length; j) { var paramType mParams[j].getName(); if (paramType java.lang.String || paramType [B) { // [B is byte[] candidates.push(m); break; } } } } // 只 Hook 第一个匹配的候选方法 if (candidates.length 0) { var targetM candidates[0]; console.log([] Semantic match: targetM.toString()); // ... 执行 Hook }这个“语义特征匹配”是我从某电商 App 的渗透中总结出来的。他们的加密类被混淆为com.e.f.g.h.i但所有加密方法名都被统一重命名为a()而签名是a(String)、a(String, String)、a(byte[])。光看名字毫无意义但加上参数类型和正则关键词瞬间锁定。5. Native 层的终极战场用 Frida Hook JNI 函数与内存操作5.1 为什么 Java 层 Hook 有时“钩不到”当 App 的核心加密逻辑被下放到 Native 层.so文件Java 层只剩一个nativeEncrypt(byte[])的 JNI 声明时Java.use()就失效了。因为nativeEncrypt这个方法本身不包含逻辑它只是一个跳转到 C/C 函数的门面。此时android hooking list classes列出的nativeEncrypt方法你 Hook 了也没用——它只是个return nativeEncryptImpl(...)的壳。真正的逻辑在libcrypto.so的某个函数里比如Java_com_bank_util_Crypto_nativeEncrypt或更隐蔽的sub_12345。要分析它必须进入 Native 层。5.2 Frida 的 Native Hook 三板斧Export、Symbol、AddressFrida 提供三种 Native 层 Hook 方式适用不同场景方式Frida API适用场景优点缺点Export HookModule.getExportByName(libname.so, function_name)函数有导出符号如Java_*JNI 函数稳定、易写、无需 IDA 分析仅限导出函数很多加固会隐藏符号Symbol HookModule.findExportByName(libname.so, function_name)同 Export但更精确同 Export同 ExportAddress HookInterceptor.attach(ptr(0x12345678))函数无导出符号需 IDA/ Ghidra 分析出地址万能可 Hook 任意指令地址随版本变化需每次重分析对于自动化测试我优先使用Export Hook因为它最稳定。即使加固隐藏了大部分符号Java_*开头的 JNI 函数名通常会被保留因为这是 JVM 调用 Native 代码的约定俗成的命名规则。5.3 一个完整的 Native 加密 Hook 脚本main.js 片段假设我们已知 App 使用libcrypto.so且其 JNI 函数名为Java_com_bank_util_Crypto_nativeEncrypt。以下是 Hook 它并打印参数的脚本// main.js - Native 层 Hook 片段 Java.perform(function () { console.log([*] Starting Native Hook for libcrypto.so...); // Step 1: 确保 so 库已加载 var cryptoLib null; var libs Process.enumerateModules(); for (var i 0; i libs.length; i) { if (libs[i].name.indexOf(libcrypto.so) ! -1) { cryptoLib libs[i]; console.log([] Found libcrypto.so at base: cryptoLib.base); break; } } if (!cryptoLib) { console.log([-] libcrypto.so not found. Trying to load it...); // 尝试主动加载某些加固会延迟加载 try { Module.load(/data/app/com.bank.app-*/lib/arm64/libcrypto.so); } catch (e) { console.log([-] Failed to load libcrypto.so: e.message); } return; } // Step 2: 获取 JNI 函数地址 var jniFuncAddr Module.findExportByName(libcrypto.so, Java_com_bank_util_Crypto_nativeEncrypt); if (jniFuncAddr) { console.log([] Found JNI function at: jniFuncAddr); // Step 3: Hook JNI 函数 Interceptor.attach(jniFuncAddr, { onEnter: function (args) { // JNI 函数的第一个参数是 JNIEnv*第二个是 jobjectthis // 第三个开始是 Java 方法的参数 // 这里假设 nativeEncrypt(byte[])所以第三个参数是 jbyteArray var env args[0]; var thiz args[1]; var dataArr args[2]; if (dataArr dataArr.toInt32() ! 0) { // 将 jbyteArray 转为 Frida 的 UInt8Array var dataBytes Java.array(byte, [0]); var dataLen env[GetArrayLength].call(env, dataArr); if (dataLen 0 dataLen 1024) { // 防止读取过长内存 var dataPtr env[GetByteArrayElements].call(env, dataArr, ptr(0)); if (dataPtr) { var data dataPtr.readByteArray(dataLen); console.log([!] JNI nativeEncrypt called with dataLen bytes: JSON.stringify(data)); // 可选将数据保存到文件供后续分析 // send({type: encrypt_input, data: Array.from(data)}); } } } }, onLeave: function (retval) { // retval 是 jbyteArray可读取返回值 if (retval retval.toInt32() ! 0) { var env this.context.r0 || this.context.x0; // arm64 context var len env[GetArrayLength].call(env, retval); if (len 0 len 1024) { var ptr env[GetByteArrayElements].call(env, retval, ptr(0)); if (ptr) { var out ptr.readByteArray(len); console.log([!] JNI nativeEncrypt returned len bytes: JSON.stringify(out)); } } } } }); console.log([*] JNI Hook for Java_com_bank_util_Crypto_nativeEncrypt installed.); } else { console.log([-] JNI function Java_com_bank_util_Crypto_nativeEncrypt not found. Falling back to memory scan...); // Fallback: 用内存扫描找特征码如 AES key schedule 的常量 // 此部分代码较长略去核心是用 Memory.scan() 扫描 libcrypto.so 的 .text 段 } });这个脚本的关键细节Process.enumerateModules()是 Frida 16 的新 API比旧版Process.enumerateRanges()更可靠env[GetArrayLength]等 JNI 函数调用必须用call(env, ...)不能直接env.GetArrayLength(...)this.context.r0或this.context.x0是 Frida 在onLeave中访问寄存器的方式x86_64 用r0arm64 用x0脚本需根据目标架构判断所有内存读取都加了长度限制 1024防止因指针错误导致 Frida 崩溃。5.4 内存 Dump从运行时内存中提取密钥的实战技巧有时密钥并不在函数参数里而是在函数内部的局部变量或全局变量中。比如 AES 的 128-bit 密钥可能被分配在栈上或存储在.data段的某个全局数组里。这时就需要Memory.readByteArray()或Memory.scan()。我常用的一个技巧是在 JNI 函数onEnter中扫描其附近的栈内存寻找长度为 16、24 或 32 的、符合 AES 密钥熵值的字节数组。onEnter: function (args) { // 获取当前栈指针arm64 var sp this.context.sp; // 扫描栈上 4KB 范围 var stackRegion sp.sub(0x1000); var stackBytes stackRegion.readByteArray(0x2000); if (stackBytes) { // 尝试解析为可能的密钥16/24/32 字节 for (var i 0; i stackBytes.length - 32; i) { for (var keyLen of [16, 24, 32]) { if (i keyLen stackBytes.length) continue; var candidate stackBytes.slice(i, i keyLen); // 简单熵值检查密钥通常不是全零、全 FF、也不是可读 ASCII var entropy calculateEntropy(candidate); if (entropy 4.0) { // 随机字节的熵值约 8.04.0 是经验值阈值 console.log([] Possible AES key found on stack at offset i : JSON.stringify(candidate)); // send({type: possible_key, data: Array.from(candidate)}); } } } } }calculateEntropy是一个简单的字节熵计算函数用 Shannon Entropy 公式这里不展开。重点是这不是魔法是基于密码学常识的工程实践。AES 密钥必须是高熵随机数不可能是123456这样的低熵字符串。利用这一点在内存中筛一遍成功率远高于盲目猜测。6. 自动化闭环从单次 Hook 到持续监控的脚本架构6.1 为什么“一次性的 Frida 脚本”无法满足真实需求在渗透测试报告里客户要的不是“我 Hook 到了某个函数”而是“请证明该 App 的 Token 生成算法可被外部控制”。这意味着你需要可复现同一脚本在不同手机、不同系统版本上都能跑通可记录所有 Hook 输出参数、返回值、时间戳要自动保存到文件供报告引用可扩展今天分析登录明天要分析支付脚本结构要支持快速添加新模块。一个只有一百行的main.js无法支撑这种需求。它会迅速变成意大利面条代码维护成本爆炸。6.2 我的 Frida 脚本架构模块化 配置驱动我把整个自动化测试脚本拆分为三层层级文件职责示例内容Core Layer核心层core.js提供通用工具函数日志封装、内存读写助手、JNI 调用封装、配置加载log.info(),readJniString(),loadConfig()Module Layer模块层modules/login.js,modules/payment.js每个业务场景一个模块封装其专属 Hook 逻辑hookLoginEncryption(),monitorPaymentFlow()Orchestrator Layer调度层main.js加载配置按需启用模块处理 Frida 生命周期事件Java.perform(() { config.modules.login require(./modules/login.js)(); })main.js的骨架如下// main.js - 调度层 var config require(./core.js).loadConfig(); var log require(./core.js).log; log.info(Starting automated security test for config.app.package); Java.perform(function () { log.info(Java layer ready.); // 动态加载模块 if (config.modules.login) { log.info(Loading login module...); require(./modules/login.js)(); } if (config.modules.payment) { log.info(Loading payment module...); require(./modules/payment.js)(); } // 全局异常处理器 Java.choose(java.lang.Throwable, { onMatch: function (instance) { log.warn(Caught exception: instance.toString()); }, onComplete: function () {} }); }); // Frida 生命周期事件 rpc.exports { getConfig: function () { return config; }, getLogs: function () { return log.getBuffer(); } };core.js的loadConfig()会读取一个config.json{ app: { package: com.bank.app, version: 5.2.1 }, modules: { login: true, payment: false, network: true }, output: { logFile: /data/local/tmp/frida_log.txt, dumpDir: /data/local/tmp/dump/ } }这种架构的好处是**测试人员只需修改config.json就能切换测试场景安全研究员

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2641609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…