如何向WinAPI的CreateProcess传递非字符串类型的多参数
用WinAPI CreateProcess传递非字符串参数(内存指针/数值)并支持修改的实现方案
你当前的方法无法生效的核心原因有两个:
CreateProcessW的命令行参数仅支持字符串类型,直接传递结构体指针会被当作字符串解析,必然出错。- Windows进程拥有独立的地址空间,父进程的内存指针在子进程中是无效的,无法直接访问。
以下是几种可行的实现方案,均支持子进程修改数据:
方案一:使用共享内存(File Mapping)
共享内存是跨进程共享数据的标准方案,父进程创建一块命名的共享内存区域,写入参数数据;子进程通过名称打开这块共享内存,读取并修改数据,修改结果会直接同步到父进程。
父进程代码
#include <windows.h> #include <swprintf.h> struct Arguments { void* ptr; // 若要让子进程访问父进程内存,需先将该内存也转为共享内存 int value; } Arg; int main() { Arg.value = 1337; Arg.ptr = NULL; // 示例仅传递数值,若需传递可访问内存需额外处理 // 创建共享内存,大小刚好容纳Arguments结构体 HANDLE hMapFile = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Arguments), L"MySharedArgs"); if (hMapFile == NULL) return GetLastError(); // 将共享内存映射到父进程地址空间 Arguments* pSharedArgs = (Arguments*)MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(Arguments)); if (pSharedArgs == NULL) { CloseHandle(hMapFile); return GetLastError(); } // 将参数写入共享内存 *pSharedArgs = Arg; // 启动子进程,将共享内存名称作为命令行参数传递 STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi; wchar_t cmdLine[256]; swprintf_s(cmdLine, L"\"...\\Injet x86.exe\" MySharedArgs"); if (!CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { UnmapViewOfFile(pSharedArgs); CloseHandle(hMapFile); return GetLastError(); } // 等待子进程结束,读取修改后的参数 WaitForSingleObject(pi.hProcess, INFINITE); Arg = *pSharedArgs; // 清理资源 UnmapViewOfFile(pSharedArgs); CloseHandle(hMapFile); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0; }
子进程代码(无默认库)
#include <windows.h> struct Arguments { void* ptr; int value; }; void WINAPI WinMainCRTStartup() { // 获取命令行中的共享内存名称 wchar_t* cmdLine = GetCommandLineW(); // 跳过程序名,定位到共享内存名称 while (*cmdLine != L' ' && *cmdLine != L'\0') cmdLine++; if (*cmdLine == L' ') cmdLine++; // 打开共享内存 HANDLE hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, cmdLine); if (hMapFile == NULL) ExitProcess(GetLastError()); // 将共享内存映射到子进程地址空间 Arguments* pArgs = (Arguments*)MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(Arguments)); if (pArgs == NULL) { CloseHandle(hMapFile); ExitProcess(GetLastError()); } // 修改参数数据(会同步到父进程的共享内存) pArgs->value = 42; // 清理资源 UnmapViewOfFile(pArgs); CloseHandle(hMapFile); ExitProcess(0); }
方案二:使用WriteProcessMemory写入子进程内存
父进程先以暂停状态启动子进程,在子进程地址空间分配内存并写入参数,再通过共享内存传递该内存的地址,最后恢复子进程运行。子进程读取地址后直接访问自己地址空间内的参数并修改。
父进程代码
#include <windows.h> struct Arguments { void* ptr; int value; } Arg; int main() { Arg.value = 1337; Arg.ptr = NULL; STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi; // 以暂停状态启动子进程 if (!CreateProcessW( L"...\\Injet x86.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { return GetLastError(); } // 在子进程地址空间分配内存 Arguments* pRemoteArgs = (Arguments*)VirtualAllocEx( pi.hProcess, NULL, sizeof(Arguments), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (pRemoteArgs == NULL) { TerminateProcess(pi.hProcess, -1); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return GetLastError(); } // 将参数写入子进程内存 if (!WriteProcessMemory(pi.hProcess, pRemoteArgs, &Arg, sizeof(Arguments), NULL)) { VirtualFreeEx(pi.hProcess, pRemoteArgs, 0, MEM_RELEASE); TerminateProcess(pi.hProcess, -1); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return GetLastError(); } // 创建共享内存传递子进程内的参数地址 HANDLE hMapAddr = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(void*), L"MyArgAddr"); if (hMapAddr != NULL) { void** pSharedAddr = (void**)MapViewOfFile(hMapAddr, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(void*)); if (pSharedAddr != NULL) { *pSharedAddr = pRemoteArgs; UnmapViewOfFile(pSharedAddr); } CloseHandle(hMapAddr); } // 恢复子进程运行 ResumeThread(pi.hThread); // 等待子进程结束,读取修改后的参数 WaitForSingleObject(pi.hProcess, INFINITE); Arguments modifiedArg; ReadProcessMemory(pi.hProcess, pRemoteArgs, &modifiedArg, sizeof(Arguments), NULL); // 清理资源 VirtualFreeEx(pi.hProcess, pRemoteArgs, 0, MEM_RELEASE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0; }
子进程代码(无默认库)
#include <windows.h> struct Arguments { void* ptr; int value; }; void WINAPI WinMainCRTStartup() { // 打开存储参数地址的共享内存 HANDLE hMapAddr = OpenFileMappingW(FILE_MAP_READ, FALSE, L"MyArgAddr"); if (hMapAddr == NULL) ExitProcess(GetLastError()); void** pRemoteArgsAddr = (void**)MapViewOfFile( hMapAddr, FILE_MAP_READ, 0, 0, sizeof(void*)); if (pRemoteArgsAddr == NULL) { CloseHandle(hMapAddr); ExitProcess(GetLastError()); } // 获取子进程内的参数地址 Arguments* pArgs = (Arguments*)*pRemoteArgsAddr; // 修改参数数据 pArgs->value = 42; // 清理资源 UnmapViewOfFile(pRemoteArgsAddr); CloseHandle(hMapAddr); ExitProcess(0); }
关键注意事项
- 地址空间隔离:父进程的内存指针无法直接在子进程中使用,必须通过共享内存或
WriteProcessMemory将数据转移到子进程可访问的空间。 - 数据修改同步:使用共享内存时,子进程的修改会直接同步到父进程;使用
WriteProcessMemory方案时,父进程需要主动读取子进程内存来获取修改后的数据。 - 资源清理:所有创建的句柄、映射内存都要及时关闭/释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者EnderMega
相关产品推荐
相关产品推荐

