# 06 - mmap and the process address space

入侵进程的地址空间

## 1. 回顾 <a href="#qjsgp" id="qjsgp"></a>

关于进程的第二课...

#### 1.1. 新闻 <a href="#q3uti" id="q3uti"></a>

...深度强化学习

Reinforce learning？

#### 1.2. git init... <a href="#pqbgh" id="pqbgh"></a>

README.md / TODO.md..

git repo 的 初始化版本

通过 commit 进行状态的转移

everything is state machine...

#### 1.3. 我们如何应对？ <a href="#vww3n" id="vww3n"></a>

**我们还得学 操作系统**

* 操作系统依然很重要
* 编程语言是“可信可验证”的桥梁
* * Markdown，js，Python，...
* 操作系统是运行支撑
* * 虚拟环境、文件系统快照、网络...

程序必须要到一个真实的环境...大语言模型终究会产生幻觉......

agent...

今天我们可以使用 docker...使用隔离机制...本地文件不受影响...

#### 1.4. 状态机的生命周期管理 API <a href="#ifso6" id="ifso6"></a>

**fork，execve 和 \_exit**

* 操作系统视角：状态机的复制、重置和删除

```
int pid = fork();
if (pid == -1) { // 错误
    perror("fork"); goto fail;
} else if (pid == 0) { // 子进程
    execve(...);
    perror("execve"); exit(EXIT_FAILURE);
} else { // 父进程
    ...
    int status;
    waitpid(pid, &status, 0); // testkit.c 中有
}
```

## 2. 进程的初始状态 <a href="#pkonp" id="pkonp"></a>

我们可以创建进程...然后会进行执行...

#### 2.1. 进程 execve 后的初始状态 <a href="#wufhh" id="wufhh"></a>

更深层次的理解...

**寄存器**

* 直接进行打印

**内存**

* 有点难办
* * 可以把任何整数 cast 成 pointer
* * * 32 位 整数 - 32 位 指针
* * 用工具，看真实系统

暂时忽略操作系统管理的状态：pid，打开的文件...

进程空间里面的某些空间（绝大部分）是不能访问的...

那么 到底哪些可以访问？？？

* 所有一切都是有答案的！
* 没有黑魔法

向 AI 真诚发问...就会得到进步...

#### 2.2. 结论 <a href="#e8-bf-9b-e7-a8-8b-execve-e5-90-8e-e7-9a-84-e5-88-9d-e5-a7-8b-e7-8a-b6-e6-80-81-1" id="e8-bf-9b-e7-a8-8b-execve-e5-90-8e-e7-9a-84-e5-88-9d-e5-a7-8b-e7-8a-b6-e6-80-81-1"></a>

**进程 execve 后的初始状态**

* ABI 中规定的 initial state ([System V ABI](https://jyywiki.cn/OS/manuals/sysv-abi.pdf))
* * Section 3.4: “Process Initialization”
  * 只规定了部分寄存器和栈 (argv 和 envp 中的字符串保存在栈中)
* Binary 中指定的 PT\_LOAD 段
* * 内存是分成 “一段一段” 的
  * 每一段有访问权限 (rwx)

#### 2.3. 进程的地址空间 <a href="#t68ve" id="t68ve"></a>

配合 gdb 调试器，我们甚至可以 “随时查看程序的地址空间”。这一切代码都是人工智能生成的！因为 AI 知晓几乎所有的细节，它是帮助我们理解复杂细节的利器。

```
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec6/address-space# ./alloc
mmap: 7fd2c4e88000
Read get: 2
Read get: 0
Read get: 3
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec6/address-space# ./mmap-demo
This is allocated memory at 0x7fe150f8a000
Mapped executable at 0x7fe150ec0000, size: 823704 bytes
First 16 bytes of executable: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec6/address-space# ./simple
```

## 3. 进程的地址空间管理 <a href="#mibjy" id="mibjy"></a>

#### 3.1. 往后想一想 <a href="#meagk" id="meagk"></a>

**进程的初始状态**

* 只有**ELF 文件里声明的**内存和一些操作系统分配的内存
* * 任何其他指针的访问都是非法的
  * 如果我们从输入读一个 size，然后 malloc(size)
* * * 内存从拿来呢？

**一定有一个系统调用可以改变进程的地址空间**

如果让你设计操作系统的 API

* 你会怎么设计？

#### 3.2. Memory Map 系统调用 <a href="#h0si7" id="h0si7"></a>

**在状态机状态上增加/删除/修改一段可访问的内存**

* MAP\_ANONYMOUS: 匿名 (申请) 内存
* fd: 把文件 “搬到” 进程地址空间中 (例子：加载器)
* 更多的行为请参考手册 (复杂性暴增)

```
// 映射
void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);
int munmap(void *addr, size_t length);

// 修改映射权限
int mprotect(void *addr, size_t length, int prot);
```

* mmap 是一个非常强大的系统调用，用于将文件或设备的内存区域映射到进程的地址空间中。这允许进程像访问普通内存一样访问文件内容，而不需要显式地读写文件。
* munmap 用于取消之前通过 mmap 创建的内存映射。
* mprotect 用于修改已映射内存区域的保护属性。
* 我们可以用 pmap 命令查看进程的地址空间
* * (它是怎么实现的？)

#### 3.3. 使用 mmap <a href="#wcfwr" id="wcfwr"></a>

**Example 1: 申请大量内存空间**

* 瞬间完成内存分配
* * mmap/munmap 为 malloc/free 提供了机制
  * libc 的大 malloc 会直接调用一次 mmap 实现
* 不妨 strace/gdb 看一下

**Example 2: Everything is a file**

* 映射大文件、只访问其中的一小部分

```
# 打开文件
with open('/dev/sda', 'rb') as fp:
    # 映射文件
    mm = mmap.mmap(fp.fileno(),
                   prot=mmap.PROT_READ, length=128 << 30)
    # 打印文件前 512 字节
    hexdump.hexdump(mm[:512])
```

mmap 本质是一个 syscalls，用于将一个文件或设备的内存区域映射到进程的地址空间中。简单来说，它允许你像访问普通内存一样访问文件内容，而不需要显式地读写文件。

* 高效处理大文件
* * 按需加载
  * 减少 I/O 操作
* 高效内存分配
* * 瞬间完成内存分配
* * * 操作系统不会真的分配内存
    * 只是做一个映射？
    * AI：mmap 申请内存时，不会立即分配物理内存，只有在实际访问时才会分配，因此申请大量内存时非常高效
* * 与 malloc 的关系
* 内存保护
* * 设置保护属性

老师上课尽量多的进行了示例演示...

对于 mmap 的行为我自己的理解就是，在内存空间上 绑定一些 文件，通过记录文件路径...通过 AI 还需要注意的就是映射的回收 munmap

尽量多的学习 AI 的 best practice...当然有些 OI 竞赛的高血压代码 LLM 有可能也会输出...这时候要批判看待...

## 4. 入侵进程的地址空间 <a href="#asgaw" id="asgaw"></a>

#### 4.1. Hacking Address Space <a href="#g6ilu" id="g6ilu"></a>

**进程 (状态机) 在 “无情执行指令机器” 上执行**

* 状态机是一个封闭世界
* **但如果允许一个进程对其他进程的地址空间有访问权**？
* * 意味着可以任意改变另一个程序的行为
* * * 听起来就很 cool
* * 例子：我们可以改变 gdb 或 其他编译程序的内部代码
* * * 可以让你获得开挂权？...
    * 如下

**“入侵” 进程地址空间的例子**

* 调试器 (gdb)
* * gdb 可以任意观测和修改程序的状态

#### 4.2. 物理入侵进程地址空间 <a href="#juhur" id="juhur"></a>

**金手指：直接物理劫持内存**

* 听起来很离谱，但 “卡带机” 时代的确可以做到！
* * 可以通过直接操作硬件来读取或修改内存内容
  * 这种技术在现代系统中仍然存在，但通常需要特定的硬件支持或内核权限。

![](https://cdn.nlark.com/yuque/0/2025/webp/44785005/1743562565530-7b0b0e1c-fefb-4ad3-b1d5-d4845ec1fc44.webp)

* 今天我们有 Debug Registers 和 [Intel Processor Trace](https://perf.wiki.kernel.org/index.php/Perf_tools_support_for_Intel%C2%AE_Processor_Trace)
* * 调试寄存器是 CPU 提供的一种机制，用于支持调试功能。
  * Intel 处理器提供的一种硬件跟踪功能，可以记录程序的执行路径和内存访问情况。
* 帮助系统工具 “合法入侵” 地址空间
* * ：通过调试器或性能分析工具，合法地访问和修改进程的地址空间。

#### 4.3. 物理入侵进程地址空间 <a href="#ucazf" id="ucazf"></a>

**Game Genie: 一个 Look-up Table (LUT)**

![](https://cdn.nlark.com/yuque/0/2025/webp/44785005/1743562834737-49f28483-06f4-4021-a35b-cb8077596993.webp)

* 简单、优雅：当 CPU 读地址 *a* 时读到 *x*，则替换为 *y*
* * [Technical Notes](https://tuxnes.sourceforge.net/gamegenie.html) ([专利](https://patents.google.com/patent/EP0402067A2/en), [How did it work?](https://www.howtogeek.com/706248/what-was-the-game-genie-cheat-device-and-how-did-it-work/))

#### 4.4. 随着游戏越来越大 <a href="#ofv2d" id="ofv2d"></a>

**地址空间太大了，分不清哪些才是玩家属性...**

* 包含动态分配的内存，每次地址都不一样
* 思路：**Everything is a state machine**
* * 观察状态机的 trace，就知道哪个是金钱了

**查找 + Filter**

* 进入游戏时 exp=4950exp=4950
* 打了个怪 exp=5100exp=5100
* 符合 4950→51004950→5100 变化的内存地址是**很少**的
* * 好了，出门就是满级了

#### 4.5. 脚本的开始... <a href="#c6p4s" id="c6p4s"></a>

如果有一天可以接触，也是蛮有意思的...

你只要认为一件事情可以干，这件事情就可以干下去，尽管这件事情网上没有先例，没有教程...

AI 会助你完成这一切...

#### 4.6. “外挂” <a href="#cju3k" id="cju3k"></a>

**采集视频信号**

* 采集卡 ([MS2130](https://jyywiki.cn/OS/manuals/MS2130.pdf)) + 树莓派 = 外挂

**用魔法打败魔法**

* 创造变得前所未有的容易

我能否用 FPGA 设计一个电路，收到视频流，以及来自 I/O 端口的 bound-box 绘图指令，把 bound-box 绘制到视频流上输出。

总的来说是发挥想象力...看你想得到什么，然后就可以实现，换个思路，也许就会改变人类的命运...
