Winapi 如何定位流程';Win32中的全局和堆栈区域?

Winapi 如何定位流程';Win32中的全局和堆栈区域?,winapi,process,multithreading,stack,globals,Winapi,Process,Multithreading,Stack,Globals,如何定位Win32进程的哪些内存区域包含每个线程的全局数据和堆栈数据 获取您感兴趣的内存区域中分配的变量的地址。当你有地址时,你如何处理它们完全是另一个问题 您还可以objdump-h(我认为它是-h,可能是-x)列出节地址,包括数据节 据我所知,没有API可以做到这一点。但是,如果进程中有一个DLL,那么在创建每个线程时,将收到DLL\u进程\u附加/DLL\u线程\u附加通知。当您收到这些通知时,您可以记录该线程的线程ID和堆栈对象的地址,因为您将在新线程上被调用。因此,将线程id和堆栈地址

如何定位Win32进程的哪些内存区域包含每个线程的全局数据和堆栈数据

获取您感兴趣的内存区域中分配的变量的地址。当你有地址时,你如何处理它们完全是另一个问题

您还可以
objdump-h
(我认为它是-h,可能是-x)列出节地址,包括数据节

据我所知,没有API可以做到这一点。但是,如果进程中有一个DLL,那么在创建每个线程时,将收到DLL\u进程\u附加/DLL\u线程\u附加通知。当您收到这些通知时,您可以记录该线程的线程ID和堆栈对象的地址,因为您将在新线程上被调用。因此,将线程id和堆栈地址存储在您当时创建的某个表中。不要试图在DllMain中做很多工作,只需记录堆栈位置并返回

然后,您可以使用get将每个线程堆栈上的变量地址转换为虚拟分配范围,该范围应为您提供堆栈的基址(请记住,堆栈从高地址增长到低地址)。堆栈的默认分配大小为1Mb,但这可以由链接器开关或线程创建者覆盖,但堆栈必须是连续的。因此,您从
VirtualQuery
返回的将是该时间点的完整堆栈

至于堆位置-堆可以有多个位置,但一般来说,如果要假设一个连续的堆位置,则使用获取堆对象的地址,然后使用
VirtualQuery
确定堆的该部分的页面范围

或者,您可以在hModule上为EXE和每个DLL使用
VirtualQuery
。然后你可以假设任何读写的东西,而不是堆栈或模块,都是堆的一部分。请注意,这在大多数进程中都是正确的,但在某些进程中可能不是正确的,因为应用程序可以直接调用
VirtualAlloc
CreateFileMapping
,从而生成非堆栈或堆的有效数据指针。 用于获取加载到进程中的模块列表


VirtualQuery基本上采用随机地址,并返回该地址所属页面集合的基址以及页面保护。因此,从一个特定的指针开始选择分配的“类型”是很好的

全球数据

我假设“全局”是指所有未使用new、malloc、HeapAlloc、VirtualAlloc等动态分配的数据,这些数据可以在源代码中声明,但不在函数和类定义的范围内

您可以通过将每个DLL作为PE文件加载到PE文件读取器中,并确定.data和.bss节的位置(对于不同的编译器,它们可能有不同的名称)来定位这些DLL。您需要为每个DLL执行此操作。这将为每个DLL提供此数据的一般位置。然后,如果您有调试信息,或者没有调试信息,则可以使用映射文件将DLL地址映射到调试信息/mapfile信息,以获取每个变量的名称和确切位置

您可能会发现帮助您执行此任务的代码比自己编写查询PE文件的代码要容易得多

线程堆栈

使用ToolHelp32(如果在Windows NT 4上,则使用PSAPI库)枚举应用程序中的线程。对于每个线程,获取线程上下文并读取ESP寄存器(x64的RSP)。现在对从每个上下文读取的ESP/RSP寄存器中的地址进行虚拟查询。该地址周围的1MB(默认值)区域(从mbi.AllocationBase开始,向上工作1MB)是堆栈位置。请注意,堆栈大小可能不是1MB,如果您愿意,可以从启动线程的DLL/EXE的PE头中查询


编辑,修复我交换了一些注册名的打字错误,谢谢@interjay

你是指ESP而不是EIP吗?@interjay。哎呀!是的。ESP/RSP而不是EIP/RIP。编辑了这篇文章以便修改。谢谢你的拯救。