当前位置: 首页 > article >正文

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

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就能切换测试场景安全研究员

相关文章:

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

1. 这不是“装个插件就能跑”的教程,而是你真正要动手写脚本的起点很多人点开“Frida Objection 自动化安全测试”这类标题,心里想的是:下载个 Objection CLI,objection -g com.example.app explore一敲,再android ho…...

ThinkPHP 5.x远程代码执行漏洞(CVE-2018-1002015)深度解析与实战防御

1. 这个漏洞不是“理论存在”,而是真实打穿过生产环境的子弹ThinkPHP 5.x远程代码执行漏洞(CVE-2018-1002015)在2018年3月被公开时,很多团队第一反应是“又一个框架RCE”,随手打个补丁就扔进待办清单底部。我见过最典型…...

TPS不是数字而是手术刀:JMeter性能诊断核心原理

1. 为什么TPS不是“点一下就出来的数字”,而是一把性能诊断的手术刀很多人第一次用JMeter跑完脚本,盯着监听器里跳出来的“TPS:42.3”发呆——这数字到底准不准?它和我写的接口响应时间有什么关系?为什么加了10个线程&…...

管理企业多项目API Key与访问权限的最佳实践

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 管理企业多项目API Key与访问权限的最佳实践 在企业或团队中引入大模型能力时,一个常见的挑战是如何安全、高效地管理多…...

C#实现与欧姆龙PLC通信的示例代码

C#实现与欧姆龙PLC通信,整合了FINS-TCP协议实现和主流开发框架: 一、通信方案选型对比 协议类型适用场景开发复杂度推荐库FINS-TCP欧姆龙设备专用通信中等HslCommunicationModbus TCP多品牌设备通用通信高NModbus4OPC UA跨平台工业物联网集成高OPC Foun…...

基于C#实现的支持五笔和拼音输入的输入法

一、核心架构设计 二、关键代码实现 1. 输入法核心类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72…...

企业内统一AI开发环境借助TaotokenCLI工具一键配置

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 企业内统一AI开发环境借助Taotoken CLI工具一键配置 在中大型企业的技术团队中,为所有开发者提供统一、标准化的AI服务…...

Python HTTPS请求SSL证书验证失败排查指南

1. 这不是requests的bug,是TLS握手失败在敲门你刚写完一行requests.get("https://api.example.com"),回车一按,终端却甩出一长串红色报错:HTTPSConnectionPool(hostapi.example.com, port443): Max retries exceeded wi…...

2026年阿里云OpenClaw/Hermes Agent配置Token Plan部署保姆级

2026年阿里云OpenClaw/Hermes Agent配置Token Plan部署保姆级。OpenClaw是开源的个人AI助手,Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流 AI 工具&am…...

为团队统一开发环境使用Taotoken CLI一键配置所有成员的API密钥

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 为团队统一开发环境使用Taotoken CLI一键配置所有成员的API密钥 当团队协作参与项目或比赛时,统一API接入配置能提升效…...

RuoYi登录接口自动化:验证码、AES加密与JWT全链路验证

1. 为什么登录接口自动化不是“点几下就完事”,而是RuoYi项目落地的第一道生死线在接手第7个基于RuoYi-Vue的政企内部系统交付时,我遇到过最尴尬的一幕:客户现场验收当天,测试同事用Postman手工执行登录接口,输入账号密…...

DeepSeek隐私保护能力首次第三方穿透测试报告(CNAS认证机构出具,仅限本期披露3项核心缺陷)

更多请点击: https://intelliparadigm.com 第一章:DeepSeek数据隐私保护能力概览 DeepSeek系列大模型在设计与部署阶段即深度融入隐私优先(Privacy-by-Design)原则,其数据处理机制严格遵循最小化采集、本地化计算、端…...

通过Taotoken用量看板与账单追溯功能实现团队成本精细化管理

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过Taotoken用量看板与账单追溯功能实现团队成本精细化管理 对于技术团队的管理者而言,在引入大模型能力支持业务创新…...

零起点Python机器学习快速入门【1.1】

1.4 机器学习经典案例目前人工智能、机器学习正处于黄金时期,各种应用随处可见,以下是一些常见的机器学习应用案例。 机器人客服:当你拨打移动、银行等公司的服务热线时,大部分都是通过人工智能技术合成的电脑客服在和你沟通&am…...

电力负荷预测挑战:Informer2020如何实现长序列时间序列预测的完整解决方案

电力负荷预测挑战:Informer2020如何实现长序列时间序列预测的完整解决方案 【免费下载链接】Informer2020 The GitHub repository for the paper "Informer" accepted by AAAI 2021. 项目地址: https://gitcode.com/gh_mirrors/in/Informer2020 在…...

CTSD算法超参数调优实战:从原理到应用,解决机器翻译重复与幻觉问题

1. 项目概述:当机器翻译开始“复读”,我们如何用CTSD算法精准调校?在机器翻译的实际部署和优化中,一个让工程师和研究者都颇为头疼的问题是:模型有时会像卡住的唱片一样,反复输出相同的词或短语。这种现象&…...

零起点Python机器学习快速入门【1.0】

第 1 章 从阿尔法狗开始说起1.1 阿尔法狗的前世今生百度百科的“阿尔法狗”词条是:阿尔法狗( AlphaGo)是一款围棋人工智能程序,由谷歌( Google)旗下 DeepMind 公司的戴密斯哈萨比斯、大卫席尔瓦、黄士杰与他…...

Android应用架构规范深度解析与面试指南

引言 在Android应用开发中,架构设计是确保应用可维护性、可扩展性和稳定性的核心要素。随着移动应用的复杂度日益增加,采用规范的架构模式不仅能提升开发效率,还能减少错误和重构成本。本文将以“架构规范”为核心重点领域,深入探讨Android应用的主流架构模式、实现细节、…...

Taotoken官方价折扣与Token Plan套餐的实际节省效果分析

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken官方价折扣与Token Plan套餐的实际节省效果分析 1. 引言 在接入和使用大模型API时,成本是开发者与团队持续关…...

深入掌握Android响应式编程:RxJava与Kotlin Coroutines+Flow实战指南

目录 响应式编程范式解析 RxJava核心架构剖析 操作符系统深度应用 多线程调度实战策略 Kotlin协程基础重构 Flow异步流处理机制 StateFlow与SharedFlow应用场景 响应式测试方法论 复杂状态管理实战 性能优化与异常处理 技术选型对比指南 面试题库精粹 第一章 响应式编程范式解析…...

体验 Taotoken 官方价折扣与快速接入带来的开发提速

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 体验 Taotoken 官方价折扣与快速接入带来的开发提速 启动一个新的 AI 项目时,开发者往往面临两个最直接的问题&#xf…...

Taotoken 平台在应对突发流量时 API 路由与容灾的实际表现观察

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken 平台在应对突发流量时 API 路由与容灾的实际表现观察 1. 背景与场景 近期,我们团队负责的一款应用进行了产品…...

DeepSeek负载均衡失效导致LLM响应延迟飙升300%?紧急回滚+根因分析全流程复盘(含Wireshark抓包关键证据)

更多请点击: https://kaifayun.com 第一章:DeepSeek负载均衡方案 DeepSeek大模型服务在高并发推理场景下,需依托稳定、低延迟、可扩展的负载均衡架构保障SLA。本方案基于四层(TCP/SSL)与七层(HTTP/HTTPS&a…...

限流策略失效导致服务雪崩?DeepSeek v3.2+最新RateLimiter配置参数详解,含12个关键字段压测对比数据

更多请点击: https://kaifayun.com 第一章:限流策略失效导致服务雪崩?DeepSeek v3.2最新RateLimiter配置参数详解,含12个关键字段压测对比数据 在高并发微服务场景中,RateLimiter 配置不当是引发级联失败与服务雪崩的…...

如何彻底解锁你的加密音乐:终极免费浏览器解决方案

如何彻底解锁你的加密音乐:终极免费浏览器解决方案 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: https://…...

DeepSeek长上下文延迟飙升预警:GPU显存碎片率>68%时的实时context重分片算法(已集成至v3.2.1热补丁)

更多请点击: https://codechina.net 第一章:DeepSeek长上下文处理 DeepSeek系列模型(如DeepSeek-V2、DeepSeek-Coder、DeepSeek-MoE)原生支持长达128K tokens的上下文窗口,显著超越传统Transformer架构在长文本建模中…...

为什么92%的DeepSeek部署失败?揭秘量化校准中被忽略的3个KL散度阈值临界点

更多请点击: https://intelliparadigm.com 第一章:为什么92%的DeepSeek部署失败?揭秘量化校准中被忽略的3个KL散度阈值临界点 在真实生产环境中,DeepSeek-R1/Distill系列模型的INT4量化部署失败率高达92%,核心症结并非…...

植物大战僵尸修改器终极指南:如何快速掌握PvZ Toolkit提升游戏体验

植物大战僵尸修改器终极指南:如何快速掌握PvZ Toolkit提升游戏体验 【免费下载链接】pvztoolkit 植物大战僵尸 PC 版综合修改器 项目地址: https://gitcode.com/gh_mirrors/pv/pvztoolkit 你是否在玩植物大战僵尸时遇到过阳光不够用、金币积累太慢的烦恼&…...

【Gemini商业价值护城河构建指南】:用4维动态估值法锁定长期LTV,错过Q3将丧失成本优化黄金窗口

更多请点击: https://kaifayun.com 第一章:Gemini生命周期价值分析 Gemini模型的生命周期价值(LTV)不仅体现在其推理性能与多模态能力上,更贯穿于部署、迭代、监控与成本优化的全链路环节。相较于传统大模型&#xff…...

提示词工程师正在消失?不,是升级为“AI交互架构师”——掌握这4类元提示设计能力的人已溢价2.8倍

更多请点击: https://intelliparadigm.com 第一章:提示词工程的范式迁移与角色升维 传统提示词设计常被视作“指令微调”或“模板填充”的辅助技巧,而大模型能力边界持续拓展正推动其向系统性工程范式跃迁。提示词不再仅是输入层的语法糖&am…...