尝试注入dll时如何正确使用VirtualFreeEx

时间:2019-01-15 21:32:20

标签: c++ winapi parameters dll-injection

我正在尝试制作DLL注入器,但是函数中存在参数错误。

我尝试将变量更改为char *,我已经确认进程ID是正确的,因为使用的是代码块,但是我正在尝试的程序无法在x64或x86中进行编译上是使用代码块创建的,该DLL可与其他注入器一起使用,我已确认dll路径正确。

{{1}}

第一个功能在VirtualFreeEx上打印87,第二个功能在VirtualFreeEx上打印6。我该如何解决?我正在使用GNU GCC编译器。

1 个答案:

答案 0 :(得分:1)

您根本不执行任何错误处理。 OpenProcess()VirtualAllocEx()WriteProcessMemory()CreateRemoteThread(),所有这些功能都会失败,您需要进行处理。并且GetLastError()仅在它们确实失败时才有意义。

CreateRemoteThreadInject()中,如果CreateRemoteThread()成功,则您不必等待线程完成,然后再尝试释放分配的内存。然后,您将关闭HANDLE到该进程,然后再使用该HANDLE释放已分配的内存。而且您没有关闭HANDLE返回的CreateRemoteThread()

您在Injectstuff()中以正确的顺序执行操作,但是仍然缺乏足够的错误处理,并且您没有为DLL路径字符串上的空终止符分配足够的内存。

但是,为什么您有两个函数实际上执行相同的操作?它们之间唯一真正的区别是Injectstuff()是向OpenProcess()询问超出其实际需要的权限,而CreateRemoteThreadInject()仅询问其实际需要的特定权限。

另一方面,您使用system()执行echo命令是完全没有用的。您应该只写std::coutstd::cerr,并在需要时flush写。完全不需要为执行其echo命令而掏出系统命令进程。

请尝试以下类似操作:

void DisplayLastError(const char *operation, int err)
{
    std::cerr << "Error ";
    if (err) std::cerr << err << " ";
    std::cerr << operation << std::endl;
}

void DisplayLastError(const char *operation)
{
    DisplayLastError(operation, GetLastError());
}

bool CreateRemoteThreadInject(DWORD IDofproc, const char * dll)
{
    if (!IDofproc)
        return false;

    LPVOID pLoadLibrary = (LPVOID) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
    if (!pLoadLibrary)
    {
        DisplayLastError("getting LoadLibrary pointer");
        return false;
    }

    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, IDofproc);
    if (!hProcess)
    {
        DisplayLastError("opening the process");
        return false;
    }

    LPVOID pMemory = VirtualAllocEx(hProcess, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if (!pMemory)
    {
        DisplayLastError("allocating memory");
        CloseHandle(hProcess);
        return false;
    }

    if (!WriteProcessMemory(hProcess, pMemory, dll, strlen(dll) + 1, NULL))
    {
        DisplayLastError("writing to allocated memory");
        VirtualFreeEx(hProcess, pMemory, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return false;
    }

    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pMemory, 0, NULL);
    if (!hThread)
    {
        DisplayLastError("creating remote thread");
        VirtualFreeEx(hProcess, pMemory, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return false;
    }

    WaitForSingleObject(hThread, INFINITE);

    DWORD dwExitCode = 0;
    GetExitCodeThread(hThread, &dwExitCode);

    CloseHandle(hThread);

    VirtualFreeEx(hProcess, pMemory, 0, MEM_RELEASE);
    CloseHandle(hProcess);

    if (!dwExitCode)
    {
        DisplayLastError("loading dll", 0);
        return false;
    }

    MessageBox(NULL, TEXT("Injected"), TEXT(""), MB_OK);
    return true;
}

bool Injectstuff(DWORD processId, char* dllpath)
{
    std::cout << "Process ID: " << processId << std::endl;
    return CreateRemoteThreadInject(processId, dllpath);
}

此外,请注意,仅当目标进程为32位时,才能检测LoadLibraryA()是否成功所需的代码。传递给CreateRemoteThread()的函数必须始终返回32位的DWORD,并且在32位进程中调用时,LoadLibraryA()返回32位的HMODULE,但是返回在64位进程中进行调用时,使用64位HMODULE。线程无法返回64位退出代码,并且GetExitCodeThread()无法检索64位退出代码,因此返回的HMODULE将被截断,这可能导致错误的结果。因此,在注入64位进程时,直接使用LoadLibraryA() 作为线程函数并不是真正合适的,除非您不关心加载的结果。如果需要的话,可以注入一个小的函数thunk,它间接调用LoadLibrary()并将结果保存到一个内存地址,当线程完成时,注入器可以使用ReadProcessMemory()从中读取该内存地址。或使用different injection technique