内存中进程的实际起始地址/W32调试API

Real Starting Address Of A Process in Memory / Win32 Debug APIs

本文关键字:地址 W32 调试 API 进程 内存      更新时间:2023-10-16

起初,我是c++和调试的新手。我使用带有DEBUG_ONLY_THIS_PROCESS参数的CreateProcess api,然后等待CREATE_PROCESS_DEBUG_EVENT。收到后,我检查Eip寄存器以获得点的地址。我认为这一点是Main函数的地址。

为了验证这个想法,我使用ollydbg来查看exe的起始地址。但这和我的不一样。我在调试api中找到的是0x77a364d8,但olly说它是0x00401000。然后我没有停下来,检查olly中的地址0x77a364d8。我找到了地址并在那里设置了一个断点。

然后我重新加载olly,看到olly首先进入0x77a364d8地址并加载进程,然后进入0x00401000地址并在那里等待。0x77a364d8地址指向一些ntdll函数,以便将进程加载到内存中,如我所见。

如果这是真的,我如何通过代码(c++,我是一个新手,请交叉t:)获得0x00401000地址,它是Main函数的地址还是什么?

收到CREATE_PROCESS_DEBUG_EVENT后,您应该能够访问联合的CREATE_PROCESS_DEBUG_INFO成员。它有一个名为lpStartAddress的成员。

您的调试事件循环应该类似于:

DWORD dwContinueDebugStatus = DBG_CONTINUE;
while(dwContinueDebugStatus)
{
DEBUG_EVENT debugEvt;
WaitForDebugEvent(&debugEvt, INFINITE);
switch(debugEvt.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
// Grab the main thread entry point.
LPTHREAD_START_ROUTINE exentry = debugEvt.u.CreateProcessInfo.lpStartAddress;
break;
/* Handle the rest of your debug events here. */
}
ContinueDebugEvent(debugEvt.dwProcessId, debugEvt.dwThreadId, dwContinueDebugStatus);
}

编辑:有几件事我忘了提。。。

通过这些方法中的任何一种获得入口点都可能是调用main()的CRT函数。在使用dbghelp.dll时,没有可靠的方法可以在不进行符号查找的情况下获得main()

此外,John Robbins的《调试应用程序》一书中有一章介绍了如何使用一些示例代码创建一个小型调试器。这可能是我找到的最好的文档/示例(但我希望它更好)。它可以很便宜,所以可能值得一看。

入口点将而不是(至少在正常情况下)与main相同。入口点的签名是void entrypoint(void);。这必须检索命令行,将其解析为单独的参数等,为调用main做准备(在GUI程序中调用WinMain之前,有一个完全独立的命令行可以检索相当不同的"东西")。

如果您想要main的实际地址,您可能至少需要尝试使用SymFromName作为名称_main和/或_wmain(或者,如果您可能正在处理GUI程序,WinMain/wWinmain),以获得真正属于目标程序的代码,而不是来自库模块的代码,几乎没有人见过。

这都来自内存,因此可能包含一些错误。

为了在新进程中找到EXE的入口点地址,您需要读取该进程的PEB字段ImageBaseAddress。PEB总是在一个固定的地址,但这取决于你的EXE是32位还是64位,你必须事先确定(WOW64有一个32位的PEB,但我认为它可能还没有初始化)。

请注意,您不能仅从EXE中获取此文件,因为它可能会由于ASLR而被重新定位。一旦有了这个,就可以使用ReadProcessMemory读取EXE的PE头,并从IMAGE_OPTIONAL_HEADER结构中获取AddressOfEntryPoint字段。这是一个RVA,所以把它添加到前面找到的基地址中,瞧,你就有了入口点地址。