gem-universe / blog

0 stars 0 forks source link

[操作系统]17. Linux进程的地址空间 #20

Open supergem3000 opened 6 months ago

supergem3000 commented 6 months ago

17. Linux 进程的地址空间 (jyywiki.cn)

Linux进程的地址空间

查看进程的地址空间 pmap 地址空间是若干连续的 “内存段”。“段” 的内存可以根据权限访问(只读、可读写、可执行等);不在段内/违反权限的内存访问 触发 SIGSEGV。 pmap是通过访问procfs(/proc/[pid]/maps)实现的。

进程地址空间管理

操作系统应该提供一个修改进程地址空间的系统调用。

// 映射一段内存
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: 可以用来申请内存 (MAP_ANONYMOUS),也可以把文件 “搬到” 进程地址空间中。

使用mmap 1、申请大量内存空间

#define GiB * (1024LL * 1024 * 1024)

int main() {
  volatile uint8_t *p = mmap(NULL, 8 GiB, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  printf("mmap: %lx\n", (uintptr_t)p);
  if ((intptr_t)p == -1) {
    perror("cannot map");
    exit(1);
  }
  *(p + 7 GiB) = 3;
  printf("Read get: %d\n", *(p + 7 GiB));
}

2、映射大文件,只访问其中一小部分

import mmap, hexdump
with open('/dev/sda', 'rb') as fp:
    mm = mmap.mmap(fp.fileno(),
                   prot=mmap.PROT_READ, length=128 << 30)
    hexdump.hexdump(mm[:512])

将某驱动器映射到内存,打印前512字节。(需要sudo)

如果把文件映射到内存,什么时候把内存修改写回文件? 立即生效会造成大量IO,定期生效可能会有丢失。需要看操作系统手册msync来了解这些。

入侵进程地址空间

一些例子:调试器(gdb)、profiler(perf)

入侵进程地址空间:金手指 卡带机时代,物理劫持内存。如果读内存地址a读到x时,替换成y。

新技术DMA外挂:Direct Memory Access(直接内存访问)技术,允许显卡等设备直接访问内存。利用这种技术使用特殊的软硬件修改内存实现外挂功能。

入侵进程地址空间:金山游侠 在进程内存中找到代表“金钱”、“生命”的重要属性并改掉。扫描进程所有内存,看哪里的值和金钱、生命等属性值一样,可以认为这段内存就是存的这个值,把它改掉。

入侵进程地址空间:按键精灵 大量重复固定的任务。给进程发送键盘、鼠标事件即可。可以做个假的硬件驱动等实现。

入侵进程地址空间:变速齿轮 调整游戏的逻辑更新速度。除了syscall是不能感知时间的。劫持和时间相关的syscall,改变程序对时间的认知。 等于直接修改了程序代码,借此原理可以针对游戏定制外挂,改掉原有逻辑。