调试.DLL注入问题 - 假定执行代码未被命中的断点

时间:2017-07-05 02:54:09

标签: c++ qt debugging dll dll-injection

我编写了一个程序(.DLL),它将被注入process.exe。

DLL注入器代码:

Bool InjectDll(DWORD pID, const char* dllPath) {
    Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
    if (!Proc)
    {
        return false;
    }
    void* LoadLibAddr = (void*)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    void* RemoteString = (void*)VirtualAllocEx(Proc, NULL, strlen(dllPath), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(Proc, (LPVOID)RemoteString, dllPath, strlen(dllPath), NULL);
    HANDLE ret = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, (LPVOID)RemoteString, CREATE_SUSPENDED, NULL);
    if (ret) {
        return true;
    }
}

要注入的.DLL的DllMain()函数:

#include <Windows.h>

extern void vMain();

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
    )
{
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&vMain, 0, 0, 0);
        return true;
    }
    return false;
}

VMAIN:

void vMain() {
    CreateConsole();        
    std::cout << "vMain() has executed!\n";
}

当我在visual studio中编译时,要注入的.DLL工作正常,但是当我在QT Creator中编译时,vMain()永远不会被执行。注入器,.DLL和目标进程都是32位。所以我尝试通过使用CreateRemoteThread()标志调用.DLL注入器调用CREATE_SUSPENDED来调试目标进程,这样我就可以在LoadLibraryA()上设置断点,恢复线程,逐步完成从断点执行,并查看返回值。但是,LoadLibraryA()上的断点没有被击中。

所以我调试了.DLL注入器应用程序以确保正在创建远程线程。我确认通过在GetThreadID()的返回值上调用CreateRemoteThread(),输出它,并在目标进程的线程列表中查看该线程:

ThreadList

请记住线程仍然处于暂停状态。经过进一步检查,EIP指向_RtlUserThreadStart()中的第一条指令。我在这条指令上设置了一个断点。然后我通过从我的.DLL注入器程序中调用ResumeThread()来恢复被挂起的线程。断点没有被击中。

值得注意的是,目标应用程序没有任何反断点机制,除了这个实例,断点对我来说还没有用。

那我怎么弄清楚问题是什么?有没有理由我的断点没被击中?有没有更好的方法来调试问题?

1 个答案:

答案 0 :(得分:0)

从DLL内部执行控制台输出时,您可能需要将stdout重定向到控制台:

// AllocConsole() instead of CreateConsole()
AllocConsole();
freopen("CONOUT$", "w", stdout); // <====
std::cout << "vMain() has executed!\n";

此外,在DllMain()内创建线程并不是一个好主意,原因如下:

相关问题:

我记得我过去遇到过一些麻烦,而且我不再按照建议在DllMain()内创建线程/窗口。

不过,有些情况下它可行,但我不相信它。

话虽如此,如果上述情况不起作用,请尝试直接调用vMain()而不用线程,看看会发生什么。