扫描调用进程的内存
Posted
技术标签:
【中文标题】扫描调用进程的内存【英文标题】:scan memory of calling process 【发布时间】:2015-01-22 20:40:42 【问题描述】:我必须在 C 中空间。这是作业。我的问题是我不完全理解虚拟内存寻址。
我正在通过尝试读取和写入内存地址来扫描内存空间。我不能使用 proc 文件或任何其他方法。
所以我的问题是设置指针。
据我了解,“用户模式空间”从地址 0x0 开始,但是,如果我将函数的起点设置为 0x0,那么我不是在扫描当前进程的地址空间吗?您如何建议调整指针(如果有的话)以寻址父进程地址空间?
编辑:好的,很抱歉造成混乱,感谢您的帮助。我们不能使用 proc 文件系统,因为分配是为了让我们了解信号。
所以,基本上我将尝试读取然后写入每个内存页中的地址,以测试它是否为R
、RW
或不可访问。为了看看我是否成功,我将倾听某些信号——我还不确定如何去做那部分。我将创建一个结构链表来表示内存的可访问性。该程序将被编译为 32 位程序。
关于父进程和子进程:确切的文本状态
调用时,函数会扫描调用进程的整个内存区域...
也许我对孩子和父母的互动有误,因为我们已经在课堂上讨论过这个(fork 函数等),所以我假设我的函数将扫描一个父进程。我将要求教授澄清。
所以,从这张图片来看,我只是从 0x0 开始。
【问题讨论】:
进程的一个主要目的是隔离内存访问。父进程中的任何数据都不能在子进程中直接寻址。而且地址空间通常不会从 0 开始。如果是这样,那么不幸的是空指针是有效的,这使得涉及访问空指针的错误更难找到。 好吧,如果您不能“使用 proc 文件 或任何其他方法”(已添加重点),那么您将无法解决问题。您所做的任何事情都会构成 some 方法,即使是您自己设计的方法之一。我了解(我认为)您不允许访问/proc
文件系统中的文件,但可接受的解决方案的实际限制尚不清楚。
编辑您的问题以改进它!为什么不能使用/proc/
?
你确定明白老师对你的期望吗?您能否提供更多背景信息?
【参考方案1】:
从用户态进程的角度来看,它的地址 space 从地址 0x0
开始,但并非该空间中的每个地址都对进程有效或可访问。特别是,地址0x0
本身绝不是有效地址。如果一个进程试图访问实际上并未分配给该进程的内存(在其地址空间中),则会产生分段。
您实际上可以使用分段错误行为来帮助您确定地址空间的哪些部分实际上分配给了进程。为SIGSEGV
安装一个信号处理程序,然后跳过整个空间,尝试从每一页的某个地方读取一些内容。每次捕获 SIGSEGV 时,您都知道该页面未映射到您的进程。之后返回并扫描每个可访问的页面。
不过,只能阅读。不要尝试写入随机内存,因为程序可访问的大部分内存是程序本身及其使用的共享库的二进制代码。您不仅不想让程序崩溃,而且大部分内存可能被标记为进程只读。
编辑:一般来说,一个进程只能访问它自己的(虚拟)地址空间。然而,正如@cmaster 所观察到的,有一个系统调用(ptrace()
)允许一些进程在被观察进程的地址空间的上下文中访问其他一些进程的内存。这就是通用调试器通常的工作方式。
【讨论】:
@cmaster,很好。调试器使用ptrace()
访问子进程的内存(或者控制它们)。在某些情况下,进程也可以跟踪不是其子进程的其他进程。答案已编辑。【参考方案2】:
您可以(从您的程序中)读取/proc/self/maps
文件。首先在终端中尝试以下两个命令
cat /proc/self/maps
cat /proc/$$/maps
(至少要明白什么是地址空间)
然后阅读proc(5)、mmap(2),当然还有关于processes、address space、virtual memory、MMU、shared memory、VDSO的维基页面。
如果要在两个进程之间共享内存,请先阅读shm_overview(7)
如果你不能使用/proc/
(很遗憾)考虑mincore(2)
您也可以不可移植地尝试从某个地址读取(并可能使用volatile int*
重写相同的值)并捕获SIGSEGV
信号(在信号处理程序中使用sigsetjmp(3) ),并在-dichotomical-循环中执行此操作(以4Kbytes的倍数)-从一些合理的开始和结束地址(当然不是从0开始,但可能从(void*)0x10000
到(void*)0xffffffffff600000
)
见signal(7)。
您还可以使用特定于 Linux (Gnu libc) 的 dladdr(3)。还请查看ptrace(2)(应该经常从一些其他进程中使用)。
另外,您可以研究elf(5) 并阅读您自己的可执行文件ELF。通常它是/proc/self/exe
(符号链接),但您应该能够从您的main
的argv[0]
中获取它(也许约定您的程序应该以其完整路径名开始)。
注意ASLR 并在您的老师允许的情况下禁用它。
PS。我不知道你的老师对你有什么期望。
【讨论】:
问题指定不能使用“proc files”。 我改进了我的答案以考虑到这一点。老实说,我不懂老师。使用/proc/
更有启发性!
我同意,我不确定练习的目的是什么。
我同意整个过程看起来很奇怪,因为我在网上看到的所有内容都表明要以不同的方式进行。我应该了解信号,所以你关于non-portable
方法的段落似乎是正确的。谢谢。【参考方案3】:
这比乍看之下要困难一些。在 Linux 中,每个进程都有自己的内存空间。使用任意内存地址仅指向该进程的内存空间。然而,有一些机制允许一个进程访问另一个进程的内存区域。某些 Linux 功能允许使用此共享内存 功能。例如看看
this link 给出了在 Linux 下使用shmget
、shmctl
和其他系统调用的一些示例。也可以搜索mmap
系统调用,用于将文件映射到进程的内存中,也可以用于访问另一个进程的内存。
【讨论】:
我觉得我有点迂腐,但是如果系统正常工作,用户态进程永远可以访问另一个进程的地址空间。共享内存不会这样做:它会导致两个或多个进程的独立地址空间的一部分引用相同的内存,但每个进程仍然通过自己的地址空间访问该内存。特别是,给定的共享内存块的地址对于访问它的不同进程不一定相同。 @John Bollinger 是的。进一步澄清一点。例如在x86 系统,两个进程访问共享内存区域中的相同物理地址。 CPU 的分页机制用于将给定进程的一系列(所谓的虚拟)地址映射到一系列物理内存。两个不同的用户进程可以将不同的进程(虚拟)内存地址映射到相同的物理内存地址。以上是关于扫描调用进程的内存的主要内容,如果未能解决你的问题,请参考以下文章