You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用MessageBoxA无弹窗问题:跨进程注入WPF等程序失败排查

问题描述

本人有多年C#开发经验,现学习C语言并开展低阶项目。尝试通过跨进程注入调用MessageBoxA到空白WPF App、记事本(32/64位)、计算器等程序,WPF App与注入程序均编译为x64版本,调试输出显示所有步骤均执行成功,但始终无MessageBox弹窗,且代码量比网上示例多,寻求问题原因。

调试输出

Process ID for WpfApp1.exe found: 948
Target process found. PID: 948
Opened handle to process.
Handle to user32.dll loaded successfully.
Address of MessageBoxA: 00007ffc67fc8b70
Allocated memory at remote address: 00000262a8500000
Successfully wrote message to remote memory.
Remote thread created successfully.
Remote thread completed.

注入代码

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
#include <unistd.h>

DWORD GetPID(const char *processName);

int main(void) {
    DWORD processId = GetPID("WpfApp1.exe");

    if (!processId) {
        printf("Process not found\n");
        fflush(stdout);
        return 1;
    }
    printf("Target process found. PID: %lu\n", processId);
    fflush(stdout);

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
    if (!hProcess) {
        printf("Failed to open process. Error code: %lu\n", GetLastError());
        fflush(stdout);
        return 1;
    }
    printf("Opened handle to process.\n");
    fflush(stdout);

    // Explicitly load user32.dll
    HMODULE hUser32 = LoadLibrary("user32.dll");
    if (!hUser32) {
        printf("Failed to load user32.dll. Error code: %lu\n", GetLastError());
        fflush(stdout);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Handle to user32.dll loaded successfully.\n");
    fflush(stdout);

    LPVOID msgBoxAddress = (LPVOID)GetProcAddress(hUser32, "MessageBoxA");
    if (!msgBoxAddress) {
        printf("Failed to find address of MessageBoxA. Error code: %lu\n", GetLastError());
        fflush(stdout);
        FreeLibrary(hUser32);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Address of MessageBoxA: %p\n", msgBoxAddress);
    fflush(stdout);

    LPVOID remoteString = VirtualAllocEx(hProcess, NULL, 256, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!remoteString) {
        printf("Failed to allocate memory in target process. Error code: %lu\n", GetLastError());
        fflush(stdout);
        FreeLibrary(hUser32);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Allocated memory at remote address: %p\n", remoteString);
    fflush(stdout);

    if (!WriteProcessMemory(hProcess, remoteString, "Hello World!", 13, NULL)) {
        printf("Failed to write to remote memory. Error code: %lu\n", GetLastError());
        fflush(stdout);
        VirtualFreeEx(hProcess, remoteString, 0, MEM_RELEASE);
        FreeLibrary(hUser32);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Successfully wrote message to remote memory.\n");
    fflush(stdout);

    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)msgBoxAddress, remoteString, 0, NULL);
    if (!hThread) {
        printf("Failed to create remote thread. Error code: %lu\n", GetLastError());
        fflush(stdout);
        VirtualFreeEx(hProcess, remoteString, 0, MEM_RELEASE);
        FreeLibrary(hUser32);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Remote thread created successfully.\n");
    fflush(stdout);

    WaitForSingleObject(hThread, INFINITE);
    printf("Remote thread completed.\n");
    fflush(stdout);

    VirtualFreeEx(hProcess, remoteString, 0, MEM_RELEASE);
    FreeLibrary(hUser32);
    CloseHandle(hThread);
    CloseHandle(hProcess);
    return 0;
}

DWORD GetPID(const char *processName) {
    PROCESSENTRY32 processEntry;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot == INVALID_HANDLE_VALUE) {
        printf("Failed to create snapshot. Error code: %lu\n", GetLastError());
        fflush(stdout);
        return 0;
    }

    processEntry.dwSize = sizeof(processEntry);
    if (Process32First(hSnapshot, &processEntry)) {
        do {
            if (strcmp(processEntry.szExeFile, processName) == 0) {
                DWORD pid = processEntry.th32ProcessID;
                CloseHandle(hSnapshot);
                printf("Process ID for %s found: %lu\n", processName, pid);
                fflush(stdout);
                return pid;
            }
        } while (Process32Next(hSnapshot, &processEntry));
    }

    printf("Failed to find process: %s\n", processName);
    fflush(stdout);
    CloseHandle(hSnapshot);
    return 0;
}
分析与解决

核心错误:线程函数签名不匹配

CreateRemoteThread要求线程函数的签名为:

DWORD WINAPI ThreadProc(LPVOID lpParameter);

但MessageBoxA的签名是:

int WINAPI MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

直接将MessageBoxA作为线程函数传入,会导致参数传递完全错误:

  • 传入的remoteString被当作第一个参数HWND(无效窗口句柄)
  • lpText、lpCaption、uType参数为栈中随机值
    这种情况下MessageBoxA无法正确解析参数,自然不会弹出窗口,甚至可能直接返回错误码。

冗余代码说明

在注入进程中调用LoadLibrary("user32.dll")完全多余:

  • 目标进程作为GUI程序,默认已经加载了user32.dll
  • 系统核心DLL(如user32.dll、kernel32.dll)在同架构的所有进程中基地址一致,直接通过GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA")即可获取正确地址。

修正方案

最可靠且通用的方式是使用DLL注入,这也是网上示例常用的方法:

步骤1:编写注入用DLL

#include <windows.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
        case DLL_PROCESS_ATTACH:
            // DLL被加载到目标进程时调用MessageBoxA
            MessageBoxA(NULL, "Hello from injected DLL!", "Injection Success", MB_OK);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

将此代码编译为x64 DLL(与目标进程架构一致)。

步骤2:修改注入程序

改为通过CreateRemoteThread调用目标进程的LoadLibraryA加载上述DLL:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

DWORD GetPID(const char *processName);

int main(void) {
    DWORD processId = GetPID("WpfApp1.exe");
    if (!processId) {
        printf("Process not found\n");
        fflush(stdout);
        return 1;
    }
    printf("Target process found. PID: %lu\n", processId);
    fflush(stdout);

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
    if (!hProcess) {
        printf("Failed to open process. Error code: %lu\n", GetLastError());
        fflush(stdout);
        return 1;
    }
    printf("Opened handle to process.\n");
    fflush(stdout);

    // 获取LoadLibraryA的地址(系统DLL地址全局一致)
    LPVOID loadLibAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
    if (!loadLibAddr) {
        printf("Failed to get LoadLibraryA address. Error code: %lu\n", GetLastError());
        fflush(stdout);
        CloseHandle(hProcess);
        return 1;
    }

    // DLL的绝对路径,确保目标进程能访问到
    const char* dllPath = "C:\\Full\\Path\\To\\Your\\Inject.dll";
    size_t pathLength = strlen(dllPath) + 1;

    // 在目标进程中分配内存存放DLL路径
    LPVOID remotePath = VirtualAllocEx(hProcess, NULL, pathLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!remotePath) {
        printf("Failed to allocate remote memory. Error code: %lu\n", GetLastError());
        fflush(stdout);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Allocated remote memory for DLL path: %p\n", remotePath);
    fflush(stdout);

    // 将DLL路径写入目标进程内存
    if (!WriteProcessMemory(hProcess, remotePath, dllPath, pathLength, NULL)) {
        printf("Failed to write DLL path to remote memory. Error code: %lu\n", GetLastError());
        fflush(stdout);
        VirtualFreeEx(hProcess, remotePath, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Wrote DLL path to remote memory successfully.\n");
    fflush(stdout);

    // 创建远程线程调用LoadLibraryA加载DLL
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibAddr, remotePath, 0, NULL);
    if (!hThread) {
        printf("Failed to create remote thread. Error code: %lu\n", GetLastError());
        fflush(stdout);
        VirtualFreeEx(hProcess, remotePath, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return 1;
    }
    printf("Remote thread created successfully.\n");
    fflush(stdout);

    WaitForSingleObject(hThread, INFINITE);
    printf("Remote thread completed.\n");
    fflush(stdout);

    // 清理资源
    VirtualFreeEx(hProcess, remotePath, 0, MEM_RELEASE);
    CloseHandle(hThread);
    CloseHandle(hProcess);
    return 0;
}

DWORD GetPID(const char *processName) {
    PROCESSENTRY32 processEntry;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot == INVALID_HANDLE_VALUE) {
        printf("Failed to create snapshot. Error code: %lu\n", GetLastError());
        fflush(stdout);
        return 0;
    }

    processEntry.dwSize = sizeof(processEntry);
    if (Process32First(hSnapshot, &processEntry)) {
        do {
            if (strcmp(processEntry.szExeFile, processName) == 0) {
                DWORD pid = processEntry.th32ProcessID;
                CloseHandle(hSnapshot);
                printf("Process ID for %s found: %lu\n", processName, pid);
                fflush(stdout);
                return pid;
            }
        } while (Process32Next(hSnapshot, &processEntry));
    }

    printf("Failed to find process: %s\n", processName);
    fflush(stdout);
    CloseHandle(hSnapshot);
    return 0;
}

注意事项

  • 确保注入程序、目标进程、DLL三者架构一致(均为x64或均为x86)
  • DLL路径必须是绝对路径,否则目标进程可能找不到DLL
  • 运行注入程序需要管理员权限(否则可能无法打开目标进程)

内容的提问来源于stack exchange,提问作者JohnA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:47:02