Reputation: 127
I'm trying to pipe some data from a foreign process to my program through an injected .dll with a pipe set up. However, ReadFile() only returns once the foreign program is exited (after which it will give the correct output). Is this standard behavior, or am I using pipes (or something else) wrong?
The relavent parts of the code are below (some parts omitted to keep it concise):
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;
}
(There might be some obvious mistakes/weird practices, I'm new to C++)
Upvotes: 0
Views: 163
Reputation: 32732
Things written to std::cout
will be internally cached until either the buffer gets full or it is flushed. The pipe will not see any of the written data until this flushing occurs.
You can call std::cout.flush()
after writing your data, or append a << std::endl
to your output statement to add a newline and flush the buffer. If you are only going to send complete messages (i.e., one <<
to cout
, rather than several to compose a message) you can use the unitbuf
flag within the stream to flush the output after every output operation (std::cout << std::unitbuf << "Send from .dll";
) You can use nounitbuf
to turn buffering back on.
Upvotes: 1