ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

逆向工程实战指南:从安卓App到JS小程序的通用方法论

逆向工程实战指南:从安卓App到JS小程序的通用方法论 最近群里的技术话题几乎被“逆向”两个字包场了。我刷了一圈社区热词安卓逆向、JS逆向、小程序逆向、CTF逆向、爬虫逆向全在榜上还有不少指名道姓的需求比如“某银行App绑企逆向”“抖音JS爬虫逆向”“i茅台逆向”。名字五花八门内核却高度一致都是在没有官方接口文档的前提下通过静态分析和动态调试把程序的整体行为、通信协议和核心算法一点点还原出来。我自己更愿意把这套跨平台、跨语言的通用方法论叫做“技术逆向英语”。因为一旦掌握了这套思路不管你今天面对的是安卓APK、微信小程序、网页加密参数还是一个Windows下的EXE都能用同一套“读代码、找入口、Hook调用、还原算法”的流程去解决。这篇文章不打算列工具清单就草草收场而是把当前热度最高的几类逆向场景从思路到动手、从踩坑到出活儿完整过一遍。适合刚入门的朋友也适合那种“工具装了一堆看到程序却不知道第一刀该往哪切”的开发者。1. 逆向工程当前在玩什么五大高频方向先别急着上手跑脚本。你只有搞清楚每个热词背后到底是什么问题才能选对学习路线和技术栈。1.1 移动App逆向安卓仍是主战场安卓逆向是热度最高、资料最多、学习曲线最平滑的入口。原因很简单APK本质是zip压缩包反编译难度远低于iOS闭源体系。像i茅台这类预约抢购类App、某银行App绑企流程、各种IoT设备的安卓控制端都会被人拿去分析接口、签名、加密参数。真正需要逆向的人其实分两类。一类是做安全测试、漏洞挖掘的需要通过逆向发现逻辑漏洞另一类是搞自动化脚本或爬虫的想绕过App端的前端校验去直接调用后端接口。前者是合规的后者则必须拿到授权。我的建议很明确在学习和练习阶段一律使用自有App、开源项目或CTF靶场不碰真实金融、政务、商业系统。1.2 Web/JS逆向与爬虫系参数加密是核心热搜里的“百度翻译逆向”“抖音JS爬虫逆向”“腾讯天御验证码逆向”“DataDome逆向”“Akamai逆向”本质都归到Web逆向。Web页面跑在浏览器里所有JS代码都会被浏览器执行这就给了逆向一个天然窗口只要你有办法让JS在本地环境跑起来就能观察它对输入做了什么变换。Web逆向最核心的两个难题是混淆和环境检测。混淆让代码读起来像天书环境检测让脚本离开浏览器后立刻变形甚至报错。所以你看各种逆向教程都在讲AST还原、补环境、Hook加密函数本质上都是在跟这两件事斗争。1.3 小程序逆向包体更小但同样热门微信小程序、支付宝小程序这两年逆向需求猛增。小程序和普通Web不一样它的代码会被打包成wxapkg这样的二进制包主包和分包还会加密。但小程序又要依赖宿主App运行很多API参数最后还是要走JS逻辑。这意味着只要能把包解开、代码还原后面就进入JS逆向的老套路。热度高还有一个现实原因很多企业App的功能被搬进了小程序小程序的防护往往比原生App弱于是成了轻量级的安全突破口。但同样要强调未经授权分析他人生产经营系统在法律上是有风险的。1.4 CTF逆向最安全也最系统的训练场热搜里有“BUUCTF reverse3”“traceme.exe逆向分析”“2026平航杯手机逆向包”“逆向靶场v14下载”这些其实都是CTFCapture The Flag比赛里的Reverse方向题。CTF逆向是多好的东西它给你提供了合法、有趣、难度递进的靶子。很多非安全行业的同学觉得逆向和自己无关其实CTF逆向对软件工程师、算法工程师都很有价值。它能逼你去看编译器生成的汇编、搞清内存布局、理解程序在不同平台下的运行差异这些都是日常业务开发很难接触到的。1.5 风控对抗类方向对但别越界现在有些逆向项目已经超出了“还原算法”的范畴比如借逆向来绕过滑块验证码、设备指纹、行为风控。这类技术确实存在但它的合法边界非常模糊。你去分析自己的系统没问题去分析别人的风控然后写绕过脚本就可能涉及破坏计算机信息系统。所以我在这篇文章里只讲方法和防御思路不提供任何针对线上真实服务的绕过步骤。2. 通用底座工具链、运行环境与三个最小闭环先把底子打好。不管你是逆向App还是逆向Web下面这三件事你迟早都要面对静态分析、动态Hook、流量抓包。2.1 静态分析三件套我日常用得最多的静态工具是这些目标场景工具用途安卓APK反编译jadx把DEX转成Java代码直接看业务逻辑安卓资源/清单解析apktool解包、回编译、查看Manifest与资源跨平台二进制反汇编Ghidra分析SO库、ELF、Windows PE开源免费Windows程序深度逆向IDA Pro/免费版伪代码还原、函数流程分析、补丁对比JS代码格式化/反混淆Browser DevTools AST工具库还原压缩和混淆后的脚本很多新手上来就装全家桶其实没必要。CLI工具加一个图形反编译器就够了关键是会用。比如遇到一个安卓App你第一件事不是开Frida而是先用jadx把APK拖进去看包结构、Activity、关键字符串确定代码入口。静态分析解决的是“代码在哪、逻辑是什么”动态Hook解决的是“运行时这个函数到底吃了什么、吐了什么”。2.2 动态调试与Hook通用基底动态这块Frida是我目前唯一不换的组合拳。原因在于它支持Java层和Native层Hook还能注入到iOS、Windows、Linux设备上。配合objection很多时候连脚本都不用写直接命令行看当前Activity、枚举类、脱壳、绕过root检测。如果你主攻Windows程序那x64dbg是必备。对CTF选手来说x64dbg看汇编、下断点、分析程序是自己写的加密还是调用了系统API比Ghidra更直观。大部分时候我们是“静态看架构、动态验细节”两个配合着来。2.3 抓包工具流量即真相抓包是逆向里最容易被人忽视却最出效果的一步。Charles和mitmproxy我都在用。Charles适合图形界面看https明文流量mitmproxy适合写脚本做自动化。抓包最恶心的坑是HTTPS证书和SSL Pinning。所谓SSL Pinning就是App在代码里固定了服务端证书指纹不信任系统CA。你给手机装了Charles根证书没用App直接不认。解决办法是先把App的证书校验函数找到通过Hook禁用或绕过校验。这部分内容建议在自有测试环境里操作线上服务千万不要乱试。2.4 所有逆向通用的三个最小闭环我把自己的日常工作流程总结成三个闭环希望大家一开始就按这个节奏练习静态定位闭环拿到目标先通过关键词搜代码锁定可疑函数和调用位置。哪怕找不到精确位置也要把链路断在“某个加密函数”。动态验证闭环用Frida或调试器对目标函数下Hook输出参数和返回值确认它是否真的在运行时被调用以及输入输出是否符合预期。协议复现闭环把函数输出和抓包数据对照起来在本地脚本里用同样的算法生成合法请求跑通一遍后就算“逆向成功”。这三个闭环覆盖了App逆向、小程序逆向和JS逆向百分之八十的场景。3. 安卓App逆向破局的完整路径拆包、静态定位、动态验证下面用一个仿真实战流程走一遍。假设我手里有一个自建测试App包名是com.example.demo需要还原它的登录接口加密逻辑。3.1 信息收集拆包看骨架先跑一遍命令拿到基础信息apktool d demo.apk -o demo_src jadx -d demo_java demo.apkapktool解包后先去AndroidManifest.xml看权限、入口Activity、有没有应用加固。很多App在Application类里做初始化你看到com.stub.StubApp这种类名基本就是有加固壳了。加固后的DEX是加密的jadx直接打开只会看到壳的代码真正的业务逻辑要到运行时才释放。这时候信息收集要更近一步看assets目录下有没有加密的dex文件、lib目录下有没有so库、Application类里做了什么反射和校验。常见的免费壳通过frida-dexdump就能从内存中dump出原始DEX然后拖回jadx里继续分析。3.2 静态定位用关键词缩小搜索范围在jadx里搜关键字是最快的方法。我一般先搜和网络相关的关键词接口路径api/、login、auth、user加密算法AES、DES、RSA、MD5、HmacSHA256签名验签sign、signature、verify客户端标识deviceId、uuid、token比如这个Demo App搜索sign会看到一个叫SignUtils的类里面有个静态方法getSign(MapString, String params)。点开一看它把参数按键值排序拼成字符串再拼接一个固定的盐值最后做MD5。这一步很基础但你已经找到了算法位置。3.3 动态Hook确认函数确实走的是这条路静态分析有个致命问题静态代码可能是迷惑你的死代码根本不会被调用。所以必须动态验证。用Frida写个脚本Hook住这个SignUtils.getSignJava.perform(function () { var SignUtils Java.use(com.example.demo.utils.SignUtils); SignUtils.getSign.overload(java.util.Map).implementation function (params) { console.log(params params.toString()); var result this.getSign(params); console.log(result result); return result; }; });启动测试App手动登录一次Frida控制台会打印出参数和签名结果。如果你发现参数里有时间戳、随机数那就要多触发几次观察哪些参数会变化哪些是固定值。这一步能直接验证你在jadx里看代码的猜想到底对不对。3.4 签名校验与本地调试的坑调试重打包后的App时最常见的就是签名校验。App在启动时会检查自身的签名是否和官方一致不一致就退出。要在本地测试环境里调过它核心思路是找到校验签名的方法要么把返回值改成true要么通过Hook跳过整个校验函数。var signatureCheck Java.use(com.example.demo.Security.CheckUtil); signatureCheck.checkSign.implementation function () { return true; };这句脚本在授权测试里很好用但注意这只能用于你自己的App或CTF靶机。试图绕过别人App的签名校验再做二次打包属于明确的攻击行为。3.5 从离奇到协议还原拿到加密函数和参数后最后一步是把算法搬出App用Python或Node重新实现一遍。以MD5为例import hashlib import time def generate_sign(params: dict, salt: str) - str: sorted_str .join(f{k}{v} for k, v in sorted(params.items())) raw sorted_str salt return hashlib.md5(raw.encode()).hexdigest()然后用requests模拟一次请求如果服务端返回正常数据整个链路就算打通了。你可能会问为什么不直接抓包复制请求还要费劲还原算法因为token、sign这类参数通常有有效期甚至一次一换只有真正复现算法才能持续生成合法请求。4. JS逆向实战拆解从Hook到补环境JS逆向常见于爬虫和Web测试。它的难度很极端简单的十几分钟解决复杂的能把人熬到下半夜。但方法论是固定的。4.1 定位加密函数从请求参数反推打开浏览器开发者工具在Network面板里找到一个需要破解的接口观察请求参数。一般就有类似sign、_signature、token这样的字段。在Sources面板里搜索这些字段名搜索结果会指向一个JS文件。如果文件巨大并且是混淆过的一行代码先做格式化。然后根据文件名、函数名、字符串提示找到可能生成该参数的函数。在需要调试的关键函数位置打断点重新触发一次请求就能看到参数进来的原始值。顺着调用栈往上翻可以找到参数的来源和变换过程。比如函数A调用了函数B函数B返回了一个拼接加密串那B就是把加密逻辑所在地。4.2 Hook浏览器里的JS函数习惯了Frida之后你会发现浏览器里的Hook其实更简单。直接在Console里重写对象方法const originalEncrypt window.encryptFn; window.encryptFn function(input) { console.log(encrypt input:, input); const result originalEncrypt(input); console.log(encrypt result:, result); return result; }这一步可以把原本黑盒的加密运算过程变成白盒你不需要读懂混淆代码只需要知道“输入是什么输出是什么”。然后本地用同样的逻辑试算比对结果。4.3 反混淆AST是终极武器当混淆程度很高时光靠打断点效率太低得靠程序对付程序。JavaScript的AST抽象语法树工具比如Babel、babel/parser、escodegen可以把混淆代码解出可读的中间状态。常见混淆手段有字符串解密、控制流平坦化、死代码注入。对应解法也很成熟编写Babel插件将解密函数调用替换成常量把whileswitch结构改回if-else删除干扰分支。这些前置工作做完原本几千行的乱码可能变成几百行正常代码。4.4 补环境让加密函数离开浏览器也能跑当你确定了某个函数内部逻辑想直接复现却发现它依赖了大量浏览器环境比如window、document、navigator就需要“补环境”。做法是在Node.js里用vm模块创建一个sandbox往里面塞上脚本要用的DOM属性、Cookie、UA等const vm require(vm); const sandbox { window: {}, document: { cookie: , referrer: }, navigator: { userAgent: Mozilla/5.0 ... }, location: { href: https://target.com/page }, // 继续补充脚本用到的属性 }; vm.createContext(sandbox); vm.runInContext(jsCode, sandbox);补环境这步最考验耐心报错缺什么就补什么。等代码可以无错运行后你就能把它包装成一个本地函数随时调用生成加密参数。数据科学那边常用这种技术抓取公开数据做分析但要注意目标网站的robots协议和服务条款别越界。4.5 验证码、滑块与风控更多是工程问题很多“逆向”项目不是算法难而是目标网站有行为风控。滑块、点选、无感验证码不仅校验最终坐标还会采集鼠标轨迹、设备指纹和WebGL环境。这类问题的合法解法是购买官方验证码服务或使用测试账号而不是逆向对方的识别模型。我建议各位把精力放在算法还原上风控对抗交给专业安全团队去考虑个人开发者踩进去风险很大。5. 小程序逆向一个被低估的方向小程序逆向和App逆向很像但门槛更低因为小程序包本质还是前端资源。我最近在几个CTF靶场里练过这类题也做过自有小程序的协议审计这里分享一下路径。5.1 拿到小程序包两种常见途径第一种是从PC端微信缓存里找wxapkg文件第二种是在Android手机微信的文件目录里复制。拿到包后先判断加密类型老版本小程序的包可以直接用工具解析新版本很多加了加密需要分析GitHub上常用的解密脚本。我建议新手不要纠结解密包的过程直接找一些现成的小程序逆向工具包去练比如wxappUnpacker这类开源项目。练完后你会明白小程序包的格式就是头部带文件信息的二进制块解析后每个页面一个js文件。5.2 反编译与代码定位解包后你会看到类似app-service.js这种大文件里面是小程序所有页面的逻辑代码。和JS逆向一样先格式化再搜索关键词。小程序的请求都是封装在wx.request里所以搜索url、header、sign直接跳到业务逻辑。为了尽快定位我会在代码里搜索接口域名然后看附近代码如何构建请求参数。小程序和App有个不同点小程序的敏感操作通常会走宿主App的原生能力JS层只能看到WebAPI的调用所以有时候你还要配合微信App本身的逆向去理解参数生成这至少是进阶玩法不是第一优先级。5.3 动态Hook与消息模拟小程序运行在微信宿主进程里常规Frida可以直接attach微信进程然后搜索wx.request的实现位置Hook它查看请求参数。不过微信进程有大量反调试和加固定位准确函数需要时间。日常我做得更多的方式是用开发者工具加载小程序包在小程序的JS代码里注入日志调试时看输出。但这只能用于你自有或获得授权的小程序包别拿线上别人的小程序做实验。5.4 小程序逆向的常见坑分包和异步加载很多接口代码不在主包里而是动态下发后加载直接搜主包搜不到。域名白名单校验小程序请求域名必须配置在后台白名单本地测试经常失败。代码压缩真机发布的包都是压缩过的不格式化根本没法看。宿主App差异不同微信版本对小程序代码的处理不同可能导致解包失败。在这些坑里磨几轮你对前端工程化的理解都会加深不少很多App逆向里碰到的资源加载问题在小程序里都会提前遇到。6. 从CTF Reverse到实战几道题足够练出调试基本功学逆向光看不练是没用的。CTF Reverse是性价比最高的训练场热搜里的traceme.exe、BUUCTF reverse3其实就是很好的入门案例。6.1 想清楚一道题在考什么traceme.exe这类题目通常是给一个可执行文件运行后会问你要一串注册码只有输入正确才能得到flag。你不需要看懂整个程序只需要找到关键比较点。思路是下载后用Ghidra打开看main函数或WinMain的伪代码。你会发现程序大概率把用户输入和某个硬编码或经过计算的字符串比较。先用静态分析理解逻辑再用x64dbg动态调试在关键比较指令处下断点观察内存中的正确字符串是什么。BUUCTF reverse3则是典型的算法还原题倒腾base64、字符位移等操作。看伪代码后把加密逻辑逆推回来再用脚本计算即可。这种题做完后你对字符串处理、数组操作的底层实现会敏感很多。6.2 静态与动态结合一个推演过程以reverse3为例伪代码里可能会有这样的操作遍历输入字符对每个字符加一个固定数再交给base64编码。拿到一个密文后你需要倒过来先base64解码再对每个字符减去固定数得到原始输入。我用Python复现这个过程import base64 # 假设这是从伪代码里还原的密文 cipher aGVsbG8 # base64解码 decoded base64.b64decode(cipher).decode() # 减去固定值 offset 3 flag .join(chr(ord(c) - offset) for c in decoded) print(flag)这个例子很简单但它的思路是通用的正向加密链路的每一步逆向时都必须找到逆操作。如果是异或逆操作还是异或如果是移位逆操作是反向移位如果是查表逆操作就是反向查表。6.3 自动化工具angr和z3等手动调多了你会发现有些题目的加密逻辑非常复杂手动逆推太累。此时可以上符号执行和约束求解。angr可以通过符号执行自动探索程序路径寻找输入使程序输出正确flag。缺点是遇到复杂路径会爆内存适合小型程序。z3微软的约束求解器适合把程序里的约束条件写成表达式求解。很多CTF题里只要能定位到条件判断用z3几秒钟就能出答案。from z3 import * # 假设有约束flag[0] * 2 5 35 flag Int(flag) s Solver() s.add(flag * 2 5 35) if s.check() sat: print(s.model())当然自动化不是万能钥匙遇到反调试、反符号执行的程序还得回到手动分析。这也是为什么我建议主线还是先把基础调试练扎实。7. 实操中反复踩的坑和我的建议最后聊一点更接地气的东西。逆向这行看起来很高大上实际上每天都在和版本不匹配、环境崩溃、代码混淆搏斗。我把自己踩过的坑列出来能帮一个是一个。7.1 工具版本不匹配Frida是重灾区。电脑端frida版本和手机端frida-server版本必须严格对应差一个小版本都会提示无法连接。很多新手第一晚就挂在“Unable to connect to remote frida-server”上其实不是网络问题就是版本没对齐。我目前的处理方式是固定一套常用版本比如frida 16.x配对应frida-server不随便升级。手机和模拟器的架构也要注意ARM64、ARM32、x86_64对应的frida-server不一样。真机一般用arm64模拟器很多是x86或x86_64下错架构就启动失败。7.2 反调试和加固对动态分析的干扰很多商业App会检测Frida端口、ptrace状态检测到调试就在关键函数里走假分支。此时你会看到函数明明被Hook了却完全不打印日志或者程序直接崩溃。绕法并不通用只能基于具体App定制。一般思路是先反混淆、找反调试开关或者用更隐蔽的Hook方式比如基于硬件断点、通过内核模块处理。这个方向已经是高级课程初学阶段建议先拿不加固的App做练习不要一上来就啃最难啃的骨头。7.3 混淆代码和动态加载让静态分析失效当你看到大量类名是a.b.c字符串全是加密的说明App用了混淆加固。此时静态分析效率极低得转向动态。你可以故意触发某个页面然后用Frida枚举已加载的类和方法看调用栈找到具体调用点。或者用SSL抓包先锁定网络请求再根据参数特征去动态栈里找对应函数。总之越混的对象越要靠运行时的信息回推。7.4 我建议的学习路线如果让我推荐一条最短路径顺序是这样的先把Python/Java/JavaScript基础过一遍至少要能读懂代码和控制流。做10道左右的CTF逆向简单题熟悉Ghidra和x64dbg的基本操作。学Frida用一个自建App练习Java层Hook跑通静态定位-动态验证-协议复现闭环。尝试解一个真实开源App的接口加密比如GitHub上很多开源客户端分析它们的登录协议。再转到Web和小程序方向熟悉JS反混淆、AST、补环境。每走一步都尽量写笔记和脚本沉淀下来。逆向是个特别依赖经验积累的领域今天解不出的题过两周再回来看可能十几分钟就搞定了。最后再分享一个小技巧遇到完全没思路的逆向题先别急着上高级工具用最简单的搜索命令在代码里搜password、flag、secret这些词往往会直接看到惊喜。很多所谓“复杂”的逆向入口处的防守其实只是个纸糊的门。
返回列表