鱼C论坛

 找回密码
 立即注册
查看: 1518|回复: 14

[已解决]创建远程线程后进程异常退出

[复制链接]
发表于 2022-9-10 10:49:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
运行环境WIN10 x64,尝试使用CreateRemoteThread在计算器中创建远程进程后,计算器程序直接异常退出。。GetLastError的返回值为0(差不多是没能找到错误)
想请教以下各位大佬程序为啥会异常退出
以下是代码:
#include<stdio.h>
#include<windows.h>
HWND window_handle;
void t_main();
void t_end();
int main()
{
        HANDLE process_handle;
        HANDLE thread_handle=0;
        DWORD process_ID;
        DWORD64 thread_address;
        DWORD thread_ID;
        BOOL result;
        int code_size=(LPBYTE)t_end-(LPBYTE)t_main;
        printf("待嵌入的代码大小为:%d字节\n",code_size);

        window_handle = FindWindow(NULL, "计算器");
        printf("获取到的窗口句柄为0x%X\n",window_handle);

        GetWindowThreadProcessId(window_handle,&process_ID);
        process_handle=OpenProcess(PROCESS_ALL_ACCESS,FALSE,process_ID);
        printf("获取到的进程句柄为0x%X\n", process_handle);

        thread_address = VirtualAllocEx(process_handle,NULL,code_size,MEM_COMMIT,PAGE_EXECUTE_READ);
        printf("申请到的进程中合适的地址为:0x%X\n",thread_address);

        result = WriteProcessMemory(process_handle,thread_address,&t_main,code_size,NULL);
        if (result != 0)
        {
                printf("在内存中写入数据成功!\n");
        }
        else
        {
                printf("在内存中写入数据失败。\n");
        }
        thread_handle = CreateRemoteThread(process_handle,NULL,0,thread_address,NULL,0,NULL);
        printf("创建的线程句柄为0x%X\n", thread_handle);

//        CloseHandle(window_handle);
//        CloseHandle(process_handle);
//        CloseHandle(thread_handle);
        if (GetLastError())
        {
                printf("出现错误,错误代码为:%d\n", GetLastError());   //运行下来返回值为0
        }
        getchar();
}

static void t_main()
{
        MessageBox(window_handle, "成功!","无",NULL);
}
static void t_end()
{
        ;
}
最佳答案
2022-9-10 16:48:30
问你,当前进程的MessageBox地址和目标进程的MessageBox地址一样吗?不一样?那你为什么在目标进程中使用当前进程的MessageBox地址?
在目标进程中如何使用MessageBox ?
LoadLibrary和GetProcAddress了解一下
#include <stdio.h>
#include <windows.h>
#include <psapi.h>

HWND window_handle;

static DWORD WINAPI t_main(LPVOID lpParameter) {
    void *(*parameter)[2] = (void *)lpParameter;
    HMODULE (*LoadLibraryA)(LPCSTR lpLibFileName) = (*parameter)[0];
    FARPROC (*GetProcAddress)(HMODULE hModule, LPCSTR lpProcName) = (*parameter)[1];
    const char str_kernel32[] = "kernel32.dll";
    HMODULE kernel32 = LoadLibraryA(str_kernel32);
    const char str_user32[] = "user32.dll";
    HMODULE user32 = LoadLibraryA(str_user32);
    const char str_FreeLibrary[] = "FreeLibrary";
    BOOL (*FreeLibrary)(HMODULE hLibModule) = (void *)GetProcAddress(kernel32, str_FreeLibrary);
    const char str_MessageBoxA[] = "MessageBoxA";
    int (*MessageBoxA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = (void *)GetProcAddress(user32, str_MessageBoxA);
    const char str_ok[] = "ok!";
    const char str_none[] = "none";
    MessageBoxA(NULL, str_ok, str_none, MB_OK);
    FreeLibrary(user32);
    FreeLibrary(kernel32);
    return 123;
}

static void WINAPI t_end(void) {}

static void *find_proc_address(HANDLE hProcess, const char *proc_name) {
    HMODULE hMods[1024];
    DWORD cbNeeded;
    if(!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) return NULL;
    for(size_t i = 0; i < cbNeeded / sizeof(HMODULE); ++i) {
        FARPROC proc = GetProcAddress(hMods[i], proc_name);
        if(proc) return proc;
    }
    return NULL;
}

int main(void) {
    HANDLE process_handle;
    HANDLE thread_handle = 0;
    DWORD process_ID;
    LPVOID thread_address;
    BOOL result;
    int code_size = (LPBYTE)t_end - (LPBYTE)t_main;
    printf("待嵌入的代码大小为:%d字节\n", code_size);
    window_handle = FindWindowW(NULL, L"计算器");
    printf("获取到的窗口句柄为%p\n", window_handle);

    GetWindowThreadProcessId(window_handle, &process_ID);
    process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_ID);
    printf("获取到的进程句柄为%p\n", process_handle);

    thread_address = VirtualAllocEx(process_handle, NULL, code_size, MEM_COMMIT, PAGE_EXECUTE_READ);
    printf("申请到的进程中合适的地址为:%p\n", thread_address);

    result = WriteProcessMemory(process_handle, thread_address, t_main, code_size, NULL);
    if (result != 0) printf("在内存中写入数据成功!\n");
    else printf("在内存中写入数据失败。\n");

    void *parameter[2] = {find_proc_address(process_handle, "LoadLibraryA"), find_proc_address(process_handle, "GetProcAddress")};
    LPVOID thread_parameter = VirtualAllocEx(process_handle, NULL, sizeof(parameter), MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(process_handle, thread_parameter, ¶meter, sizeof(parameter), NULL);

    thread_handle = CreateRemoteThread(process_handle, NULL, 0, thread_address, thread_parameter, 0, NULL);
    printf("创建的线程句柄为%p\n", thread_handle);

    WaitForSingleObject(thread_handle, INFINITE);
    DWORD ExitCode;
    GetExitCodeThread(thread_handle, &ExitCode);
    printf("ExitCode: %u\n", ExitCode);

    CloseHandle(thread_handle);
    VirtualFreeEx(process_handle, thread_parameter, 0, MEM_RELEASE);
    VirtualFreeEx(process_handle, thread_address, 0, MEM_RELEASE);
    CloseHandle(process_handle);
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-9-10 16:48:30 | 显示全部楼层    本楼为最佳答案   
问你,当前进程的MessageBox地址和目标进程的MessageBox地址一样吗?不一样?那你为什么在目标进程中使用当前进程的MessageBox地址?
在目标进程中如何使用MessageBox ?
LoadLibrary和GetProcAddress了解一下
#include <stdio.h>
#include <windows.h>
#include <psapi.h>

HWND window_handle;

static DWORD WINAPI t_main(LPVOID lpParameter) {
    void *(*parameter)[2] = (void *)lpParameter;
    HMODULE (*LoadLibraryA)(LPCSTR lpLibFileName) = (*parameter)[0];
    FARPROC (*GetProcAddress)(HMODULE hModule, LPCSTR lpProcName) = (*parameter)[1];
    const char str_kernel32[] = "kernel32.dll";
    HMODULE kernel32 = LoadLibraryA(str_kernel32);
    const char str_user32[] = "user32.dll";
    HMODULE user32 = LoadLibraryA(str_user32);
    const char str_FreeLibrary[] = "FreeLibrary";
    BOOL (*FreeLibrary)(HMODULE hLibModule) = (void *)GetProcAddress(kernel32, str_FreeLibrary);
    const char str_MessageBoxA[] = "MessageBoxA";
    int (*MessageBoxA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = (void *)GetProcAddress(user32, str_MessageBoxA);
    const char str_ok[] = "ok!";
    const char str_none[] = "none";
    MessageBoxA(NULL, str_ok, str_none, MB_OK);
    FreeLibrary(user32);
    FreeLibrary(kernel32);
    return 123;
}

static void WINAPI t_end(void) {}

static void *find_proc_address(HANDLE hProcess, const char *proc_name) {
    HMODULE hMods[1024];
    DWORD cbNeeded;
    if(!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) return NULL;
    for(size_t i = 0; i < cbNeeded / sizeof(HMODULE); ++i) {
        FARPROC proc = GetProcAddress(hMods[i], proc_name);
        if(proc) return proc;
    }
    return NULL;
}

int main(void) {
    HANDLE process_handle;
    HANDLE thread_handle = 0;
    DWORD process_ID;
    LPVOID thread_address;
    BOOL result;
    int code_size = (LPBYTE)t_end - (LPBYTE)t_main;
    printf("待嵌入的代码大小为:%d字节\n", code_size);
    window_handle = FindWindowW(NULL, L"计算器");
    printf("获取到的窗口句柄为%p\n", window_handle);

    GetWindowThreadProcessId(window_handle, &process_ID);
    process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_ID);
    printf("获取到的进程句柄为%p\n", process_handle);

    thread_address = VirtualAllocEx(process_handle, NULL, code_size, MEM_COMMIT, PAGE_EXECUTE_READ);
    printf("申请到的进程中合适的地址为:%p\n", thread_address);

    result = WriteProcessMemory(process_handle, thread_address, t_main, code_size, NULL);
    if (result != 0) printf("在内存中写入数据成功!\n");
    else printf("在内存中写入数据失败。\n");

    void *parameter[2] = {find_proc_address(process_handle, "LoadLibraryA"), find_proc_address(process_handle, "GetProcAddress")};
    LPVOID thread_parameter = VirtualAllocEx(process_handle, NULL, sizeof(parameter), MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(process_handle, thread_parameter, ¶meter, sizeof(parameter), NULL);

    thread_handle = CreateRemoteThread(process_handle, NULL, 0, thread_address, thread_parameter, 0, NULL);
    printf("创建的线程句柄为%p\n", thread_handle);

    WaitForSingleObject(thread_handle, INFINITE);
    DWORD ExitCode;
    GetExitCodeThread(thread_handle, &ExitCode);
    printf("ExitCode: %u\n", ExitCode);

    CloseHandle(thread_handle);
    VirtualFreeEx(process_handle, thread_parameter, 0, MEM_RELEASE);
    VirtualFreeEx(process_handle, thread_address, 0, MEM_RELEASE);
    CloseHandle(process_handle);
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-10 18:15:09 | 显示全部楼层
人造人 发表于 2022-9-10 16:48
问你,当前进程的MessageBox地址和目标进程的MessageBox地址一样吗?不一样?那你为什么在目标进程中使用当 ...

大佬,顺便问一句,你在电脑上尝试给进程创建远程线程时,进程会异常终止吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-9-10 18:21:19 | 显示全部楼层
玛丽亚在伯大尼 发表于 2022-9-10 18:15
大佬,顺便问一句,你在电脑上尝试给进程创建远程线程时,进程会异常终止吗

用你的代码会,我改的代码不会
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-10 19:40:04 | 显示全部楼层
人造人 发表于 2022-9-10 18:21
用你的代码会,我改的代码不会

跪求大佬解答,运行修改好的代码出现了一样的问题显示ExitCode: 3221225477
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-9-10 19:44:37 | 显示全部楼层
玛丽亚在伯大尼 发表于 2022-9-10 19:40
跪求大佬解答,运行修改好的代码出现了一样的问题显示ExitCode: 3221225477

那就调试程序么,下断点,一条语句一条语句执行程序,看返回值,看看在哪一行的返回值有问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-11 22:54:22 | 显示全部楼层
人造人 发表于 2022-9-10 19:44
那就调试程序么,下断点,一条语句一条语句执行程序,看返回值,看看在哪一行的返回值有问题

折腾了一天,发现只要远程线程中存在函数调用行为(确定好了地址的)就会出现0xC0000005错误,然后进程异常终止,但是只要没有调用函数,啥问题都没有。不管是我后来写的,还是大佬你给的代码都会出现这样的问题。。敢问大佬,这可能是运行环境的问题吗(win10,vs2017,其他什么没乱动过)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-9-11 23:13:39 | 显示全部楼层
玛丽亚在伯大尼 发表于 2022-9-11 22:54
折腾了一天,发现只要远程线程中存在函数调用行为(确定好了地址的)就会出现0xC0000005错误,然后进程异 ...

你什么时候有时间,远程给你调试一下?
qq:1440332527
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-9-11 23:15:14 | 显示全部楼层
玛丽亚在伯大尼 发表于 2022-9-11 22:54
折腾了一天,发现只要远程线程中存在函数调用行为(确定好了地址的)就会出现0xC0000005错误,然后进程异 ...

不应该,重定位过地址的函数是可以调用的,不能调用函数,说明函数的地址没有进行重定位
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-12 09:37:11 | 显示全部楼层
人造人 发表于 2022-9-11 23:15
不应该,重定位过地址的函数是可以调用的,不能调用函数,说明函数的地址没有进行重定位

最后想不出什么办法,干脆写个程序自己打印MessageBoxA在其中的函数地址,然后在远程线程中使用汇编来调用函数。虽然最终成了,但是还是有一些奇怪的局限性。。
(试过C语言直接改写函数地址然后调用,会出错)
static void t_main()
{
        _asm {
        push 0x0                                //MB_OK
        push 0x4FF85C                        //正文的字符串地址
        push 0x4FF84C                        //标题的字符串地址
        push 0x0                                //父窗口句柄
        mov edi, 0x77A809A0                //MessageBoxA地址,这里很奇怪,直接call 0x77A809A0会出现之前一样的错误。。
        call edi                                //不知道为啥只有这样写才成功?
        }
        return 0;
}

static void t_end()
{
        ;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-9-12 10:57:17 | 显示全部楼层
玛丽亚在伯大尼 发表于 2022-9-12 09:37
最后想不出什么办法,干脆写个程序自己打印MessageBoxA在其中的函数地址,然后在远程线程中使用汇编来调 ...

我倒是想看看,你那边用我改的程序还不能运行,究竟错哪了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-12 15:00:38 | 显示全部楼层
终于改出来一个能用的了 此贴该完结了。
#include <stdio.h>
#include <windows.h>
#include <psapi.h>

HWND window_handle;

static DWORD WINAPI t_main(LPVOID lpParameter) {        //前一个参数的第一个元素是LoadLibraryA的地址,第二个元素是GetProcAddress的地址,第三个元素是字符串资源地址
        void *(*parameter)[3] = (void *)lpParameter;
        HMODULE(*LoadLibraryA)(LPCSTR lpLibFileName);
        LoadLibraryA = (*parameter)[0];
        FARPROC(*GetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
        GetProcAddress = (*parameter)[1];

        char* str_addr = (*parameter)[2];
        char* str_kernel32 = str_addr;
        HMODULE kernel32 = LoadLibraryA(str_kernel32);

        char* str_user32 = (str_addr += 13);
        HMODULE user32 = LoadLibraryA(str_user32);

        char* str_FreeLibrary = (str_addr += 11);
        BOOL(*FreeLibrary)(HMODULE hLibModule);
        FreeLibrary = (void *)GetProcAddress(kernel32, str_FreeLibrary);

        char* str_MessageBoxA = (str_addr += 12);
        int(*MessageBoxA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
        MessageBoxA        = (void *)GetProcAddress(user32, str_MessageBoxA);

        char* str_text = (str_addr += 12);
        char* str_title = (str_addr += 7);
        MessageBoxA(0, str_text, str_title, 0);
        FreeLibrary(user32);
        FreeLibrary(kernel32);
        return 0;
}

static void WINAPI t_end(void) {}

static void *find_proc_address(HANDLE hProcess, const char *proc_name) {
        HMODULE hMods[1024];
        DWORD cbNeeded;
        if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) return NULL;
        for (size_t i = 0; i < cbNeeded / sizeof(HMODULE); ++i) {
                FARPROC proc = GetProcAddress(hMods[i], proc_name);
                if (proc) return proc;
        }
        return NULL;
}

int main(void) {
        HANDLE process_handle;
        HANDLE thread_handle = 0;
        DWORD process_ID;
        LPVOID thread_address;
        BOOL result;
        char str_resource[128] = "kernel32.dll\0user32.dll\0FreeLibrary\0MessageBoxA\0Hello?\0Greeting\0";
        int code_size = (LPBYTE)t_end - (LPBYTE)t_main;
        printf("待嵌入的代码大小为:%d字节\n", code_size);
        window_handle = FindWindowW(NULL, L"计算器");
        printf("获取到的窗口句柄为%p\n", window_handle);

        GetWindowThreadProcessId(window_handle, &process_ID);
        process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_ID);
        printf("获取到的进程句柄为%p\n", process_handle);

        thread_address = VirtualAllocEx(process_handle, NULL, code_size, MEM_COMMIT, PAGE_EXECUTE_READ);
        printf("申请到的进程中合适的地址为:%p\n", thread_address);

        result = WriteProcessMemory(process_handle, thread_address, t_main, code_size, NULL);
        if (result != 0) printf("在内存中写入数据成功!\n");
        else printf("在内存中写入数据失败。\n");

        LPVOID string_address = VirtualAllocEx(process_handle, NULL, sizeof(str_resource), MEM_COMMIT, PAGE_READWRITE);//将字符串资源载入进程
        WriteProcessMemory(process_handle, string_address, str_resource, 128, NULL);

        void *parameter[3] = { find_proc_address(process_handle, "LoadLibraryA"), find_proc_address(process_handle, "GetProcAddress"), string_address };
        LPVOID thread_parameter = VirtualAllocEx(process_handle, NULL, sizeof(parameter), MEM_COMMIT, PAGE_READWRITE);
        WriteProcessMemory(process_handle, thread_parameter, ¶meter, sizeof(parameter), NULL);

        thread_handle = CreateRemoteThread(process_handle, NULL, 0, (LPTHREAD_START_ROUTINE)thread_address, thread_parameter, 0, NULL);
        printf("创建的线程句柄为%p\n", thread_handle);

        WaitForSingleObject(thread_handle, INFINITE);
        DWORD ExitCode;
        GetExitCodeThread(thread_handle, &ExitCode);
        printf("ExitCode: 0x%X\n", ExitCode);

        CloseHandle(thread_handle);
        VirtualFreeEx(process_handle, thread_parameter, 0, MEM_RELEASE);
        VirtualFreeEx(process_handle, thread_address, 0, MEM_RELEASE);
        CloseHandle(process_handle);
        return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-12 15:07:01 | 显示全部楼层
人造人 发表于 2022-9-12 10:57
我倒是想看看,你那边用我改的程序还不能运行,究竟错哪了

我发现在线程内定义的字符串会出问题,然后我把字符串作为资源写入进程中调用就没问题了。还有,把函数定义和函数地址设置写在一起也会有问题,我也不知道为啥,分开就没事。就这两点改一下线程就能正常运行,Exitcode=0,万事大吉。总而言之,这两个问题很奇怪,想不通。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-9-12 15:11:44 | 显示全部楼层
玛丽亚在伯大尼 发表于 2022-9-12 15:07
我发现在线程内定义的字符串会出问题,然后我把字符串作为资源写入进程中调用就没问题了。还有,把函数定 ...

需要帮你调试一下吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-9-12 16:38:23 | 显示全部楼层
人造人 发表于 2022-9-12 15:11
需要帮你调试一下吗?

不用了,谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-28 18:22

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表