【问题标题】:Creating remote thread is crashing the process创建远程线程正在使进程崩溃
【发布时间】:2016-03-21 09:22:51
【问题描述】:

我正在尝试在不同的进程中注入代码,目前已经取得了一些成功,我可以在目标进程中注入数据和方法。我可以执行远程线程,并且只有在线程函数没有主体的情况下才会在线程完成后获得返回值。例如,如果我从 ThreadFunc 中省略 MessageBox 行,那么它将起作用,但没有 std::cout/printf/MessageBox 可以存在并且没有 Windows api 调用。所以我要么立即从该函数返回,要么做一些简单的数学运算。

编译代码

#include <windows.h>
#include <tlhelp32.h>
#include <string.h>
#include <iostream>
using namespace std;

#define cbNewProc       1600

typedef struct {
    HWND hwnd;
} INJDATA, *PINJDATA;

static const char *err_str(void) {
    static char buf[2048];
    if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buf,
            sizeof(buf), NULL))
        return buf;
    return "Unknown error";
}

// entry point in remote process
static LRESULT CALLBACK ThreadFunc(LPVOID param) {
    MessageBox(NULL, "I am inside remote process", "Hiiii", 0);
    return 1;
}

static int inject_code(DWORD pid) {
    cout << "Process found: " << pid << endl;

    HANDLE hp = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
    PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid);
    if (!hp) {
        fprintf(stderr, "OpenProcess( %s )\n", err_str());
        return 0;
    }

    int size = sizeof(INJDATA) + cbNewProc;
    BYTE* pDataRemote = (BYTE*) VirtualAllocEx(hp, NULL, size,
    MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!pDataRemote) {
        fprintf(stderr, "VirtualAllocEx( %s )\n", err_str());
        CloseHandle(hp);
        return 0;
    }

    SIZE_T dwNumBytesXferred;
    BYTE* pNewProcRemote = pDataRemote + sizeof(INJDATA);
    if (!WriteProcessMemory(hp, pNewProcRemote, (void*) &ThreadFunc,
    cbNewProc, &dwNumBytesXferred)) {
        fprintf(stderr, "WriteProcessMemory( %s )\n", err_str());
        VirtualFreeEx(hp, pDataRemote, size, MEM_RELEASE);
        CloseHandle(hp);
        return 0;
    }

    INJDATA DataLocal;
    ZeroMemory(&DataLocal, sizeof(INJDATA));
    if (!WriteProcessMemory(hp, pDataRemote, &DataLocal, sizeof(INJDATA),
            &dwNumBytesXferred)) {
        fprintf(stderr, "WriteProcessMemory( %s )\n", err_str());
        VirtualFreeEx(hp, pDataRemote, size, MEM_RELEASE);
        CloseHandle(hp);
        return 0;
    }

    printf("pDataRemote=%ld\n", pDataRemote);
    printf("pNewProcRemote1=%ld\n", pNewProcRemote);
    printf("pNewProcRemote2=%ld\n", pNewProcRemote + cbNewProc);

    int nSuccess = 0;
    DWORD dwThreadId;
    HANDLE hThread = CreateRemoteThread(hp, NULL, 0,
            (LPTHREAD_START_ROUTINE) pNewProcRemote, pDataRemote, 0,
            &dwThreadId);
    if (hThread == 0) {
        cout << "CreateRemoteThread failed" << endl;
        return 0;
    }

    WaitForSingleObject(hThread, INFINITE);
    GetExitCodeThread(hThread, (PDWORD) &nSuccess);
    VirtualFreeEx(hp, pDataRemote, size, MEM_RELEASE);
    cout << "nSuccess=" << nSuccess << ", size=" << size << endl;

    CloseHandle(hp);
    return 1;
}

int main() {
    cout << "Remote Thread" << endl;

    HANDLE h;
    PROCESSENTRY32 p;

    h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (h == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "CreateToolHelp32Snapshot( %s )\n", err_str());
        return 0;
    }

    p.dwSize = sizeof(p);

    if (!Process32First(h, &p)) {
        fprintf(stderr, "Process32First( %s )\n", err_str());
        goto out_close;
    }

    do {
        if (strcasecmp(p.szExeFile, "dllexp.exe"))
            continue;
        inject_code(p.th32ProcessID);
    } while (Process32Next(h, &p));

    out_close: CloseHandle(h);
    return 0;
}

通常目标进程会因页面错误或无效读取位置错误而崩溃。

【问题讨论】:

    标签: c++ winapi


    【解决方案1】:

    这注定要失败。您的代码基于以下假设:您程序中的MessageBoxA 地址在目标进程中也是MessageBoxA 的地址。没有理由认为这是真的。您的代码基于这样的假设:目标进程将包含与调用程序相同地址的字符串文字,并且再次没有理由期待这一点。没有理由期望目标进程与您的进程具有相同的运行时,位于相同的地址。等等。

    CreateRemoteThread注入时,有两种常用的方法:

    1. 如果您同时控制这两个进程,那么您可以安排目标进程拥有一个线程函数,您可以获取其地址,例如通过 IPC。换句话说,你将线程函数编译到目标进程中,它就在那里等着你。
    2. 线程函数的签名与LoadLibrary的签名兼容。因此,您传递LoadLibrary 的地址(在目标进程中)并传递一个参数,该参数是在目标进程中分配的以空字符结尾的字符数组的地址。该字符数组包含 DLL 的路径,然后将其加载到目标进程中,然后在其 DllMain 中启动另一个线程,该线程执行需要完成的任何工作。

    这两种方法的示例都可以广泛使用,并且可以通过网络搜索找到。

    【讨论】:

    • 你说 dll 注入是唯一的可能性,但codeproject.com/Articles/4610/… 家伙提到了一种没有 dll 路由的方法,我似乎无法让它工作。
    • 您没有遵守此处列出的所有注意事项
    • 我相信我已经按照步骤 1 - 10 然后更改为“发布”构建,MessageBox 也在 user32 中,作者说模块 user32 在当前和远程进程中都映射在同一位置.我已经粘贴了示例中的代码,如果您可以看一下。 – 顺便说一句,我正在使用 mingw 编译器可以有所作为吗?
    • 我认为没有理由相信 user32 将被加载到一个稳定的地址。此外,根据使用的链接器,MessageBoxA 可能指向存根而不是 user32 中的函数。您侵犯了该文章中的第 2 条警告。
    • 对,我违反了第 2 条,当我通过 injdata (string memcpied) 发送字符串时,仍然失败,所以可能正如您所说的,问题在于 api 地址映射不正确
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    • 1970-01-01
    • 2011-06-24
    • 2021-03-28
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    相关资源
    最近更新 更多