06 - mmap and the process address space
06 - mmap 和 进程的地址空间
入侵进程的地址空间
1. 回顾
关于进程的第二课...
1.1. 新闻
...深度强化学习
Reinforce learning?
1.2. git init...
README.md / TODO.md..
git repo 的 初始化版本
通过 commit 进行状态的转移
everything is state machine...
1.3. 我们如何应对?
我们还得学 操作系统
操作系统依然很重要
编程语言是“可信可验证”的桥梁
Markdown,js,Python,...
操作系统是运行支撑
虚拟环境、文件系统快照、网络...
程序必须要到一个真实的环境...大语言模型终究会产生幻觉......
agent...
今天我们可以使用 docker...使用隔离机制...本地文件不受影响...
1.4. 状态机的生命周期管理 API
fork,execve 和 _exit
操作系统视角:状态机的复制、重置和删除
2. 进程的初始状态
我们可以创建进程...然后会进行执行...
2.1. 进程 execve 后的初始状态
更深层次的理解...
寄存器
直接进行打印
内存
有点难办
可以把任何整数 cast 成 pointer
32 位 整数 - 32 位 指针
用工具,看真实系统
暂时忽略操作系统管理的状态:pid,打开的文件...
进程空间里面的某些空间(绝大部分)是不能访问的...
那么 到底哪些可以访问???
所有一切都是有答案的!
没有黑魔法
向 AI 真诚发问...就会得到进步...
2.2. 结论
进程 execve 后的初始状态
ABI 中规定的 initial state (System V ABI)
Section 3.4: “Process Initialization”
只规定了部分寄存器和栈 (argv 和 envp 中的字符串保存在栈中)
Binary 中指定的 PT_LOAD 段
内存是分成 “一段一段” 的
每一段有访问权限 (rwx)
2.3. 进程的地址空间
配合 gdb 调试器,我们甚至可以 “随时查看程序的地址空间”。这一切代码都是人工智能生成的!因为 AI 知晓几乎所有的细节,它是帮助我们理解复杂细节的利器。
3. 进程的地址空间管理
3.1. 往后想一想
进程的初始状态
只有ELF 文件里声明的内存和一些操作系统分配的内存
任何其他指针的访问都是非法的
如果我们从输入读一个 size,然后 malloc(size)
内存从拿来呢?
一定有一个系统调用可以改变进程的地址空间
如果让你设计操作系统的 API
你会怎么设计?
3.2. Memory Map 系统调用
在状态机状态上增加/删除/修改一段可访问的内存
MAP_ANONYMOUS: 匿名 (申请) 内存
fd: 把文件 “搬到” 进程地址空间中 (例子:加载器)
更多的行为请参考手册 (复杂性暴增)
mmap 是一个非常强大的系统调用,用于将文件或设备的内存区域映射到进程的地址空间中。这允许进程像访问普通内存一样访问文件内容,而不需要显式地读写文件。
munmap 用于取消之前通过 mmap 创建的内存映射。
mprotect 用于修改已映射内存区域的保护属性。
我们可以用 pmap 命令查看进程的地址空间
(它是怎么实现的?)
3.3. 使用 mmap
Example 1: 申请大量内存空间
瞬间完成内存分配
mmap/munmap 为 malloc/free 提供了机制
libc 的大 malloc 会直接调用一次 mmap 实现
不妨 strace/gdb 看一下
Example 2: Everything is a file
映射大文件、只访问其中的一小部分
mmap 本质是一个 syscalls,用于将一个文件或设备的内存区域映射到进程的地址空间中。简单来说,它允许你像访问普通内存一样访问文件内容,而不需要显式地读写文件。
高效处理大文件
按需加载
减少 I/O 操作
高效内存分配
瞬间完成内存分配
操作系统不会真的分配内存
只是做一个映射?
AI:mmap 申请内存时,不会立即分配物理内存,只有在实际访问时才会分配,因此申请大量内存时非常高效
与 malloc 的关系
内存保护
设置保护属性
老师上课尽量多的进行了示例演示...
对于 mmap 的行为我自己的理解就是,在内存空间上 绑定一些 文件,通过记录文件路径...通过 AI 还需要注意的就是映射的回收 munmap
尽量多的学习 AI 的 best practice...当然有些 OI 竞赛的高血压代码 LLM 有可能也会输出...这时候要批判看待...
4. 入侵进程的地址空间
4.1. Hacking Address Space
进程 (状态机) 在 “无情执行指令机器” 上执行
状态机是一个封闭世界
但如果允许一个进程对其他进程的地址空间有访问权?
意味着可以任意改变另一个程序的行为
听起来就很 cool
例子:我们可以改变 gdb 或 其他编译程序的内部代码
可以让你获得开挂权?...
如下
“入侵” 进程地址空间的例子
调试器 (gdb)
gdb 可以任意观测和修改程序的状态
4.2. 物理入侵进程地址空间
金手指:直接物理劫持内存
听起来很离谱,但 “卡带机” 时代的确可以做到!
可以通过直接操作硬件来读取或修改内存内容
这种技术在现代系统中仍然存在,但通常需要特定的硬件支持或内核权限。

今天我们有 Debug Registers 和 Intel Processor Trace
调试寄存器是 CPU 提供的一种机制,用于支持调试功能。
Intel 处理器提供的一种硬件跟踪功能,可以记录程序的执行路径和内存访问情况。
帮助系统工具 “合法入侵” 地址空间
:通过调试器或性能分析工具,合法地访问和修改进程的地址空间。
4.3. 物理入侵进程地址空间
Game Genie: 一个 Look-up Table (LUT)

简单、优雅:当 CPU 读地址 a 时读到 x,则替换为 y
4.4. 随着游戏越来越大
地址空间太大了,分不清哪些才是玩家属性...
包含动态分配的内存,每次地址都不一样
思路:Everything is a state machine
观察状态机的 trace,就知道哪个是金钱了
查找 + Filter
进入游戏时 exp=4950exp=4950
打了个怪 exp=5100exp=5100
符合 4950→51004950→5100 变化的内存地址是很少的
好了,出门就是满级了
4.5. 脚本的开始...
如果有一天可以接触,也是蛮有意思的...
你只要认为一件事情可以干,这件事情就可以干下去,尽管这件事情网上没有先例,没有教程...
AI 会助你完成这一切...
4.6. “外挂”
采集视频信号
采集卡 (MS2130) + 树莓派 = 外挂
用魔法打败魔法
创造变得前所未有的容易
我能否用 FPGA 设计一个电路,收到视频流,以及来自 I/O 端口的 bound-box 绘图指令,把 bound-box 绘制到视频流上输出。
总的来说是发挥想象力...看你想得到什么,然后就可以实现,换个思路,也许就会改变人类的命运...
Last updated