1. 四大逆向方向先分清楚:各自在解决什么问题
做网安这行,几乎每隔几天就会有人跑来问我:逆向到底应该先学哪个方向?有人把 Web 逆向、软件逆向、安卓逆向、APP 逆向当成四个完全独立的赛道,也有人以为会了安卓逆向就等于会了 APP 逆向。说句实话,这四个方向确实容易让人绕晕,因为它们底层共用一套“看输入、找逻辑、还原行为”的思维,但切入角度、工具链、对抗方式差别很大。如果一开始就抱错方向,后面很容易学得又慢又挫败。
这篇文章我想把四大逆向知识点的边界、关键流程、常用工具和踩坑经验全部梳理一遍。适合刚准备入门的同学,也适合那些已经在某一块实践过、想横向补齐其他方向的从业者。读完之后你至少能分清:什么时候该去看浏览器里的 JS,什么时候该去拉 IDA 看汇编,什么时候要打开 APK 解包,什么时候要连上移动设备做全局 Hook。
1.1 Web 逆向的典型场景:加密参数怎么来的
Web 逆向本质上做的事情是:你看到一个网页,通过浏览器开发者工具能看到网络请求,但请求里的关键字段是一串加密签名,你想知道这些参数是在哪一段 JavaScript 里生成、用了什么算法、怎么拼接出来的。
最常见的学习场景是分析一个带加密接口的站点。打开浏览器开发者工具,进入网络面板,看到某个 API 请求头里带着sign、token、ts之类的字段,值是一长串看似随机的东西。这时你点进调用栈,顺着代码找,可能会看到一堆压缩过的 JS 代码,变量名是a1b2c3之类的鬼名字,流程里还有各种环境检测,比如检测是否在无头浏览器、是否为某些排查工具的环境等。
Web 逆向真正难的地方不是“看懂代码”,而是“定位入口点”。一个成熟的站点动辄几百 KB 的混淆 JS,你不能从头读到尾,必须学会用搜索、断点、下钩子、补环境这几板斧快速把关键位置找出来。等你能从一段混淆代码里精准摘出加密逻辑,Web 逆向的核心能力就已经建立了一大半。
1.2 软件逆向的典型场景:二进制里藏着的逻辑
软件逆向针对的是传统桌面程序,以 Windows、Linux 平台居多。你手里是一个可执行文件,可能是 exe,可能是 ELF,也可能是动态库。目标通常是搞清楚这个程序内部做了什么:有没有后门、逻辑分支是怎么走的、某个算法用了什么密钥、程序包的壳是什么、有没有反调试。
和 Web 逆向相比,软件逆向最大的区别在于“没有源码”,你只能靠二进制层面的符号信息、字符串、导入表和各种反汇编结果去猜业务逻辑。这非常考验耐心。工具链主要是 IDA、Ghidra、x64dbg、OllyDbg 这类,流程可以抽象为:先静态看结构,再动态跑起来下断点,最后把关键函数逐个还原成伪代码。
很多人一开始就被“汇编语言”劝退,但实际分析时你不需要把每条指令都读懂。别慌,先把常见指令认全,再依赖反编译工具的伪代码功能,你会发现大多数逻辑能还原成类似 C 语言的代码。
1.3 安卓逆向与 APP 逆向:边界到底在哪
标题里把“安卓逆向”和“APP 逆向”分成两个知识点,这点特别值得展开讲。就我的理解,安卓逆向更偏“APK 逆向”,关注的是 Android 应用的包结构、Java/Kotlin 层代码、smali 修改、Dex 反编译这些,本质上是围绕安卓运行环境的逆向分析。
而 APP 逆向的范围更广,它更像是“移动端整体逆向”,包括了安卓应用分析、iOS 应用分析、协议层分析、native 库分析、存储与密钥分析、自动化调用等多个环节。你可以理解为:安卓逆向是 APP 逆向里最重要的一个分支,但 APP 逆向面对的问题要更多元。比如一个跨平台应用,核心逻辑可能放在本地 so 库里,也可能会走一套私有协议,这部分不会因为你只是解包 APK 就自动浮现出来。
把这四个方向并列看待是合理的,因为每个方向的入手点完全不同。但你要记住,它们的底层心智又高度一致:先捕获输入输出,再找关键模块,最后还原核心计算过程。
1.4 四个方向共用的知识底座
不管做哪个方向,有几样东西是你躲不开的:HTTP 协议基本结构、常见加密算法特征、汇编基础、调试器常用操作、以及一种脚本语言(JavaScript 或者 Python)。Web 逆向和 APP 逆向尤其看重网络协议理解;软件逆向和安卓逆向则更看重二进制基础。
另外还有一个共通的底层思维:假设你在黑盒里只能看到输入和输出,怎么一步步把中间过程推理出来?这是一个需要刻意训练的能力。遇到一个陌生样本,不是急着找神兵利器,而是先规划流程:先静态摸结构,再动态看行为,最后聚焦关键点做精细分析。
2. Web 逆向:从网络请求到加密逻辑还原
Web 逆向是很多人入门逆向的第一站,原因很简单:你不需要搭建虚拟机,不需要买设备,打开浏览器 F12 就可以了。但它要解决的问题并不简单。
2.1 先看请求,再定位代码
我第一次做 Web 逆向时犯过一个典型错误:拿到一段混淆 JS 就开始从头看,结果看了半小时连业务入口都没找到。后来总结出正确顺序是:先看网络请求,找到目标接口,观察请求参数里哪些是固定的、哪些是动态的、哪些看起来像加密签名。
比如 POST 请求里有一个data字段,值是 URL 编码后的一串密文,那你要看的就不仅是这个接口本身,还要看它前面有没有 JS 对文本做加密处理。浏览器开发者工具的“调用堆栈”非常好用,点开请求发起那一行,再看调用关系,就能顺着 JS 栈往回追。要是还找不到,就用“全局搜索”功能搜索参数名,比如sign、signature、encrypt、token,看看这些词在哪个 JS 文件里出现过。
一旦定位到某个函数像加密入口,别急着全读。先在函数入口下断点,刷新页面让断点命中,再通过调用栈逐步观察参数和输出。这是 Web 逆向核心的“断点大法”。
2.2 断点调试、Hook 与补环境
断点调试确实好用,但有些 JS 会有反调试逻辑,比如无限 debugger、定时器干扰、环境检测。很多入门者卡就卡在:一下断点页面就卡死,或者代码一执行就检测到调试工具,直接走了另一条分支。
这时候需要 Hook 思路。用浏览器插件或脚本,在关键函数执行前后强行改写它的行为。比如在目标函数被调用前,通过Object.defineProperty重写某个对象的方法,把参数打印出来,或者直接替换返回值。这一步说白了就是“观察到关键函数的输入和输出”。有时你也需要补环境,意思是在本地模拟浏览器里缺失的全局变量,让混淆代码以为自己在真实浏览器里运行。
举个常见场景:目标 JS 里检测了navigator.webdriver是否存在,如果存在就不执行正常逻辑。你在本地补一个假的navigator.webdriver = undefined,代码就会继续往下走。补环境本身很繁琐,但它是 Web 逆向绕不开的一环,尤其在处理大型站点时。
2.3 Web 逆向最容易踩的坑
我在实践里总结过几个高频问题,每个都值得单独说。
第一,混淆代码里搜索字符串会失效。有些混淆工具会把字符串编码成数组,甚至动态解码,你直接搜sign可能什么都搜不到。更好的做法是搜索可能存在的 API 路径、硬编码的 key 值,或者用 AST 工具解混淆,先把字符串和变量名还原出来。
第二,改 JS 跑本地逻辑后,一遇到环境检测就挂。根本原因是浏览器环境太复杂,补环境补得不完整。可靠的做法不是一次性补全所有环境,而是采用“先跑通主干,再逐项报错补全”的方式。哪个变量报 undefined 就补哪个,反复两次之后,环境就慢慢趋近了。
第三,天天被平台的版本更新追着跑。Web 端代码更新频率极高,今天分析的接口签名算法,可能下周就换了。所以我一直建议:别记具体实现,要记分析思路和流程,能把方法论复制到新目标上才是本事。
2.4 一个典型加密参数还原过程的演示
假设你抓到一个登录接口,能看到四个参数:username、password、ts、sign。其中ts看起来是 10 位时间戳,sign是 32 位小写字母加数字的字符串。初步判断是 MD5。
搜索sign定位到这样一段逻辑:先取ts字符串,再把username、password、ts用固定分隔符拼接,最后调用md5()函数计算。你只要在本地还原这个拼接顺序,就能生成同样的sign。整个过程不对,但“抓参数、搜定位、理解拼接、本地验证”这条链路是所有 Web 逆向的基础。验证成功的方法就是拿同样的数据,用你还原的逻辑本地模拟,对比输出是否与抓包结果一致。
3. 软件逆向:从二进制到业务逻辑
软件逆向是四大方向里对基础要求最高的一个,但也是技术含量很高的一块。它解决的问题通常是:给你一个二进制程序,在没有源码的前提下,搞清楚它的内部结构和关键逻辑。
3.1 静态分析的本质:先摸文件结构
拿到一个 exe 或者 ELF 文件,我的习惯是先用工具看一眼文件格式和节区结构。Windows 程序是 PE 格式,Linux 是 ELF 格式,里面都有节区表、导入表、导出表、重定位表。用 IDA 或者 Ghidra 打开后,第一件事不是按 F5 看伪代码,而是先看导入表。一个程序如果真的走了加密逻辑,通常会在导入表里出现相关库函数。导入表有时候被加密,但只要脱壳后还是能看到。
静态分析的本质就是:在程序没有运行的情况下,把它的静态特征全部收集出来,从中提取线索。你可以查看字符串列表,看看有没有隐藏的 URL、密钥片段、错误提示信息。比如一个恶意样本里有C:\Windows\Temp\payload.bin,这个字符串就给出了非常强的行为提示。再比如某个函数里出现了固定的常量,比如0xEDB88320,能立刻想到 CRC32,出现0x67452301、0xEFCDAB89,就想到了 MD5 的初始向量。
这些特征虽然简单,却能让你的分析效率发生质的飞跃,不要小看这一步。
3.2 动态调试:让程序自己说出答案
静态分析能看到全貌,但遇到混淆代码或者加壳程序时,动态调试就是更高效的解法。动态调试的核心逻辑是:让程序在你自己可控的环境里运行,你通过调试器控制执行流程,观察寄存器、栈、内存、函数调用顺序。
以 x64dbg 为例,你可以下“断点到某函数入口”,然后观察它的参数。比如一个密码校验函数,你随便输入一长串字符串,断点命中后观察传入参数寄存器的值,就能看到程序拿到的是什么形式的数据。再继续单步,看它调用哪个加密函数,再从函数返回后的寄存器值判断结果。如果你想快速看到某个函数是否被调用,用“记录日志断点”会比手动单步更高效。
需要特别注意一点:动态调试很容易被反调试对抗。常见手段包括IsDebuggerPresent检测、时间差检测、断点检测。遇到这种情况,要么在调试器里隐藏特征,要么用 ScyllaHide 这类反反调试插件。你可以先尝试交互式调试,实在不行再回头看静态流程。
3.3 加壳与混淆的应对思路
很多商业软件和恶意软件都会加壳。加壳的目的在于让静态分析工具看不到原始代码,只有程序运行后自行解密,才能真正还原代码。加壳本身不是“无解”,只是让它从静态分析问题变成了动态转储问题。
常规处理顺序是:先识别壳种类,再用专门工具脱壳,或者直接从运行中的进程内存里 dump 出原始模块。如果连工具都脱不了,就寻找“内存解密完成但壳还没接管控制权”的时机,人工 dump。这个过程确实需要经验积累,刚开始失败几次非常正常。
混淆和壳经常同时出现。比如控制流平坦化,会把原本简单的逻辑变成一张巨大状态机,让人看得头疼。针对控制流平坦化,可以用反混淆脚本或者工具辅助还原,也可以不还原,直接根据运行时的输入输出关系推断逻辑。实战中,我反而更推荐后者:你不需要把每条指令都理顺,只需要找出关键函数和对应的输出行为就可以了。
3.4 软件逆向的实操心得
我给刚接触软件逆向的人三条建议。
第一,下载任何样本前确认自己是否有授权,本地调试也尽量放在虚拟机里,不要把工作机搞成实验场。
第二,静态分析之前先跑一遍strings和导入表分析,这些低成本动作经常直接给出答案。
第三,遇到巨型程序一定要学会“局部主战场”思维:不要试图一次看懂全部函数,先以关键导入函数为线索,逆着调用关系找到最核心的一小片代码。
4. 安卓逆向:从 APK 到 smali 再到 Dalvik
安卓逆向是四个方向里门槛相对亲民、但内容很丰富的方向。它的分析目标通常是一个 APK 文件,也可以是已经安装的 App,整个过程大致可以拆成静态分析和动态分析两条线。
4.1 解包、反编译与清单文件
拿到一个 APK,第一件事通常是拆包。APK 本质上是个 zip 包,直接用解压工具也能打开,但真正规范的做法是用apktool解包,它会帮你把资源文件、AndroidManifest.xml、Dex 文件都处理成可读形式。
解包后优先看 AndroidManifest.xml。它能告诉你四项关键信息:应用包名、入口 Activity、申请了哪些权限、注册了哪些服务。很多时候,权限申请列表就能透出套路。比如一个计算器应用申请了读取通讯录权限,那问题就很大。
再往后是看核心代码。APK 里的主要逻辑集中在 classes.dex 里,这是 Dalvik 字节码。你可以用 jadx 直接把 Dex 反编译成 Java 代码,看起来和正常源码没差别。遇到抽取壳或者无法直接反编译的情况,再考虑用 Frida 在运行时把真实类 dump 出来。
4.2 Java 层分析:优先搜索字符串
大部分安卓逆向工作都在 Java 层就能得出答案。我的方式是先看入口 Activity,再到 jadx 反编译的代码里搜索关键字符串,比如接口地址、密钥、加密算法名、常量值。搜索字符串在安卓逆向里比 Web 逆向更可靠,因为它不像 JS 那样会大量混淆命名。
如果你找到了类似AES/CBC/PKCS5Padding的字样,再顺着调用链找 key 和 IV 是怎么传入的,很快就能还原加密逻辑。很多 App 会把密钥硬编码在 Java 代码里,这也是移动端常见的安全缺陷,你要习惯去代码里翻找。
靠近底层的地方,如果看到System.loadLibrary("native-lib"),说明核心算法很可能在 native 层,这时候 Java 层分析结束,要转入 so 文件分析。
4.3 smali 修改与重打包
安卓逆向有一个独特分支叫“重打包分析”。你把解包后的 smali 代码修改逻辑,重新签名打包成一个新 APK,再安装到模拟器或者真机上验证行为。这在做样本分析和逻辑验证时很常用。
常见操作是:在 smali 里定位一个关键方法,把返回数值改成 1,或者跳转逻辑反转。修改 smali 不像写 Java 那么直观,需要记住if-eqz是“等于零跳转”这种基础指令,不过用多了就自然记住了。改完以后用apktool b回编译,再用jarsigner或apksigner签名,就能得到一个修改版 APK。
每次改代码都要重新打包签名,效率不高,所以我更推荐把“重打包”当成验证方案,而不是每一次的首选。
4.4 动态 Hook:Frida 是实战利器
静态分析看不懂的地方,Frida 能起到奇效。Frida 是一个动态插桩工具,可以在 App 运行时注入 JavaScript 脚本,Hook 任意 Java 方法,查看参数、修改返回值,甚至直接调用内部方法。
比如目标 App 有一个加密函数encode(data),你不想看它的实现,只想让它把加密前的明文和加密后的结果都打出来,可以用脚本快速实现。Frida 的思路就是“黑盒旁路”,我不用理解函数的实现细节,只要在函数入口和出口分别插桩,就能拿到输入输出对。当你搞不清算法时,用输出反推规律,是一个很有用的策略。
动态 Hook 还能绕过很多反调试。因为你不是在反馈是否调试,而是直接注入了目标进程。只要应用没有专门检测 Frida 运行特征,基本都能顺利得手。当然,这种方式也需要设备环境支持,模拟器或真机加上 frida-server 都要提前准备好。
4.5 安卓逆向几个重要的细节
一是 SDK 版本兼容问题。不同版本的安卓对签名方案、Apk 结构要求不一样,重打包后经常因为签名算法不兼容被拒绝安装,遇到这类问题优先检查签名方案。
二是模拟器检测。很多 App 会检测模拟器环境并停止运行,针对这种情况,优先换用真机测试,或者做环境掩藏处理。
三是资源混淆。现在很多 APK 会做资源混淆,把类名和字段名改成 a/b/c,你在 jadx 里看起来会很痛苦。遇到这种情况,重点去看逻辑跳转关系,而不是纠结变量名。
5. APP 逆向:移动端整体分析比想象中更深
把 APP 逆向单独拎出来讲,是因为它不只是安卓 APK 分析的延长线。实际工作中,你面对的移动 App 可能有非常复杂的跨平台架构、native 库、私有协议,甚至还会做多重混淆,这些内容都可以放到“APP 逆向”这个大框架下思考。
5.1 为什么 APP 逆向不完全是安卓逆向
很多人觉得,安卓逆向就是 APP 逆向,做完 APK 分析就结束了。但真实情况是,一个 App 的运行行为往往横跨多个层级:Java/Kotlin 层负责 UI 和业务调度,native 层负责核心算法和高性能计算,网络层负责与服务器通信,本地存储层负责数据持久化。你只分析 Java 层,就等于只看了一座冰山的水面部分。
比如很多 App 把登录签名算法放在 so 库里,Java 层只是调用了nativeSign(params)。你如果想复用这个签名逻辑,不仅要知道函数的参数格式,还要想办法调用 so 或者重写算法。而 iOS 端又是完全不同的 Mach-O 格式和 Objective-C/Swift 运行时,这显然超出了“安卓逆向”的概念。
所以我会把 APP 逆向定义为“以移动应用整体为目标的分析方法”,它的核心思路是:先确定程序的信息流从哪出发、到哪终结,然后顺着数据流动的路径逐层拆解。
5.2 从流量入手分析 App 协议
APP 逆向里非常实用的一个切入点是看流量。先抓包看 App 与服务器交互时使用了哪些接口、上传了哪些字段、是否加密。可以中转代理的方式获取 HTTP 流量。如果是 TCP 或 UDP 自定义协议,就得考虑用 RPC 方式或者直接对 so 层分析,再结合协议格式自己还原请求结构。
流量分析的好处在于能让你在完全不懂代码的情况下,快速了解 App 的业务骨架。你不需要立刻搞清楚签名算法,只要知道某个关键 action 存在,就已经能为后续深层分析指明方向。
5.3 native 库与 so 层分析
当 Java 层无法满足分析需求时,就要打开 so 文件。手机里拿到的 so 文件是 ELF 格式,你可以用 IDA 或 Ghidra 打开,查找导出函数,看看有没有 JNI 接口。使用 JNI 导出的函数通常命名规则很明确,比如Java_com_example_app_NativeLib_sign,看到这个名称就能对号入座。
分析 so 的流程和软件逆向差不多:先看导出表,再看字符串和导入表,然后针对核心函数做动态调试或者 Frida Hook。由于 so 里的代码经常做了混淆和 OLLVM 保护,直接静态分析往往困难,动态插桩调试会更高效。
建议在开始 so 分析前先掌握一点 ARM 汇编基础。 Jones 运算、函数调用约定、栈平衡这些概念都是高频出现的。即使看不懂所有指令,能看懂条件跳转、函数开头结尾的特征,已经能支撑大部分工作。
5.4 存储与密钥的常见位置
APP 逆向还会涉及本地存储分析。很多时候关键数据被藏在私有目录里,比如 SharedPreferences、数据库文件、日志文件等。获取这些数据的前提是设备能正确访问对应目录,或者说能通过备份、dump、Hook 等方式把数据提取出来。
密钥硬编码也是一个常见问题。很多 App 虽然没有在 Java 层写死密钥,但在 so 层的字符串表里留了蛛丝马迹。比如某个字符串看起来不像明文,但以0x开头,可能就是硬编码的 hex 密钥,你可以去代码里搜索引用它的位置。
5.5 合规视角与边界提醒
APP 逆向分析必须严格遵守合规边界。实际工作中,授权测试、个人学习研究、漏洞报送这类场景是被允许的,但绝不能拿别人正在运营的应用做反向破解、绕过付费、窃取用户数据。
正规的用法有很多:分析恶意 App 是否偷拍偷录、检查自家应用是否存在硬编码密钥、在漏洞挖掘过程中验证某个加密逻辑是否可被绕过。这些都属于正当的安全研究与测试范畴。搞清楚这些边界,远比学会几个工具更重要。
6. 绕不开的坑:四类逆向共通的教训与学习建议
标题里的四个知识点,单看任何一个都有很多坑。但把四个方向都摸过一遍之后,我发现有些坑几乎是通用的,踩过的次数多了,也就变成了一种经验。
6.1 环境配置中的常见误解
很多新人容易把时间浪费在“工具迷信”上:到处找破解版工具、想办法装全功能插件、为了配环境熬夜。结果真正分析的时间反而很少。我的实际体会是:工具够用就好,不用追新。
比如 Web 逆向只需要浏览器开发者工具加一个抓包代理就足够起步;软件逆向用 Ghidra 加一个调试器就能打开大多数文件;安卓逆向用 jadx 加 Frida 基本覆盖九成分析需求。先把一套环境跑通,比收藏十个工具更加重要。
还有一个容易犯的错:忽略日志和报错信息。逆向时遇到崩溃或者异常输出,这是最好的线索来源,结果很多人第一反应是重装环境。先读报错文字,往往两分钟就能定位问题。
6.2 单点思维是最大的瓶颈
不少人有这样一个习惯:一旦定位到某个加密函数,就只盯着那个函数一路深挖。但实战里,逆向分析更讲究“先整体后局部”。比如一个 App 的请求签名逻辑分散在好几个 class 里,有些 key 是在启动时动态生成的,还有一些参数要从配置文件里读取。如果你只盯单个函数,很容易最后拼不出完整的请求闭环。
更靠谱的方法是把数据流图画出来。入口是用户点击,出口是服务器的某个接口,中间每一步都记清楚输入和输出。这张图未必很正式,但能帮你建立全局视野,避免钻进死角。
6.3 建议的学习路线
如果非要说一条相对平滑的路线,我会这样推荐:先学 Web 逆向,因为它上手门槛低,能快速培养“定位关键逻辑”的感觉;然后转向软件逆向,补上二进制和汇编基础;接着做安卓逆向,进一步理解移动端运行机制;最后再进入 APP 逆向的整体分析,把 native 层和协议层结合起来看待。
但顺序不是死的。如果你对汇编和操作系统更熟悉,可以直接从软件逆向入手。反向的学习速度其实很大程度上取决于你对底层和程序运行过程的理解。
这里也放一张工具选型参考表,方便按方向快速检索:
| 方向 | 常用工具 | 关键步骤 | 核心能力 |
|---|---|---|---|
| Web 逆向 | 浏览器开发者工具、抓包代理、AST 解混淆脚本 | 定位参数、断点调试、补环境 | 快速定位和还原 JS 逻辑 |
| 软件逆向 | IDA、Ghidra、x64dbg | 静态分析、动态调试、脱壳 | 从二进制还原关键逻辑 |
| 安卓逆向 | jadx、apktool、Frida | 解包反编译、smali 修改、动态 Hook | 还原 Java 层与 Dalvik 层逻辑 |
| APP 逆向 | 抓包代理、IDA、Frida、设备环境 | 协议分析、so 分析、存储分析 | 移动应用整体数据流分析 |
6.4 最后分享一点个人感受
我在实际分析中最大的体会是:逆向不是“一次就能成功”的事情,更多时候是在反复试错、补环境、换思路之后才跑通。遇到一个顽固样本,连续几天没有进展是常态,恰恰是在这种卡住的时候,你才会真正理解工具运行原理,也才会积累出属于自己的排查习惯。
如果你刚开始接触这四个方向,别急着一次铺开,先挑一个最有兴趣的入口,把一条链路彻底跑通,再横向扩展。经验都是在具体样本里磨出来的,没有例外。以后我再遇到这类“四大方向怎么选”的问题,我都会直接说:别纠结,动手分析一个样本,答案自然就清楚了。