我想用
CreateProcess()
创建一个子进程并向它传递一些参数,但我不想传递一个 string 作为参数,我想传递一个指向内存的指针,一个值或更多。struct Arguments {
void* ptr;
int value;
} Arg;
Arg = { some_pointer, 1337 };
// I know that "(LPWSTR)&Arg" doesnt work, but thats effectively what I want.
CreateProcessW(L"...\\Injet x86.exe",
(LPWSTR)&Arg, 0, 0, 0, 0, 0, 0, &si, &pi)
然后我尝试在子进程中获得结果:
孩子:
struct Arguments {
void* ptr;
int value;
};
// Yes, Im trying to not use default libs
void WINAPI WinMainCRTStartup()
{
Sleep(10000); // For debug
Arguments* ptrArgs = (Arguments*)GetCommandLineW();
// Do stuf
}
我知道这行不通,但我想要的是将参数传递给子进程,而不是字符串,而是变量/地址,以便它可以修改。我找到的所有示例都使用字符串作为参数,但我不想这样做,我该如何实现?
已记录 方法是将所需数据作为单个字符串参数传递。这就是你应该做的。
例如:
struct Arguments {
void* ptr;
int value;
} Arg;
Arg = { some_pointer, 1337 };
WCHAR szCmdLine[32];
swprintf(szCmdLine, L"%p %d", Arg.ptr, Arg.value);
CreateProcessW(L"<path to>\\Injet x86.exe", szCmdLine, ...);
struct Arguments {
void* ptr;
int value;
};
void WINAPI WinMainCRTStartup()
{
Sleep(10000); // For debug
Arguments Arg;
swscanf(GetCommandLineW(), L"%p %d", &Arg.ptr, &Arg.value);
// Do stuff
}
但是,还有一种 未记录 方法(即,使用风险自负!)让
CreateProcess()
将任意字节传递给新进程。这篇文章中描述了这种方法1:
将任意数据传递给子进程!
最后一个未记录的技巧与之前的完全不同,所以我想我会把它留到最后。 STARTUPINFO 结构包含两个成员,lpReserved2 和 cbReserved2:
WORD cbReserved2; LPBYTE lpReserved2;
这两个成员提供了一种机制,可以将任意数量的数据从一个进程传递到另一个进程,而无需调用 VirtualAllocEx / WriteProcessMemory。 cbReserved2 成员是一个 16 位整数,指定 lpReserved2 指向的缓冲区的大小。这意味着 lpReserved2 可以大到 65535 字节。
...
如果您希望在自己的程序中使用 lpReserved2(使用 CreateProcess 而不是 spawn / exec),您需要小心,因为 lpReserved2 缓冲区必须正确构造。如果不这样做将导致子进程崩溃,或者至少变得不稳定——原因是子进程期望以特定格式找到 lpReserved2。
例如:
struct Arguments {
void* ptr;
int value;
} Arg;
Arg = { some_pointer, 1337 };
BYTE buf[sizeof(DWORD) + sizeof(Arg)];
*(DWORD*)buf = 0;
memcpy(buf + sizeof(DWORD), &Arg, sizeof(Arg));
STARTUPINFO si = { sizeof(si) };
si.lpReserved2 = buf;
si.cbReserved2 = sizeof(buf);
CreateProcessW(L"<path to>\\Injet x86.exe", ... &si, ...);
struct Arguments {
void* ptr;
int value;
};
void WINAPI WinMainCRTStartup()
{
Sleep(10000); // For debug
STARTUPINFO si = { sizeof(si) };
GetStartupInfo(&si);
Arguments* ptrArgs = (Arguments*) (si.lpReserved2 + sizeof(DWORD));
// Do stuff
}
1 注意,在 Vista WOW64 下有一个警告,它会影响通过
lpReserved2
传递的缓冲区的格式,如本讨论中所述:GetStartupInfo problem under WOW64 on 64 bit Vista
更安全的方法是让父进程在命名文件映射中创建命名管道、监听套接字或共享内存块,然后使用命令行字符串将该资源的标识符传递给子进程,然后可以根据需要连接该资源并从该资源读取数据。
话虽这么说,无论您决定采用何种方法,都知道您传递给子进程的任何内存指针在子进程的上下文中都是无效的,仅在父进程的上下文中有效。子进程中此类指针的唯一有效用途是调用
ReadProcessMemory()
以从父进程的内存中读取数据,例如:
struct Arguments {
void* ptr;
int value;
};
void WINAPI WinMainCRTStartup()
{
Sleep(10000); // For debug
Arguments Arg;
// populate from parent as needed...
DWORD dwProcessId = ...; // obtain from parent as needed
HANDLE hParent = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessId);
if (hParent)
{
ReadProcessMemory(hParent, Arg.ptr, ...);
CloseHandle(hParent);
// Do stuff
}
}
根据文档:CreateProcessW 函数(processthreadsapi.h)
[输入,输出,可选] lpCommandLine
要执行的命令行。
这个string的最大长度是32,767个字符,包括 Unicode 终止空字符。
这个参数只接受一个字符串,你不能传递一个指向内存的指针,一个值或更多。