Trim both READMEs and add the tutorial primer
README 242 -> 180 lines: the 14-row tool table becomes three sentences pointing at capabilities.py, Read this first merges into Scope, and the six-script maintenance block becomes a table. Every path, command and anchor is unchanged. README.zh-CN follows the same eight sections, and picks up two drifts: it named hwprobe.py as the cheapest first command (SKILL.md and the English README say doctor.py), and it translated triage as 'three categories', which sends a reader looking for categories that do not exist. docs/primer is the Windows reverse-engineering tutorial series with an index, corrected in three places: x64dbg instead of OllyDbg, offsets fixed only within one build, and IAT hooking assuming the target imports the API it hooks. docs/tool-acquisition keeps the part capabilities.py does not answer: licence classes, id resolution on the host, and what proves a tool runs.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
# Windows 逆向入门(讲义)
|
||||
|
||||
面向**人**的入门连载,按学习顺序读。它不是 `skills/exe-reverse/` 的一部分:那个 skill 是给
|
||||
agent 按症状和门禁查的,这里是把同一批概念按由浅入深的顺序铺开给读者。
|
||||
|
||||
## 篇目
|
||||
|
||||
| 文件 | 内容 |
|
||||
|---|---|
|
||||
| `exe1.md` | 原理:程序怎么加载、基址与偏移、代码与数据的区别 |
|
||||
| `exe2.md` | 缺失(原连载未找到这一篇) |
|
||||
| `exe3.md` | 方法:找偏移的六条路 |
|
||||
| `exe4.md` | 利用:外部工具、DLL 注入与 hook |
|
||||
| `exe5.md` | 工具:CE、IDA、x64dbg |
|
||||
|
||||
## 读到这三处要注意
|
||||
|
||||
- **`exe5.md` 的调试器是 x64dbg**,不是早期教程里的 OD。OllyDbg 只支持 32 位且早已停止更新。
|
||||
- **`exe1.md` 的“偏移固定”只在同一个构建内成立**。同一份 exe 每次加载偏移不变,但重新编译就变;
|
||||
跨版本要靠特征码重新定位,不能死记地址。
|
||||
- **`exe3.md` 的“拦截系统函数”默认目标是走 IAT 的**。运行时解析 API 或直接发系统调用的目标,
|
||||
导入表里没有那一行,这一招会落空。
|
||||
|
||||
概念上和 `skills/exe-reverse/SKILL.md` 的 `references/pe-structure.md`、
|
||||
`references/recon.md`、`references/injection-and-hooking.md` 对应;遇到具体操作时看 skill,不要只看讲义。
|
||||
@@ -0,0 +1,135 @@
|
||||
开发,是先写代码,再编译成软件。而逆向分析,到手的只有软件。从软件入手,推测对应的代码,需要了解一下编译之后的软件是怎么跑起来的。
|
||||
|
||||
|
||||
|
||||
软件运行过程
|
||||
|
||||
1、软件加载到内存。
|
||||
|
||||
2、CPU读取内存的指令。
|
||||
|
||||
3、根据指令,再读取数据,进行运算。
|
||||
|
||||
4、运算的过程,数据是存在CPU里面的寄存器。
|
||||
|
||||
5、运算过程,用到另一个功能,需要保存当前环境,存到堆栈。
|
||||
|
||||
(这里涉及操作系统和计算组成原理,大概了解,心里有底就好)
|
||||
|
||||
|
||||
|
||||
代码语言的变化
|
||||
|
||||
1、C/C++语言:高级语言,给人看的
|
||||
|
||||
2、汇编语言 :低级语言,给机器用的
|
||||
|
||||
(逆向分析,接触多是汇编语言, 需要自行学习下)
|
||||
|
||||
|
||||
|
||||
软件加载过程
|
||||
|
||||
磁盘 >>内存>>寄存器
|
||||
|
||||
1、代码编译成软件,先放在磁盘(C盘,D盘这些)
|
||||
|
||||
2、开始运行的时候,就会加载进内存(平时说的内存条)
|
||||
|
||||
3、真正运行的是在CPU(也就是所谓的芯片),里面存数据的地方叫寄存器。
|
||||
|
||||
|
||||
|
||||
软件的构成
|
||||
|
||||
软件的外部
|
||||
|
||||
包含:一个主要程序(exe后缀),多个独立库(dll后缀)。
|
||||
|
||||
内存一开始加载exe,有必要的时候,exe再把dll加载进内存来。
|
||||
|
||||
|
||||
|
||||
exe或者dll在内存的开始位置,叫做基址。(每次加载,随机放置,基址不固定)
|
||||
|
||||
exe或者dll里面和基址的距离,叫做偏移。(每次加载,内部不变,偏移固定)
|
||||
|
||||
|
||||
|
||||
打个比喻:exe和dll相当小尺子,要放在内存这个大尺子上。
|
||||
|
||||
大尺子上只要有空位,小尺子就可以随便放。
|
||||
|
||||
小尺子不管怎么放,里面的刻度固定的。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
软件的内部
|
||||
|
||||
软件 = 代码 + 数据
|
||||
|
||||
数据 = 静态数据 (数据不会变)+ 动态数据 (数据会改变)
|
||||
|
||||
动态数据 = 全局数据 (多个函数共用)+ 局部数据(单个函数私有)
|
||||
|
||||
|
||||
|
||||
代码和静态数据在软件运行过程不会改变,位置固定,可以方便使用。
|
||||
|
||||
全局数据,因为是共用的,位置固定,也可以方便使用。
|
||||
|
||||
所以这三种的偏移是不变的。
|
||||
|
||||
|
||||
|
||||
内存地址 = 基址 + 偏移。
|
||||
|
||||
基址可以用GetModuleHandle得知。
|
||||
|
||||
偏移又是不变的,内存地址也就可以算出来了 。
|
||||
|
||||
|
||||
|
||||
而偏移会变化的局部数据,就不能直接算出来了。
|
||||
|
||||
局部数据,是软件运行过程中,临时生成又销毁的。
|
||||
|
||||
所以要获取局部数据,只能在软件的运行过程进行拦截。(也就是所谓的HOOK)
|
||||
|
||||
|
||||
|
||||
逆向分析目的
|
||||
|
||||
逆向分析的两个目的
|
||||
|
||||
1、调用功能
|
||||
|
||||
2、获取数据
|
||||
|
||||
|
||||
|
||||
通过上面的原理可以知道
|
||||
|
||||
1、调用功能
|
||||
|
||||
代码是固定的,找到偏移,就可以调用。
|
||||
|
||||
2、获取数据
|
||||
|
||||
对于全局数据,找到偏移,就可以得到。
|
||||
|
||||
对于局部数据,需要拦截,才可以得到 。
|
||||
|
||||
(拦截的是代码,所以要找代码的偏移)
|
||||
|
||||
|
||||
|
||||
所以,逆向的核心点,是找固定的偏移。
|
||||
|
||||
这里说的“固定”只在一个构建内成立:同一份exe,偏移每次加载都不变;但软件一升级、重新编译,偏移就变了。所以跨版本不能死记偏移,要用特征码这类能在新版本里重新定位的办法。
|
||||
|
||||
|
||||
|
||||
下一篇,找偏移的方法。
|
||||
@@ -0,0 +1,94 @@
|
||||
Windows逆向分析入门(三)——方法篇
|
||||
前言
|
||||
|
||||
上一篇,聊到逆向分析是找偏移,有依据地找,效率会快。这一篇聊下找偏移方法。只说概念,具体的细节,后续会配合实战再展开细说。
|
||||
|
||||
|
||||
|
||||
找偏移的方法
|
||||
|
||||
1、内存
|
||||
|
||||
逆向的目的,是找功能或者数据在内存的地址。最直接的方法,就是在内存里面搜索。
|
||||
|
||||
|
||||
|
||||
对于数据:可以直接在内存搜索。
|
||||
|
||||
对于功能:如果知道代码的特征码,也可以直接在内存寻找。
|
||||
|
||||
(所谓代码的特征码,具体是一串字符串,在内存是唯一的,可以用来搜索定位)。
|
||||
|
||||
|
||||
|
||||
2、界面
|
||||
|
||||
带界面的软件,一般流程就是:
|
||||
|
||||
1、软件生成界面,界面上会有按钮,编辑框这些控件。
|
||||
|
||||
2、用户操作界面,点击按钮或者输入文字等等。
|
||||
|
||||
3、软件接收到用户的操作,调用对应的功能。
|
||||
|
||||
4、调用的功能对数据进行处理。
|
||||
|
||||
5、处理结果显示在界面上。
|
||||
|
||||
|
||||
|
||||
如果知道这个流程在代码里面是怎么实现的,就能找到对应的功能和数据。
|
||||
|
||||
|
||||
|
||||
3、日志
|
||||
|
||||
软件运行的过程,是没办法像视频那样可以倒放。
|
||||
|
||||
想了解软件的运行过程,需要在软件里面埋下标记。
|
||||
|
||||
当软件运行过程,经过做标记的位置,就可以输出信息。(也就是所谓的日志)
|
||||
|
||||
而逆向分析,通过日志找到标记,能知道对应的功能在哪里。
|
||||
|
||||
|
||||
|
||||
4、字符串
|
||||
|
||||
代码里面写的字符串,编译成软件的过程,会被当作全局数据,存在固定的地方。
|
||||
|
||||
而字符串可能有对应的功能,比如 send msg,可能出现在发送信息的功能附近。
|
||||
|
||||
通过搜索字符串,看看哪里用了这个字符串,就可以找到对应的功能。
|
||||
|
||||
|
||||
|
||||
5、系统函数
|
||||
|
||||
写代码的过程中,需要用到一些比较基础的功能。(比如读写文件,收发网络信息)
|
||||
|
||||
这个时候直接用系统提供的接口就可以了。
|
||||
|
||||
这些接口是公用的,所以偏移固定的。
|
||||
|
||||
通过拦截这些接口,就可以定位了。
|
||||
|
||||
但这招有个前提:目标确实经过导入表(IAT)调用这个接口。现在的软件常在运行时才解析API地址,或者直接发系统调用,导入表里根本没有这一行,这时拦截就落空了,要换别的方法定位。
|
||||
|
||||
|
||||
|
||||
6、第三方库
|
||||
|
||||
软件可以看成由多个模块组成的,像搭积木那样。
|
||||
|
||||
而这些模块大多通用的,比如:界面模块,日志模块。
|
||||
|
||||
为了加快开发速度,一般会使用别人写好的第三方模块。
|
||||
|
||||
如果第三方模块是开源的,相当知道软件的一部分代码。
|
||||
|
||||
通过第三方的代码,可以推算出软件还没解开的另一部分。
|
||||
|
||||
|
||||
|
||||
下一篇,找到偏移之后,聊聊利用偏移写代码的思路。
|
||||
@@ -0,0 +1,85 @@
|
||||
偏移之后,就是写辅助工具了。这一篇聊聊写辅助工具的原理。具体的代码细节,等到实战会展开细说。
|
||||
|
||||
|
||||
|
||||
明确一下
|
||||
|
||||
逆向两个目的
|
||||
|
||||
1、调用功能
|
||||
|
||||
2、获取数据
|
||||
|
||||
|
||||
|
||||
对应的实现方法
|
||||
|
||||
1、调用功能
|
||||
|
||||
找到偏移,直接调用。
|
||||
|
||||
2、获取数据
|
||||
|
||||
对于全局数据,找到偏移,直接得到。
|
||||
|
||||
对于局部数据,拦截代码,间接得到 。
|
||||
|
||||
|
||||
|
||||
写外部工具
|
||||
|
||||
1、调用功能
|
||||
|
||||
windows系统提供了接口(CreateRemoteThread),允许一个软件调用另一个软件的功能。
|
||||
|
||||
2、获取数据
|
||||
|
||||
对于全局数据
|
||||
|
||||
windows系统提供了接口(ReadProcessMemory),允许一个软件获取另一个软件的数据。
|
||||
|
||||
对于局部数据
|
||||
|
||||
windows系统提供了调试机制,就是在目标软件设置陷阱,当软件触发到陷阱,会暂停下并且抛出报错信息
|
||||
|
||||
辅助工具监听到报错信息,进而获取目标软件的数据。
|
||||
|
||||
|
||||
|
||||
写内部工具
|
||||
|
||||
辅助工具,可以写个间谍模块(dll),然后注入到目标软件里面去。
|
||||
|
||||
通过间谍模块,辅助工具就可以操控目标软件,进而调用功能或者获取数据。
|
||||
|
||||
|
||||
|
||||
1、调用功能
|
||||
|
||||
在内部,可以直接调用
|
||||
|
||||
2、获取数据
|
||||
|
||||
对于全局数据
|
||||
|
||||
在内部,可以直接获取
|
||||
|
||||
对于局部数据
|
||||
|
||||
内部修改代码拦截(HOOK)
|
||||
|
||||
|
||||
|
||||
正常流程:步骤1 -> 步骤2
|
||||
|
||||
拦截流程:步骤1 -> hook拦截 -> 步骤2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
理论上的东西,差不多这样,下一篇,聊逆向分析用到的工具。
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
Windows逆向分析入门(五)——工具篇
|
||||
前言
|
||||
|
||||
老话,工欲善其事,必先利其器。这篇聊聊逆向分析用到的工具。不聊工具细节,自行百度学习。重要的是理清:使用工具,是为了解决什么问题。
|
||||
|
||||
|
||||
|
||||
工具
|
||||
|
||||
1、CE
|
||||
|
||||
找偏移的方法中聊到,最直接就是在内存里面搜索。
|
||||
|
||||
CE(CheatEngine又称CE修改器),就是用来搜索内存里面东西,得到内存地址。
|
||||
|
||||
|
||||
|
||||
2、IDA
|
||||
|
||||
逆向分析,我们拿到手的是已经编译好的软件,看不了代码。
|
||||
|
||||
要是能把软件恢复成代码,分析起来就方便多了。
|
||||
|
||||
IDA这个工具,就是用来把软件恢复成代码的。
|
||||
|
||||
软件编译过程会去掉一些多余的信息。
|
||||
|
||||
所以IDA没办法说完全恢复代码。
|
||||
|
||||
但是用来分析还是很方便的。
|
||||
|
||||
这就是所谓的静态分析。
|
||||
|
||||
|
||||
|
||||
3、x64dbg
|
||||
|
||||
用IDA分析软件的时候,软件并没有运行起来,能分析的是软件的静态结构。
|
||||
|
||||
如果要知道到软件运行的具体过程是什么样的,就需要用动态调试工具,比如x64dbg。
|
||||
|
||||
x64dbg里面看到的是汇编的代码,需要熟悉汇编语言和CPU的运行过程,原理篇有聊到。
|
||||
|
||||
早年的教程里常见的是OD(OllyDbg),它只支持32位程序,而且早已停止更新。今天用x64dbg;内核调试或者需要命令行脚本时,用WinDbg。
|
||||
|
||||
|
||||
|
||||
经验
|
||||
|
||||
工具这块建议重视,多花点时间,效率会快很多。
|
||||
|
||||
CE用来定位数据,x64dbg用来动态调试,IDA用来看代码,多灵活结合。
|
||||
@@ -0,0 +1,59 @@
|
||||
# Tool acquisition, and what it costs
|
||||
|
||||
**What this answers:** how a tool gets onto an analysis host, what its licence permits, and how
|
||||
you know it actually runs. This is the part `capabilities.py` reports as a gap but does not
|
||||
close -- the probe says "missing", and this says what to do about it.
|
||||
|
||||
**When to load this:** when a route is blocked by an absent tool, or when its real cost is a
|
||||
licence rather than an install.
|
||||
|
||||
## Licence class before download
|
||||
|
||||
| Class | Examples | What it costs you |
|
||||
|---|---|---|
|
||||
| Open | Ghidra, radare2/rizin, x64dbg, Frida, gdb, lldb, upx, 7-Zip | nothing; support and maintenance are the real cost |
|
||||
| Free, restricted | IDA Free (non-commercial), Cheat Engine, most vendor trials | a licence *condition*, not a price; a commercial engagement may exclude it |
|
||||
| Commercial | IDA Pro + Hex-Rays, Binary Ninja, Hopper | a per-seat licence; procurement lead time is part of the plan |
|
||||
| Trial | vendor time-limited builds | an expiry date in the middle of a session; write it down |
|
||||
|
||||
**No cracked builds, no key generators, no patched installers.** Two reasons, and the second is
|
||||
the engineering one: a patched binary is an untrusted binary, and you would run it on the machine
|
||||
whose integrity every later measurement depends on. An unlicensed tool is a capability you do not
|
||||
have -- record it that way.
|
||||
|
||||
## An id copied from a document is `unverified` until a search returns it
|
||||
|
||||
`winget search`, `brew search`, `apt-cache search`. Identifiers get renamed, forks get
|
||||
republished, and a mirror is not the vendor's build. The resolution is one command, and it is the
|
||||
difference between a record of what happened and a guess that worked once.
|
||||
|
||||
Two more things worth knowing before the install: WinDbg exists as a Store build and as the SDK's
|
||||
Debugging Tools (`cdb`/`kd`), and those are different command lines; on macOS a downloaded bundle
|
||||
carries a quarantine attribute, so verify the hash before removing it.
|
||||
|
||||
## "Installed" is not "available"
|
||||
|
||||
| Kind | What proves it works | What it does not prove |
|
||||
|---|---|---|
|
||||
| CLI | the version string **and** one real command on a fixture you control | that it parses *your* target without error |
|
||||
| GUI | it opened the sample and rendered a function list, witnessed by a human | that the analysis finished, or that the decompiler is licensed |
|
||||
| Kernel / driver | the second machine answered on the debug link | that the driver loads on this build |
|
||||
|
||||
A GUI-only tool is a request for a human, not an unavailable capability. A weaker CLI substitute
|
||||
is not the same capability, and a headless host cannot render the real one.
|
||||
|
||||
## When the tool is paid and you cannot pay
|
||||
|
||||
1. **Use the free implementation and record what it cannot do.** Ghidra's decompiler differs from
|
||||
Hex-Rays in readability, not in existence; "recovered with Ghidra, control flow verified by
|
||||
hand" is a real result.
|
||||
2. **Ask the requester to license it.** A procurement question with a lead time, not a technical
|
||||
blocker -- name the blocked route and its cost.
|
||||
3. **Narrow the deliverable** so the missing capability is not on the critical path.
|
||||
|
||||
## What to record
|
||||
|
||||
Per tool: class, version, absolute path, **the smoke test you ran**, and a label -- `observed`
|
||||
(you ran it), `inferred` (the install succeeded, you did not run it), `unverified` (someone told
|
||||
you it is there). Then re-run `doctor.py` and keep both outputs: their difference is the change
|
||||
you made to the experiment.
|
||||
Reference in New Issue
Block a user