来自注入的 .dll 的管道冻结直到进程终止
Pipe from injected .dll frozen until process termination
我正在尝试通过设置了管道的注入 .dll 将一些数据从外部进程传输到我的程序。但是,ReadFile() 只有 returns 一旦外部程序退出(之后它将给出正确的输出)。这是标准行为,还是我使用的管道(或其他东西)有误?
相关部分代码如下(为简洁省略部分):
main.cpp:
int main() {
// Create a duplex pipe-based communication channel
STARTUPINFO startupInfo = {};
HANDLE parent_IN, parent_OUT;
if (!IntraProcessComms(startupInfo, parent_IN, parent_OUT)) {
std::cout << "Could not set up communication necessities" << std::endl;
return 1;
}
// Launch program and obtain the handle
PROCESS_INFORMATION processInfo = {};
if (!CreateProcess(
nullptr, // path
LPSTR("[the program path]"), // commands
nullptr, // handler inheritable
nullptr, // thread inheritable
true, // handler inheritance from caller
0, // creation flag
nullptr, // environment
nullptr, // directory
&startupInfo, // startup info
&processInfo)) { // process info
std::cout << "Could not launch program" << std::endl;
return 2;
}
// Inject the DLL (omitted here; it is injected successfully)
if (!InjectDLL(processInfo.hProcess, "scraper.dll")) {
std::cout << "Could not inject DLL" << std::endl;
return 3;
}
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
std::cout << "Successfully set up" << std::endl;
char buffer[BUFSIZ];
ZeroMemory(buffer, BUFSIZ);
ReadFile(parent_IN, buffer, sizeof(buffer), nullptr, nullptr);
std::cout << "Read: \"" << buffer << "\"" << std::endl;
return 0;
}
bool IntraProcessComms(STARTUPINFO &si, HANDLE &parent_IN, HANDLE &parent_OUT) {
HANDLE child_IN, child_OUT;
SECURITY_ATTRIBUTES securityAttr {
sizeof(SECURITY_ATTRIBUTES), // size
nullptr, // security
true // inheritable
};
// Create pipes from the child to the parent and vice-versa
if (!CreatePipe(
&parent_IN,
&child_OUT,
&securityAttr,
0)
|| !CreatePipe(
&child_IN,
&parent_OUT,
&securityAttr,
0))
return false;
// Ensure only the correct handles are inherited
if (!SetHandleInformation(
parent_IN,
HANDLE_FLAG_INHERIT,
0)
|| !SetHandleInformation(
parent_OUT,
HANDLE_FLAG_INHERIT,
0))
return false;
// Set up startupinfo
si.cb = sizeof(STARTUPINFO);
si.hStdError = child_OUT;
si.hStdOutput = child_OUT;
si.hStdInput = child_IN;
si.dwFlags = STARTF_USESTDHANDLES;
return true;
}
scraper.dll:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
if (fdwReason == DLL_PROCESS_ATTACH) {
// stdout was redirected by IntraProcessComms()
std::cout << "Send from .dll";
}
return true;
}
(可能有一些明显的 mistakes/weird 做法,我是 C++ 新手)
写入 std::cout
的内容将在内部缓存,直到缓冲区变满或被刷新。在此刷新发生之前,管道将看不到任何写入的数据。
您可以在写入数据后调用 std::cout.flush()
,或将 << std::endl
附加到输出语句以添加换行符并刷新缓冲区。如果您只打算发送完整的消息(即,一个 <<
到 cout
,而不是几个来组成一条消息),您可以在流中使用 unitbuf
标志来刷新输出每次输出操作后 (std::cout << std::unitbuf << "Send from .dll";
) 您可以使用 nounitbuf
重新打开缓冲。
我正在尝试通过设置了管道的注入 .dll 将一些数据从外部进程传输到我的程序。但是,ReadFile() 只有 returns 一旦外部程序退出(之后它将给出正确的输出)。这是标准行为,还是我使用的管道(或其他东西)有误?
相关部分代码如下(为简洁省略部分):
main.cpp:
int main() {
// Create a duplex pipe-based communication channel
STARTUPINFO startupInfo = {};
HANDLE parent_IN, parent_OUT;
if (!IntraProcessComms(startupInfo, parent_IN, parent_OUT)) {
std::cout << "Could not set up communication necessities" << std::endl;
return 1;
}
// Launch program and obtain the handle
PROCESS_INFORMATION processInfo = {};
if (!CreateProcess(
nullptr, // path
LPSTR("[the program path]"), // commands
nullptr, // handler inheritable
nullptr, // thread inheritable
true, // handler inheritance from caller
0, // creation flag
nullptr, // environment
nullptr, // directory
&startupInfo, // startup info
&processInfo)) { // process info
std::cout << "Could not launch program" << std::endl;
return 2;
}
// Inject the DLL (omitted here; it is injected successfully)
if (!InjectDLL(processInfo.hProcess, "scraper.dll")) {
std::cout << "Could not inject DLL" << std::endl;
return 3;
}
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
std::cout << "Successfully set up" << std::endl;
char buffer[BUFSIZ];
ZeroMemory(buffer, BUFSIZ);
ReadFile(parent_IN, buffer, sizeof(buffer), nullptr, nullptr);
std::cout << "Read: \"" << buffer << "\"" << std::endl;
return 0;
}
bool IntraProcessComms(STARTUPINFO &si, HANDLE &parent_IN, HANDLE &parent_OUT) {
HANDLE child_IN, child_OUT;
SECURITY_ATTRIBUTES securityAttr {
sizeof(SECURITY_ATTRIBUTES), // size
nullptr, // security
true // inheritable
};
// Create pipes from the child to the parent and vice-versa
if (!CreatePipe(
&parent_IN,
&child_OUT,
&securityAttr,
0)
|| !CreatePipe(
&child_IN,
&parent_OUT,
&securityAttr,
0))
return false;
// Ensure only the correct handles are inherited
if (!SetHandleInformation(
parent_IN,
HANDLE_FLAG_INHERIT,
0)
|| !SetHandleInformation(
parent_OUT,
HANDLE_FLAG_INHERIT,
0))
return false;
// Set up startupinfo
si.cb = sizeof(STARTUPINFO);
si.hStdError = child_OUT;
si.hStdOutput = child_OUT;
si.hStdInput = child_IN;
si.dwFlags = STARTF_USESTDHANDLES;
return true;
}
scraper.dll:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
if (fdwReason == DLL_PROCESS_ATTACH) {
// stdout was redirected by IntraProcessComms()
std::cout << "Send from .dll";
}
return true;
}
(可能有一些明显的 mistakes/weird 做法,我是 C++ 新手)
写入 std::cout
的内容将在内部缓存,直到缓冲区变满或被刷新。在此刷新发生之前,管道将看不到任何写入的数据。
您可以在写入数据后调用 std::cout.flush()
,或将 << std::endl
附加到输出语句以添加换行符并刷新缓冲区。如果您只打算发送完整的消息(即,一个 <<
到 cout
,而不是几个来组成一条消息),您可以在流中使用 unitbuf
标志来刷新输出每次输出操作后 (std::cout << std::unitbuf << "Send from .dll";
) 您可以使用 nounitbuf
重新打开缓冲。