EnumProcessModulesEx and CreateToolhelp32Snapshot

2019-03-05 17:48发布

问题:

Edit:

The answer of this question is here:

https://stackoverflow.com/a/27317947/996540

When you create a project in msvc, the option /DYNAMICBASE is default enabled now. Because of ASLR(Address space layout randomization, since Windows Vista), everytime you run an exe, it's load address is random.

I am doing the DLL injection job recently, so I did some research into it on google, and have read some projects. Get the load address (base address) of an exe is important.

It seems there're two simple APIs to do this: EnumProcessModulesEx and CreateToolhelp32Snapshot. But I never succeeded.

So this is the code sample:

void TestEnumProcessModulesEx(const char* app)
{
    std::cout << "Begin TestEnumProcessModulesEx(" << mybit() << ")" << std::endl;

    STARTUPINFOA startupInfo = {0};
    startupInfo.cb = sizeof(startupInfo);
    PROCESS_INFORMATION processInformation = {0};

    if (CreateProcessA(app, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation))
    {
        std::vector<HMODULE> buf(128);
        DWORD needed = 0;
        for (;;) {
            if (EnumProcessModulesEx(processInformation.hProcess, &buf[0], DWORD(buf.size()*sizeof(HMODULE)), &needed, LIST_MODULES_ALL) == FALSE) {
                DWORD ec = GetLastError();
                std::cout << "GetLastError() = " << ec << std::endl;
                break;
            }
            else if (needed <= buf.size() * sizeof(HMODULE)) {
                break;
            }
            else {
                const size_t oldSize = buf.size();
                buf.resize(oldSize * 2);
            }
        }
        ResumeThread(processInformation.hThread);
        WaitForSingleObject(processInformation.hProcess, INFINITE);
    }

    std::cout << "End TestEnumProcessModulesEx(" << mybit() << ")" << std::endl;
}

To reduce the length of this Question, the complete code - including the CreateToolhelp32Snapshot's test code - is not listed here, but you can get it from:

https://dl.dropboxusercontent.com/u/235920/enum_proc_mods_sample.7z or https://www.mediafire.com/?cry3pnra8392099

"If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process. If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299)." - from MSDN.

And this is a blog post about this question: http://winprogger.com/getmodulefilenameex-enumprocessmodulesex-failures-in-wow64/

Unfortunately, this does not make sence, because whatever the specified process is 32bit or 64bit, it fails with 299; whatever the caller process is 32-bit or 64bit, it fails with 299.

This is the output of my sample:

Begin TestEnumProcessModulesEx(32bit)
GetLastError() = 299
hello world 32bit
End TestEnumProcessModulesEx(32bit)

Begin TestEnumProcessModulesEx(32bit)
GetLastError() = 299
hello world 64bit
End TestEnumProcessModulesEx(32bit)

Begin TestEnumProcessModulesEx(64bit)
GetLastError() = 299
hello world 32bit
End TestEnumProcessModulesEx(64bit)

Begin TestEnumProcessModulesEx(64bit)
GetLastError() = 299
hello world 64bit
End TestEnumProcessModulesEx(64bit)

As you see, any combination is failed.

My OS is Windows 7 64bit pro and my compiler is VS2013.

So, what can I do ?

回答1:

I have no idea about the unsuccess of EnumProcessModulesEx and CreateToolhelp32Snapshot, let's leave this question to the expert.

My goal is to get the load address (base address) of the child process, find the entry point and patch it - the reason to patch the entry point is here: https://opcode0x90.wordpress.com/2011/01/15/injecting-dll-into-process-on-load/

Since DLL injection is the main purpose of mine, I have to reconsider this question. I would use the "CreateRemoteThread & LoadLibrary Technique" http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces#section_2 to do the DLL injection (In fact ASLR is not the barrier of this technique by the way), Although there are so many limits in DLLMain http://msdn.microsoft.com/en-us/library/windows/desktop/dn633971%28v=vs.85%29.aspx , but do a little works is OK: Find the base address of an exe using GetModuleHandleA(NULL), save the HMODULE returned into shared memory, next, the caller process read shared memory and get the HMODULE. Synchronization mechanism is necessary of course.

So, the answer is IPC. (not every IPC mechanism is safe in DLLMain by the way)