06 - 程序与进程;进程管理 API [2025 南京大学操作系统原理]

[00:00:00]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

大家好!我是姜艳艳,欢迎来到《操作系统原理》的第六课!上节课我们聊了 forkexecveexit,搞清楚了进程如何创建和运行。今天我们要深入进程的地址空间,聚焦 mmap 系统调用,探索如何管理内存,甚至“入侵”其他进程的地址空间!就像我常说的,“一切都是状态机,地址空间就是状态机的内存舞台!” 这节课我会带你们从进程的初始状态入手,理解 mmap 的魔法,还会分享一些系统黑客的趣事,让你们感受到操作系统的无限可能。

我会从 execve 后的初始状态讲起,剖析 mmap 的功能,用代码和调试工具展示内存映射的奥秘,最后聊聊如何利用地址空间做有趣的事情。内容整理自字幕,保留了我的原话风格,修正了错别字,补充了逻辑和例子,用 Markdown 写成博客,方便你复习。准备好进入内存的奇妙世界了吗?咱们开始吧!


1. 复习:进程与地址空间的起点

[00:00:00]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

进程
状态机(寄存器+内存)
execve(重置状态)
初始地址空间(代码/数据/堆/栈)
mmap(修改地址空间)
分配内存/映射文件

图示说明:进程是一个状态机,execve 重置状态,初始化地址空间(包含代码、数据、堆、栈),mmap 修改地址空间,分配内存或映射文件。

上节课我们学了 fork 复制状态机,execve 重置状态机,exit 销毁状态机。fork 像水果叉,分裂出两个进程,寄存器和内存一模一样;execve 加载新程序,传参 argvenvp,从 main 开始运行。今天我们聚焦地址空间,这是进程内存的舞台。“execve 后的初始状态是什么?哪些内存可以访问?这些问题我们今天都会解开!”

补充:问 AI,“进程地址空间是什么?” 它会解释,地址空间是进程的虚拟内存范围,包含代码、数据、堆、栈等,由操作系统管理。


2. 进程地址空间的初始状态

[00:10:13]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

execve(初始状态)
寄存器(PC=entry point)
地址空间(内存布局)
代码段(只读)
数据段(读写)
堆(动态分配)
栈(高地址)
VDSO/VDMA(系统共享)

图示说明execve 初始化进程状态,寄存器 PC 指向 ELF 文件的入口点,地址空间包含代码段、数据段、堆、栈,以及系统共享的 VDSO/VDMA 区域。

寄存器的初始状态

[00:10:32]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:10:32]~[00:11:02]

execve 后,寄存器是什么样?” 我们可以用 GDB 的 starti 命令,在程序第一条指令前暂停,打印寄存器。关键是程序计数器(PC),它指向 ELF 文件的入口点(entry point)。用 readelf -h 查看 ELF 文件,入口点地址(如 0x401620)会出现在 Entry point address 字段。

例子

readelf -h simple
# 输出:Entry point address: 0x401620
gdb simple
(gdb) starti
(gdb) info registers
# PC 应为 0x401620

地址空间的内存布局

[00:11:02]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:11:02]~[00:33:17]

“内存是个大字节数组,地址空间是进程的舞台!” 32 位系统有 2³² 字节,64 位有 2⁶⁴ 字节,但大部分地址是“红区”(不可访问)。execve 初始化地址空间,包含:

  • 代码段:只读,存储程序指令(如 main 函数)。
  • 数据段:读写,存储全局变量。
  • :动态分配(如 malloc)。
  • :高地址,存储局部变量和函数调用。
  • VDSO/VDMA:操作系统共享的只读区域,存储系统信息(如时间、CPU 编号)。

例子:运行 simple.c

char arr[10 * 1024 * 1024]; // 10MB 数据
int main() { return 0; }

用 GDB 查看:

gdb simple
(gdb) starti
(gdb) info proc mappings

输出显示代码段(只读)、数据段(10MB,读写)、栈(高地址)、VDSO(系统共享)等。

细节:VDSO(Virtual Dynamic Shared Object)避免频繁系统调用,直接读系统状态(如时间)。VDMA 是类似机制,优化性能。


3. mmap:改变地址空间的魔法

[00:40:31]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

mmap(系统调用)
分配内存(匿名映射)
映射文件(文件映射)
指定大小(读写权限)
文件描述符(只读/读写)
共享内存(父子进程)
可执行文件(加载器)

图示说明mmap 修改地址空间,支持匿名映射(分配内存)和文件映射(映射文件)。匿名映射可创建共享内存,文件映射可加载可执行文件。

mmap 的基本功能

[00:42:27]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:42:27]~[00:45:27]

mmap 是地址空间的魔法师!” 它修改进程的内存映射,分配新内存或映射文件。基本用法:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr:指定映射起始地址(通常设为 NULL,让内核选择)。
  • length:映射大小。
  • prot:保护权限(PROT_READPROT_WRITEPROT_EXEC)。
  • flags:映射类型(MAP_PRIVATE 私有、MAP_SHARED 共享、MAP_ANONYMOUS 匿名)。
  • fd:文件描述符(匿名映射设为 -1)。
  • offset:文件偏移量。

例子:分配 4KB 内存:

#include <sys/mman.h>
#include <stdio.h>
void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) perror("mmap failed");

匿名映射:动态分配内存

[00:43:35]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:43:35]~[00:45:27]

“匿名映射像 malloc,但更灵活!” 它分配内存,无需关联文件,常用于堆扩展或共享内存。

例子:父子进程共享内存(参考 testkit):

void *buf = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (fork() == 0) {
    strcpy(buf, "Child output");
} else {
    wait(NULL);
    printf("Parent reads: %s\n", buf);
}

子进程写入共享内存,父进程读取。

文件映射:内存即文件

[00:45:27]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:45:27]~[01:05:12]

“文件是字节序列,内存也是字节序列,mmap 直接把文件搬进内存!” 它映射文件内容到地址空间,省去 read 操作。

例子:映射可执行文件:

#include <sys/mman.h>
#include <fcntl.h>
int fd = open("simple", O_RDONLY);
struct stat st;
fstat(fd, &st);
void *p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
printf("ELF magic: %x\n", *(int *)p); // 打印 0x464c457f

细节:映射可执行文件是加载器的核心,后面会详讲。


4. 观察与调试地址空间

[00:46:53]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

调试工具
GDB(info proc mappings)
pmap(/proc/PID/maps)
state_dump(自定义GDB插件)
查看内存映射
解析maps文件
可视化寄存器+内存

图示说明:用 GDB、pmap 和自定义 state_dump 插件观察地址空间。GDB 查看内存映射,pmap 解析 /proc/PID/mapsstate_dump 提供可视化输出。

pmap 与 /proc 文件系统

[00:47:19]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:47:19]~[00:54:30]

pmap 揭秘地址空间!” 它读取 /proc/PID/maps,显示进程的内存映射。

例子

pmap 29602
# 输出:fish 进程的映射,包括 libgcc、libc 等库

strace pmap 29602 确认它打开 /proc/29602/maps,解析后输出。

自定义 GDB 插件:state_dump

[00:17:39]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[00:17:39]~[01:05:12]

“我用 AI 写了 state_dump 插件,秒变可视化调试器!” 它扩展 GDB,输出寄存器和内存映射到 Markdown。

例子

gdb simple
(gdb) source state_dump.py
(gdb) state_dump
# 输出:寄存器(16 进制/10 进制)、内存映射表格

自动模式

(gdb) auto_state_dump
# 每次暂停(断点/单步)自动输出

细节:AI 生成的插件用 info proc mappings 获取内存映射,格式化输出。调试 mmap 示例时,确认 4KB 内存和文件映射正确添加。


5. 入侵进程地址空间:系统黑客的乐趣

[01:05:29]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

入侵地址空间
ptrace(poke/peek)
/proc/PID/mem
process_vm_writev
GDB(修改变量)
游戏修改器(金山游侠)
批量写内存

图示说明:入侵地址空间的工具包括 ptrace(读写内存)、/proc/PID/mem(文件式访问)、process_vm_writev(批量写)。GDB 用 ptrace,金山游侠用 /proc/PID/mem

游戏作弊器的历史

[01:07:33]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[01:07:33]~[01:17:57]

“想玩游戏又不想被虐?作弊器来帮忙!” 早期卡带主机的作弊器(如 Game Genie)通过硬件劫持 ROM,替换内存值(如生命值从 10 改 100)。

例子:Game Boy 作弊码 00594CB31 使玩家无敌。它修改指令或数据的立即数。

金山游侠:软件入侵

[01:17:57]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[01:17:57]~[01:25:10]

“金山游侠是童年神器!” 它用 /proc/PID/mem 读写进程内存,动态修改游戏变量(如金钱)。

例子:修改虚拟机中的游戏:

# 游戏显示金钱 5000
./modifier 51213 5000  # 扫描 PID 51213,找到值 5000 的地址
# 花钱到 4400
./modifier 51213 4400  # 再次扫描,缩小范围到 3 个地址
# 修改为 123456789
./modifier 51213 123456789

游戏金钱变为 123456789!

细节:通过 lseekread/write 操作 /proc/PID/mem,实现内存扫描和修改。

ptrace 与 process_vm_writev

[01:24:44]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[01:24:44]~[01:26:29]

ptrace 是调试神器!” 它提供 PTRACE_POKEDATAPTRACE_PEEKDATA,读写进程内存,GDB 依赖它。process_vm_writev(Linux 3.2 引入)支持批量写内存,适合复杂场景。

补充:问 AI,“ptrace 如何实现调试?” 它会解释 ptrace 的跟踪和修改功能。


6. 创意与未来:从 mmap 到 DMA 外挂

[01:26:29]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

创意应用
DMA外挂(物理内存劫持)
视频外挂(FPGA+AI)
高带宽内存拷贝
HDMI视频分析
模式识别(红框标注)

图示说明mmap 启发创意,如 DMA 外挂(拷贝物理内存)和视频外挂(用 FPGA 和 AI 分析 HDMI 信号,标注目标)。

DMA 外挂:现代作弊

[01:27:13]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[01:27:13]~[01:28:47]

“DMA 外挂防不胜防!” 它通过硬件设备直接读写物理内存,绕过操作系统检测。

例子:DMA 设备将游戏内存拷贝到独立存储,解析后修改变量(如生命值)。

视频外挂:AI 与 FPGA

[01:28:47]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]
[01:28:47]~[01:32:03]

“用 AI 做视频外挂,酷到炸!” HDMI 信号通过采集卡(如 MS2130)输入树莓派或 FPGA,AI 识别目标(敌人),在视频上叠加红框。

例子:射击游戏外挂:

  1. HDMI 输出到 FPGA。
  2. FPGA 分流信号:一路 USB 送电脑,AI 分析;一路叠加红框后输出。
  3. 延迟约 100ms,但效果显著。

细节:AI 可调用大模型(如 Claude 3.7)优化代码,FPGA 用 Verilog 实现信号处理。


7. 总结与展望

[01:32:03]-[G:\姜艳艳操作系统操作空间\output\字幕\6\06 - mmap 和进程的地址空间;入侵进程的地址空间 [2025 南京大学操作系统原理].mp4]

mmap 让地址空间随心所欲,入侵地址空间开启无限可能!” 从 execve 的初始状态到 mmap 的动态修改,再到 ptrace/proc/PID/mem 的黑客玩法,操作系统是创意的舞台。“用 mmap 写个加载器,试试金山游侠的原理,问 AI 如何优化 DMA 外挂!保持好奇,计算机世界没有魔法,只有你想不到的可能!”

我的期望:动手写 mmap 代码,调试地址空间,探索 System V ABI!下节课我们聊加载器和可执行文件,揭秘程序启动的最后拼图!


参考资料

这篇博客带你掌握地址空间的魔法,希望你爱上操作系统的自由!有问题随时邮件我,或在 QQ 群讨论。让我们用代码和创意,征服系统世界!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐