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

How to correctly use VirtualFreeEx when trying to inject a dll

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

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

void EchoLastError()
{
    std::string ToExecute;
    std::stringstream Command;
    Command << "echo " << GetLastError();
    ToExecute = Command.str();
    system(ToExecute.c_str());
    Command.str(std::string());
}
BOOL CreateRemoteThreadInject(DWORD IDofproc, const char * dll)
{
    HANDLE Process;
    LPVOID Memory, LoadLibrary;
    if (!IDofproc)
    {
        return false;
    }
    Process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, IDofproc);

    EchoLastError();

    system("pause");
    LoadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

    Memory = (LPVOID)VirtualAllocEx(Process, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

    WriteProcessMemory(Process, (LPVOID)Memory, dll, strlen(dll) + 1, NULL);

    CreateRemoteThread(Process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, (LPVOID)Memory, NULL, NULL);
    EchoLastError();
    CloseHandle(Process);

    VirtualFreeEx(Process, (LPVOID)Memory, 0, MEM_RELEASE);
    EchoLastError();
    MessageBox(NULL, "Injected", "", MB_OK);

    return true;
}



//other
bool Injectstuff(DWORD processId, char* dllpath)
{
    std::stringstream kds;
    kds << "echo Process ID: " << processId;
    std::string dl = kds.str();
    system(dl.c_str());
    EchoLastError();
    HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
    EchoLastError();
    system("pause");
    if (hTargetProcess)
    {
        LPVOID LoadLibAddress = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
        EchoLastError();
    system("pause");
        LPVOID LoadPath = VirtualAllocEx(hTargetProcess, 0, strlen(dllpath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        EchoLastError();
    system("pause");
        HANDLE RemoteThread = CreateRemoteThread(hTargetProcess, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibAddress, LoadPath, 0, 0);
        EchoLastError();
    system("pause");
        WaitForSingleObject(RemoteThread, INFINITE);
        EchoLastError();
    system("pause");
        VirtualFreeEx(hTargetProcess, LoadPath, strlen(dllpath), MEM_RELEASE);
        EchoLastError();
    system("pause");
        CloseHandle(RemoteThread);
        CloseHandle(hTargetProcess);
        return true;
    }
    return false;
}

第一个函数在 VirtualFreeEx 上打印 87,第二个函数在 VirtualFreeEx 上打印 6。我该如何解决这些问题?我正在使用 GNU GCC 编译器。

您根本没有进行任何错误处理。 OpenProcess()VirtualAllocEx()WriteProcessMemory()CreateRemoteThread(),所有这些函数都可能失败,你需要处理它。而 GetLastError() 只有在它们确实失败时才有意义。

CreateRemoteThreadInject() 中,如果 CreateRemoteThread() 成功,则您在尝试释放分配的内存之前没有等待线程完成。在使用 HANDLE 释放分配的内存之前,您正在关闭进程的 HANDLE 。而且您没有关闭 HANDLE return 编辑 CreateRemoteThread().

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

但是,为什么有两个函数在本质上做同样的事情?它们之间唯一真正的区别是 Injectstuff() 要求 OpenProcess() 获得比实际需要更多的权限,而 CreateRemoteThreadInject() 只要求它实际需要的特定权限。

附带说明一下,您使用 system() 执行 echo 命令是完全没用的。你应该只写 std::coutstd::cerr ,如果需要的话 flush 。根本不需要 shell 出一个系统命令进程来执行它的 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);
}

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