WriteFile and ReadFile on child process's stdio (using overlapped named pipe) - c++

I want to read asynchronously from a child process's stdin, so I create an IOCP loop that listens for when ReadFile() is done. But ReadFile() is never done, it always returns ERROR_IO_PENDING, and WriteFile() always returns ERROR_IO_PENDING.
Node.js can asynchronously read from a child process:
const child_process = require("child_process")
var p = child_process.spawn("gcc")
p.stdout.on('data', data=>console.log(String(data)))
p.stderr.on('data', data=>console.log(String(data)))
How to do this in the Win32 API?
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <wchar.h>
#pragma comment (lib, "User32.lib")
static HANDLE iocp = INVALID_HANDLE_VALUE;
typedef struct PROCESS {
OVERLAPPED ol;
HANDLE hProcess,
stdin_read, stdin_write,
stdout_read, stdout_write,
stderr_read, stderr_write;
char buf[100];
} PROCESS, *PPROCESS, *LPROCESS;
DWORD WINAPI Worker(LPVOID param);
BOOL create_pipe(HANDLE* pserver_pipe, HANDLE* pclient_pipe, PROCESS* p) {
static __int64 counter=0;
HANDLE server_pipe, client_pipe;
int err;
WCHAR name[64];
for (;;) {
swprintf(name, sizeof(name), L"\\\\?\\pipe\\child\\%Id.%p", counter, p);
server_pipe = CreateNamedPipeW(
name,
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
65536,
65536,
0,
NULL);
if (server_pipe != INVALID_HANDLE_VALUE)
break;
err = GetLastError();
if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
return FALSE;
}
counter++;
}
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = 1;
client_pipe = CreateFileW(name,
GENERIC_READ|WRITE_DAC,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (client_pipe==INVALID_HANDLE_VALUE){
return FALSE;
}
if (CreateIoCompletionPort(client_pipe, iocp, (ULONG_PTR)p, 0)==NULL){
return FALSE;
}
if (CreateIoCompletionPort(server_pipe, iocp, (ULONG_PTR)p, 0)==NULL){
return FALSE;
}
*pclient_pipe = client_pipe;
*pserver_pipe = server_pipe;
return TRUE;
}
int wmain()
{
iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
assert(iocp);
PROCESS child_process{};
assert(create_pipe(&child_process.stdout_write, &child_process.stdout_read, &child_process));
assert(create_pipe(&child_process.stderr_write, &child_process.stderr_read, &child_process));
assert(create_pipe(&child_process.stdin_write, &child_process.stdin_read, &child_process));
HANDLE hThread = CreateThread(NULL, 0, Worker, iocp, 0, NULL);
assert(hThread);
WCHAR szCmdline[]=L"cmd";
PROCESS_INFORMATION piProcInfo{};
STARTUPINFOW siStartInfo{.cb = sizeof(STARTUPINFO),
.dwFlags=STARTF_USESTDHANDLES,
.hStdInput=child_process.stdin_read,
.hStdOutput=child_process.stdout_write,
.hStdError=child_process.stderr_write};
assert(CreateProcessW(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo));
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
// CloseHandle(child_process.stdout_write);
// CloseHandle(child_process.stdin_read);
ReadFile(child_process.stdout_read, child_process.buf, sizeof(child_process.buf), NULL, &child_process.ol);
int err = GetLastError();
if (err!=ERROR_IO_PENDING){
printf("Error in ReadFile %d\n", err);
}else{
puts("ReadFile is pending...\n");
}
char buf[100];
DWORD dwIn;
for(;;){
ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buf, sizeof buf, &dwIn, NULL);
if (dwIn<=0)
break;
WriteFile(child_process.stdin_write, buf, dwIn, NULL, &child_process.ol);
err = GetLastError();
if (err!=ERROR_IO_PENDING){
printf("Error in WriteFile %d\n", err);
}else{
puts("WriteFile is pending...\n");
}
}
PostQueuedCompletionStatus(iocp, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(iocp);
}
DWORD WINAPI Worker(LPVOID param) {
DWORD dwIoSize = 0;
LPOVERLAPPED ol;
PROCESS* ctx;
for(;;){
BOOL bSuccess = GetQueuedCompletionStatus((HANDLE)param, &dwIoSize,
(PDWORD_PTR)&ctx,
&ol,
INFINITE);
if (ctx == NULL) {
printf("ctx is NULL, maybe you call PostQueuedCompletionStatus? err=%d\n", GetLastError());
break;
}
if (bSuccess==FALSE || dwIoSize == 0) {
printf("GetQueuedCompletionStatus does not success(maybe EOF reached?) err=%d\n", GetLastError());
break;
}
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ctx->buf, dwIoSize, NULL, NULL);
ReadFile(ctx->stdout_read, ctx->buf, sizeof(ctx->buf), NULL, &ctx->ol);
}
return 0;
}

After search on Github, it's quite easy.
Create a Named Pipe for current process(read), and create a File for child process(write).
Github links:
https://github.com/parasol-framework/parasol/blob/c5ad64188c7496e3ff54eb75fd03c9e3124fe08b/src/core/microsoft/processes.c
https://github.com/dinamsky/malware-botnets/blob/4cd142d10f971cb93c334b6f48c12c85bcc8f63a/Phatbot-stoney/Phatbot-stoney/cmdshell.cpp
https://github.com/grimjoey/jlstudio/blob/e5d2d81f0a94d2020f2e912e43a487d9cb6f7c33/src/jls/process.cpp
https://github.com/Ai-Thinker-Open/Ai-Thinker-Open_ESP32-S2_SDK/blob/7d75213674b4572f90c68162ad6fe9b16dae65ad/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c
https://github.com/LeonColt/skripsi/blob/141af593ec65cd7adaedf7a90fc4cd7cde5cc602/Maschinen/RedirectIOChildProcess.cpp
redirect stdout and stderr
#include <windows.h>
#include <assert.h>
#include <stdio.h>
struct Stdio;
typedef void (*Callback)(struct Stdio* self, DWORD len);
struct Stdio {
OVERLAPPED ol;
HANDLE pipe;
BYTE buf[100];
Callback callback;
};
typedef struct CTX {
struct Stdio Stdout, Stderr, Stdin;
} CTX, *LCTX, *LPCTX;
HANDLE Hstdout=INVALID_HANDLE_VALUE;
HANDLE Hstderr=INVALID_HANDLE_VALUE;
DWORD WINAPI Worker(LPVOID iocp){
struct Stdio *stdio;
OVERLAPPED *ol;
DWORD dwIoSize;
for(;;){
if (!GetQueuedCompletionStatus(iocp, &dwIoSize, (PDWORD_PTR)&stdio, &ol, INFINITE) || dwIoSize==0 || ol==NULL || stdio==NULL){
switch (GetLastError()){
case ERROR_BROKEN_PIPE:
puts("the process has been exited, exit thread...");
break;
default:
printf("error = %d, exit thread\n", GetLastError());
}
break;
}
stdio->callback(stdio, dwIoSize);
}
return 0;
}
void OnStdoutRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstdout, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
void OnStderrRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstderr, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
int wmain(){
assert(Hstdout = GetStdHandle(STD_OUTPUT_HANDLE));
assert(Hstderr = GetStdHandle(STD_ERROR_HANDLE));
HANDLE Pstdout, Pstderr; // child process's
CTX ctx{.Stdout=Stdio{.callback=OnStdoutRead}, .Stderr=Stdio{.callback=OnStderrRead}};
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
HANDLE hThread = CreateThread(NULL, 0, Worker, iocp, 0, NULL); // Worker thread
SECURITY_ATTRIBUTES sa{.nLength=sizeof(SECURITY_ATTRIBUTES), .bInheritHandle=TRUE};
const WCHAR* pipe_name1 = L"\\\\.\\Pipe\\child-1";
assert((ctx.Stdout.pipe = CreateNamedPipeW(
pipe_name1,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert(INVALID_HANDLE_VALUE != (Pstdout = CreateFileW(
pipe_name1,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL)));
const WCHAR *pipe_name2 = L"\\\\.\\Pipe\\child-2";
assert((ctx.Stderr.pipe = CreateNamedPipeW(
pipe_name2,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((Pstderr = CreateFileW(
pipe_name2,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
STARTUPINFOW si{.cb = sizeof(si),
.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW,
.wShowWindow = SW_HIDE,
.hStdInput = GetStdHandle(STD_INPUT_HANDLE), // use current stdin
.hStdOutput = Pstdout,
.hStdError = Pstderr};
WCHAR cmd[] = L"powershell"; // or cmd, py, bash...
PROCESS_INFORMATION pInfo{};
assert(CreateProcessW(
NULL, cmd, NULL, NULL,
TRUE, 0, NULL, NULL,
&si, &pInfo));
assert(CloseHandle(Pstdout)); // we don't need this
assert(CloseHandle(Pstderr)); // we don't need this
assert(CreateIoCompletionPort(ctx.Stdout.pipe, iocp, (ULONG_PTR)&ctx.Stdout, 0));
assert(CreateIoCompletionPort(ctx.Stderr.pipe, iocp, (ULONG_PTR)&ctx.Stderr, 0));
ReadFile(ctx.Stdout.pipe, ctx.Stdout.buf, sizeof(ctx.Stdout.buf), NULL, &ctx.Stdout.ol);
ReadFile(ctx.Stderr.pipe, ctx.Stdout.buf, sizeof(ctx.Stderr.buf), NULL, &ctx.Stderr.ol);
WaitForSingleObject(pInfo.hProcess, INFINITE); // wait for process exit
PostQueuedCompletionStatus(iocp, 0, 0, NULL); // tell IOCP Worker exit
WaitForSingleObject(hThread, INFINITE); // wait for thread exit
assert(CloseHandle(hThread));
assert(CloseHandle(ctx.Stderr.pipe));
assert(CloseHandle(ctx.Stdout.pipe));
assert(CloseHandle(pInfo.hProcess));
assert(CloseHandle(iocp));
assert(CloseHandle(Hstderr));
puts("exit main function..."); // !!important: before close stdout
assert(CloseHandle(Hstdout));
}
Redirect stdin, stdout, stderr
#include <windows.h>
#include <assert.h>
#include <stdio.h>
static HANDLE Hstdout, Hstderr, Hstdin, HstopEvent;
struct Stdio;
typedef void (*Callback)(struct Stdio* self, DWORD len);
struct Stdio {
OVERLAPPED ol;
HANDLE pipe;
BYTE buf[100];
Callback callback;
};
typedef struct CTX {
struct Stdio Stdout, Stderr, Stdin;
} CTX, *LCTX, *LPCTX;
DWORD WINAPI Worker(LPVOID iocp){
struct Stdio *stdio;
OVERLAPPED *ol;
DWORD dwIoSize;
for(;;){
if (!GetQueuedCompletionStatus(iocp, &dwIoSize, (PDWORD_PTR)&stdio, &ol, INFINITE) || dwIoSize==0 || ol==NULL || stdio==NULL){
switch (GetLastError()){
case ERROR_BROKEN_PIPE:
SetEvent(HstopEvent);
puts("the process has been exited, exit thread...");
break;
default:
printf("error = %d, exit thread\n", GetLastError());
}
break;
}
stdio->callback(stdio, dwIoSize);
}
return 0;
}
void OnStdoutRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstdout, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
void OnStderrRead(struct Stdio *self, DWORD len){
WriteConsoleA(Hstderr, self->buf, len, NULL, NULL);
ReadFile(self->pipe, self->buf, sizeof(self->buf), NULL, &self->ol);
}
void OnStdinWriteComplete(struct Stdio *self, DWORD len){
printf("[%u bytes write to stdin]\n", len);
}
int wmain(){
assert((Hstdout = GetStdHandle(STD_OUTPUT_HANDLE))!=INVALID_HANDLE_VALUE);
assert((Hstderr = GetStdHandle(STD_ERROR_HANDLE))!=INVALID_HANDLE_VALUE);
assert((Hstdin = GetStdHandle(STD_INPUT_HANDLE))!=INVALID_HANDLE_VALUE);
assert((HstopEvent=CreateEventW(NULL, FALSE, FALSE, NULL))!=INVALID_HANDLE_VALUE);
CTX ctx{.Stdout=Stdio{.callback=OnStdoutRead}, .Stderr=Stdio{.callback=OnStderrRead}, .Stdin=Stdio{.callback=OnStdinWriteComplete}};
STARTUPINFOW si{.cb = sizeof(si), .dwFlags = STARTF_USESTDHANDLES};
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
HANDLE hThread = CreateThread(NULL, 0, Worker, iocp, 0, NULL); // Worker thread
SECURITY_ATTRIBUTES sa{.nLength=sizeof(SECURITY_ATTRIBUTES), .bInheritHandle=TRUE};
const WCHAR* pipe_name1 = L"\\\\.\\Pipe\\child-1";
assert((ctx.Stdout.pipe = CreateNamedPipeW(
pipe_name1,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((si.hStdOutput = CreateFileW(
pipe_name1,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
const WCHAR *pipe_name2 = L"\\\\.\\Pipe\\child-2";
assert((ctx.Stderr.pipe = CreateNamedPipeW(
pipe_name2,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((si.hStdError = CreateFileW(
pipe_name2,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
const WCHAR *pipe_name3 = L"\\\\.\\Pipe\\child-3";
assert((ctx.Stdin.pipe = CreateNamedPipeW(
pipe_name3,
PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE,
1,
4096,
4096,
5000,
NULL))!=INVALID_HANDLE_VALUE);
assert((si.hStdInput = CreateFileW(
pipe_name3,
GENERIC_READ,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL))!=INVALID_HANDLE_VALUE);
WCHAR cmd[] = L"powershell"; // or cmd, py, bash...
PROCESS_INFORMATION pInfo{};
assert(CreateProcessW(
NULL, cmd, NULL, NULL,
TRUE, 0, NULL, NULL,
&si, &pInfo));
assert(CloseHandle(si.hStdError)); // we don't need this
assert(CloseHandle(si.hStdInput)); // we don't need this
assert(CloseHandle(si.hStdOutput)); // we don't need this
assert(CreateIoCompletionPort(ctx.Stdout.pipe, iocp, (ULONG_PTR)&ctx.Stdout, 0));
assert(CreateIoCompletionPort(ctx.Stderr.pipe, iocp, (ULONG_PTR)&ctx.Stderr, 0));
ReadFile(ctx.Stdout.pipe, ctx.Stdout.buf, sizeof(ctx.Stdout.buf), NULL, &ctx.Stdout.ol);
ReadFile(ctx.Stderr.pipe, ctx.Stdout.buf, sizeof(ctx.Stderr.buf), NULL, &ctx.Stderr.ol);
DWORD dwIoSize;
for(;;){
CHAR buf[100];
ReadConsoleA(Hstdin, buf, sizeof(buf), &dwIoSize, NULL);
if (WaitForSingleObject(HstopEvent, 0)==WAIT_OBJECT_0)
break;
WriteFile(ctx.Stdin.pipe, buf, dwIoSize, NULL, &ctx.Stdin.ol);
if (WaitForSingleObject(HstopEvent, 0)==WAIT_OBJECT_0)
break;
}
PostQueuedCompletionStatus(iocp, 0, 0, NULL); // tell IOCP Worker exit
WaitForSingleObject(hThread, INFINITE); // wait for thread exit
assert(CloseHandle(hThread));
assert(CloseHandle(ctx.Stderr.pipe));
assert(CloseHandle(ctx.Stdout.pipe));
assert(CloseHandle(pInfo.hProcess));
assert(CloseHandle(iocp));
assert(CloseHandle(Hstderr));
assert(CloseHandle(HstopEvent));
puts("exit main function..."); // !!important: before close stdout
assert(CloseHandle(Hstdout));
}

Related

How to exclude remote Windows MailSlot access for universal well-known LOCAL SIDs?

I try to windows Mailslots for interprocess communication but I'd like to refuse any remote communication.
I set well-known LOCAL sid for my mailslot BUT I still could write to mailslot from another computer in my domain
SID_IDENTIFIER_AUTHORITY sid_auth_local = SECURITY_LOCAL_SID_AUTHORITY;
if (AllocateAndInitializeSid(&sid_auth_local, 1,
SECURITY_LOCAL_LOGON_RID, 0, 0, 0, 0, 0, 0, 0, &localSid))
client:
if ((mailslot = CreateFileA("\\\\MYDOMAIN\\mailslot\\MYSLOT", GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
I've attached client server example.
What is wrong here? Is there the way to exclude remote connection through mailslots?
Thx.
server example:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <accctrl.h>
#include <aclapi.h>
int main(void)
{
char buffer[4];
DWORD readBytes;
DWORD res;
HANDLE mailslot;
PSID localSid = NULL;
PACL acl = NULL;
SECURITY_ATTRIBUTES *p_sa = NULL;
SECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS_A ea;
SECURITY_ATTRIBUTES sa;
SID_IDENTIFIER_AUTHORITY sid_auth_local = SECURITY_LOCAL_SID_AUTHORITY;
if (AllocateAndInitializeSid(&sid_auth_local, 1,
SECURITY_LOCAL_LOGON_RID, 0, 0, 0, 0, 0, 0, 0, &localSid)) //SECURITY_LOCAL_LOGON_RID
{
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = (LPSTR)localSid;
if (SetEntriesInAclA(1, &ea, NULL, &acl) == ERROR_SUCCESS &&
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) &&
SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
{
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
p_sa = &sa;
}
}
if ((mailslot = CreateMailslot(L"\\\\.\\mailslot\\MYSLOT", 2048, MAILSLOT_WAIT_FOREVER, p_sa)) == INVALID_HANDLE_VALUE)
{
printf("Failed to create a MailSlot %d\n", GetLastError());
return 0;
}
if (localSid) FreeSid(localSid);
if (acl) LocalFree(acl);
while ((res = ReadFile(mailslot, buffer, 4, &readBytes, NULL)) != 0)
{
printf("Received %d bytes %s\n", readBytes, buffer);
}
CloseHandle(mailslot);
return 0;
}
client example:
#include <windows.h>
#include <stdio.h>
void main(int argc, char *argv[])
{
HANDLE mailslot;
DWORD writtenBytes;
if ((mailslot = CreateFileA("\\\\MYDOMAIN\\mailslot\\MYSLOT", GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with error %d\n", GetLastError());
return;
}
if (WriteFile(mailslot, "Hi\n", 3, &writtenBytes, NULL) == 0)
{
printf("WriteFile failed with error %d\n", GetLastError());
return;
}
printf("Wrote %d bytes\n", writtenBytes);
CloseHandle(mailslot);
}

Execute CMD.EXE with CreateProcessWithLogonW() without a new console

I have to run cmd.exe with CreateProcessWithLogonW() but in the context of my program without creating another console, but MSDN says the CREATE_NEW_CONSOLE flag has been set by default. How can I unset this flag so this API doesn't create a new window for my child process?
The following code shows how this API is used in my program. I don't want the new program to run in a new console, but I could not find a solution for that.
BOOL status = FALSE;
DWORD process_flags = 0 | arg_process_flags;
DWORD logon_flags = 0 | arg_logon_flags;
PTSTR duplicate_command_Line;
PPROCESS_INFORMATION ptr_process_info;
STARTUPINFO startup_info;
RtlZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
if (ptr_process_info = arg_process_infos ? arg_process_infos : (PPROCESS_INFORMATION)LocalAlloc(LPTR, sizeof(PROCESS_INFORMATION)))
{
if (duplicate_command_Line = _wcsdup(arg_command_Line))
{
switch (arg_type)
{
case KULL_M_PROCESS_CREATE_NORMAL:
status = CreateProcess(NULL, duplicate_command_Line, NULL, NULL, FALSE, process_flags, NULL, NULL, &startup_info, ptr_process_info);
break;
case KULL_M_PROCESS_CREATE_USER:
status = CreateProcessAsUser(arg_user_token, NULL, duplicate_command_Line, NULL, NULL, FALSE, process_flags, NULL, NULL, &startup_info, ptr_process_info);
break;
case KULL_M_PROCESS_CREATE_LOGON:
status = CreateProcessWithLogonW(arg_user, arg_domain, arg_password, logon_flags, NULL, duplicate_command_Line, process_flags, NULL, NULL, &startup_info, ptr_process_info);
break;
}
if (status && (arg_auto_close_handle || !arg_process_infos))
{
CloseHandle(ptr_process_info->hThread);
CloseHandle(ptr_process_info->hProcess);
}
if (!arg_process_infos)
LocalFree(ptr_process_info);
free(duplicate_command_Line);
}
}
You could redirected input and output of child process
Here's my test program(remove the error checking).
Parent:
#include <windows.h>
#include <iostream>
#define BUFSIZE 4096
void main()
{
printf("in Parent \n");
HANDLE R_In, R_Out, R_err, W_In, W_Out, W_err;
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
SECURITY_ATTRIBUTES saAttr;
BOOL bSuccess;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&R_In, &W_In, &saAttr, 0);
CreatePipe(&R_Out, &W_Out, &saAttr, 0);
CreatePipe(&R_err, &W_err, &saAttr, 0);
PROCESS_INFORMATION process_info;
STARTUPINFO startup_info;
RtlZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
startup_info.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
startup_info.wShowWindow = SW_HIDE;
startup_info.hStdInput = R_In;
startup_info.hStdOutput = W_Out;
startup_info.hStdError = W_err;
BOOL ret = CreateProcessWithLogonW(L"username",L"domain",L"password", 0,L"ChildProcess.exe",NULL, CREATE_NO_WINDOW,NULL,NULL,&startup_info,&process_info);
CloseHandle(R_In);
CloseHandle(W_Out);
CloseHandle(W_err);
CHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
bSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
bSuccess = WriteFile(W_In, chBuf, dwRead, &dwWritten, NULL);
while (1)
{
bSuccess = ReadFile(R_Out, chBuf, BUFSIZE, &dwRead, NULL);
if (bSuccess == 0 & GetLastError() == ERROR_BROKEN_PIPE) // child process exit.
break;
bSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
}
WaitForSingleObject(process_info.hProcess, INFINITE);
printf("Parent exit\n");
}
Child:
#include <windows.h>
#include <iostream>
#define BUFSIZE 4096
#pragma warning(disable : 4996)
void main()
{
CHAR chBuf[BUFSIZE];
scanf("%s", chBuf);
printf("in Child %s\n", chBuf);
printf("Child exit\n");
return;
}
Result:
Do you mean you don't want to create a new window?
try startup_info.dwFlags = STARTF_USESHOWWINDOW;startup_info.wShowWindow = SW_HIDE; then it won't create a window.
It's been awhile, but passing DETACHED_PROCESS should work.
If not, you can call CreateProcessWithLogonW passing it a win32 binary that you provide (possibly your own with different options) that in turn will call CreateProcess opening cmd.exe without passing CREATE_NEW_CONSOLE.
Unless you're already admin, creating in the same console is utterly impossible, and if you are admin, it's an arcane technique you're better off not using.

CreateEvent initial state signaled is not signaling event

I am working on IO redirection program and i successfully created poc for it. The program spawn the child process and communicate with it using named pipes. I used Event object to get event whenever there is data on the pipe. I set the event to signaled state by default but i am not getting the event for the first time. To get the event i have to write on input pipe. When i write some command on input pipe i get the event and and get the output for the old command, not the current command(Please see the output).
below is the working code.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <thread>
#include <string>
using namespace std;
#define input_pipe_name L"\\\\.\\pipe\\input"
#define output_pipe_name L"\\\\.\\pipe\\output"
#define process_name L"cmd.exe"
HANDLE input_pipe_handle;
HANDLE output_pipe_handle;
HANDLE input_file_handle;
HANDLE output_file_handle;
OVERLAPPED output_overlapped = { 0 };
BOOL InitHandels()
{
input_pipe_handle = CreateNamedPipe(input_pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 120000, 0);
SetHandleInformation(input_pipe_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
if (input_pipe_handle == INVALID_HANDLE_VALUE)
{
cout << "pipe creation error: " << GetLastError() << endl;
return FALSE;
}
output_pipe_handle = CreateNamedPipe(output_pipe_name, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 120000, 0);
SetHandleInformation(output_pipe_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
if (output_pipe_handle == INVALID_HANDLE_VALUE)
{
cout << "pipe creation error: " << GetLastError() << endl;
return FALSE;
}
input_file_handle = CreateFile(input_pipe_name, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (input_file_handle == INVALID_HANDLE_VALUE)
{
cout << "file creation error: " << GetLastError() << endl;
return FALSE;
}
output_file_handle = CreateFile(output_pipe_name, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (output_file_handle == INVALID_HANDLE_VALUE)
{
cout << "file creation error: " << GetLastError() << endl;
return FALSE;
}
output_overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
ConnectNamedPipe(output_pipe_handle, &output_overlapped);
}
void CreateChildProcess()
{
TCHAR szCmdline[] = L"cmd.exe";
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = output_pipe_handle;
siStartInfo.hStdOutput = output_pipe_handle;
siStartInfo.hStdInput = input_pipe_handle;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
{
cout << "process creation error: " << GetLastError() << endl;
//return FALSE;
}
else
{
HANDLE h_array[] = {output_overlapped.hEvent, piProcInfo.hProcess};
for (;;)
{
DWORD result = WaitForMultipleObjects(2, h_array, FALSE, 1000);
DWORD bwritten = 0, bread = 0;
char buffer[4096];
switch (result)
{
case WAIT_TIMEOUT:
//cout << "TimeOut" << endl;
break;
case WAIT_OBJECT_0:
ReadFile(output_file_handle, buffer, sizeof(buffer), &bread, &output_overlapped);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, bread, &bwritten, 0);
ResetEvent(output_overlapped.hEvent);
break;
case WAIT_OBJECT_0 + 1:
break;
//return FALSE;
}
}
}
}
int main()
{
DWORD bwritten;
InitHandels();
//CreateChildProcess();
std::thread t1(CreateChildProcess);
for (;;Sleep(1000))
{
std::string mystring;
std::cin >> mystring;
mystring.append("\n");
WriteFile(input_file_handle, mystring.c_str(), mystring.length(), &bwritten, &output_overlapped);
//WriteFile(input_file_handle, "dir\n", 4, &bwritten, &output_overlapped);
}
t1.join();
return 0;
}
I get the following output
dir
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
D:\Programming\VS\to_post_on_stack\to_post_on_stack>hello
dir
Volume in drive D has no label.
Volume Serial Number is 54FB-7A94
Directory of D:\Programming\VS\to_post_on_stack\to_post_on_stack
01/13/2018 05:36 PM <DIR> .
01/13/2018 05:36 PM <DIR> ..
01/13/2018 05:36 PM <DIR> Debug
01/12/2018 08:54 PM 608 stdafx.cpp
01/12/2018 08:54 PM 642 stdafx.h
01/12/2018 08:54 PM 630 targetver.h
01/13/2018 05:36 PM 7,434 to_post_on_stack.cpp
01/12/2018 08:54 PM 8,038 to_post_on_stack.vcxproj
01/12/2018 08:54 PM 1,277 to_post_on_stack.vcxproj.filters
6 File(s) 18,629 bytes
3 Dir(s) 39,347,019,776 bytes free
D:\Programming\VS\to_post_on_stack\to_post_on_stack>dir
hello
'hello' is not recognized as an internal or external command,
operable program or batch file.
D:\Programming\VS\to_post_on_stack\to_post_on_stack>dir
As you can see in the output when i send dir command i get the old output. When i send hello i get the output for the dir command which i executed before hello.
SO can anyone point out the mistake that why i am not getting signal for the very first time. And why the output is not getting in sequence?
the code example full of critical bugs:
the first and main:
If hFile was opened with FILE_FLAG_OVERLAPPED, the following
conditions are in effect:
The lpOverlapped parameter must point to a valid and unique
OVERLAPPED structure, otherwise the function can incorrectly report
that the io operation is complete.
and
io operation resets the event specified by the hEvent member of the
OVERLAPPED structure to a nonsignaled state when it begins the I/O
operation. Therefore, the caller does not need to do that.
when io operation is complete - io subsystem write to lpOverlapped final status of operation, number of bytes transferred, and if it containing event - set this event to signal state. if you use the same lpOverlapped in concurrent - they overwrite result each other, and you never know - which operation is really complete - event is one, common !, also if you use event - system reset event before begin io - as result - one operation can complete and set event, then another operation reset it after this
you call in 2 threads in concurrent:
WriteFile(input_file_handle, ..&output_overlapped);
ReadFile(output_file_handle, .. &output_overlapped);
with this you already have UB because the same &output_overlapped used in concurrent. we need allocate unique overlapped to every operation. and if you use events for detect completion - you need create several events - this is not good way at all. much better use iocp completion here - we not need create events, we not need create separate thread.
ReadFile(output_file_handle, buffer, sizeof(buffer), &bread, &output_overlapped);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, bread, &bwritten, 0);
ResetEvent(output_overlapped.hEvent);
at first ReadFile resets the event specified by the hEvent member of the OVERLAPPED structure to a nonsignaled state when it begins the I/O operation. Therefore, the caller does not need to do that. and more - when you call ResetEvent - operation can be already completed - so you reset already signaled event - and as result you lost completion signal. if call ReasetEvent this need do before io operation (ReadFile in concrete case) but not after - which is error. however we not need do this and before - because io subsystem anyway do this.
else one critical bug - we can not use buffer, breadin WriteFile just after asynchronous call to ReadFile - the call is can be not completed yet. and context of buffer yet not defined.
the &bread is undefined always in asynchronous call and must not be used at all
The lpNumberOfBytesRead parameter should be set to NULL. Use the
GetOverlappedResult function to get the actual number of bytes read.
If the hFile parameter is associated with an I/O completion port,
you can also get the number of bytes read by calling the
GetQueuedCompletionStatus function.
else one very common mistake - that we create 2 pipe pairs (input_pipe_handle, output_file_handle) - this is absolute not need - we can use the 1 pipe pair.
the call to SetHandleInformation excess - we need just create handle with inherit properties via SECURITY_ATTRIBUTES.
code example:
//#define _XP_SUPPORT_
struct IO_COUNT
{
HANDLE _hFile;
HANDLE _hEvent;
LONG _dwIoCount;
IO_COUNT()
{
_dwIoCount = 1;
_hEvent = 0;
}
~IO_COUNT()
{
if (_hEvent)
{
CloseHandle(_hEvent);
}
}
ULONG Create(HANDLE hFile);
void BeginIo()
{
InterlockedIncrement(&_dwIoCount);
}
void EndIo()
{
if (!InterlockedDecrement(&_dwIoCount))
{
SetEvent(_hEvent);
}
}
void Wait()
{
WaitForSingleObject(_hEvent, INFINITE);
}
};
class U_IRP : OVERLAPPED
{
enum { connect, read, write };
IO_COUNT* _pIoObject;
ULONG _code;
LONG _dwRef;
char _buffer[256];
~U_IRP()
{
_pIoObject->EndIo();
}
ULONG Read()
{
_code = read;
AddRef();
return CheckIoResult(ReadFile(_pIoObject->_hFile, _buffer, sizeof(_buffer), 0, this));
}
ULONG CheckIoResult(BOOL fOk)
{
if (fOk)
{
#ifndef _XP_SUPPORT_
OnIoComplete(NOERROR, InternalHigh);
#endif
return NOERROR;
}
ULONG dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_IO_PENDING)
{
OnIoComplete(dwErrorCode, 0);
}
return dwErrorCode;
}
VOID OnIoComplete(DWORD dwErrorCode, DWORD_PTR dwNumberOfBytesTransfered)
{
switch (_code)
{
case connect:
switch (dwErrorCode)
{
case ERROR_PIPE_CONNECTED:
case ERROR_NO_DATA:
dwErrorCode = NOERROR;
case NOERROR:
Read();
}
break;
case read:
if (dwErrorCode == NOERROR)
{
if (dwNumberOfBytesTransfered)
{
if (int cchWideChar = MultiByteToWideChar(CP_OEMCP, 0, _buffer, (ULONG)dwNumberOfBytesTransfered, 0, 0))
{
PWSTR wz = (PWSTR)alloca(cchWideChar * sizeof(WCHAR));
if (MultiByteToWideChar(CP_OEMCP, 0, _buffer, (ULONG)dwNumberOfBytesTransfered, wz, cchWideChar))
{
if (int cbMultiByte = WideCharToMultiByte(CP_ACP, 0, wz, cchWideChar, 0, 0, 0, 0))
{
PSTR sz = (PSTR)alloca(cbMultiByte);
if (WideCharToMultiByte(CP_ACP, 0, wz, cchWideChar, sz, cbMultiByte, 0, 0))
{
DbgPrint("%.*s", cbMultiByte, sz);
}
}
}
}
}
Read();
}
break;
case write:
break;
default:
__debugbreak();
}
Release();
if (dwErrorCode)
{
DbgPrint("[%u]: error=%u\n", _code, dwErrorCode);
}
}
static VOID WINAPI _OnIoComplete(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
)
{
static_cast<U_IRP*>(lpOverlapped)->OnIoComplete(RtlNtStatusToDosError(dwErrorCode), dwNumberOfBytesTransfered);
}
public:
void AddRef()
{
InterlockedIncrement(&_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_dwRef)) delete this;
}
U_IRP(IO_COUNT* pIoObject) : _pIoObject(pIoObject)
{
_dwRef = 1;
pIoObject->BeginIo();
RtlZeroMemory(static_cast<OVERLAPPED*>(this), sizeof(OVERLAPPED));
}
ULONG Write(const void* pvBuffer, ULONG cbBuffer)
{
_code = write;
AddRef();
return CheckIoResult(WriteFile(_pIoObject->_hFile, pvBuffer, cbBuffer, 0, this));
}
ULONG Connect()
{
_code = connect;
AddRef();
return CheckIoResult(ConnectNamedPipe(_pIoObject->_hFile, this));
}
static ULONG Bind(HANDLE hFile)
{
return BindIoCompletionCallback(hFile, U_IRP::_OnIoComplete, 0)
#ifndef _XP_SUPPORT_
&& SetFileCompletionNotificationModes(hFile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)
#endif
? NOERROR : GetLastError();
}
};
ULONG IO_COUNT::Create(HANDLE hFile)
{
_hFile = hFile;
if (_hEvent = CreateEvent(0, TRUE, FALSE, 0))
{
return U_IRP::Bind(hFile);
}
return GetLastError();
}
void ChildTest()
{
static const WCHAR name[] = L"\\\\?\\pipe\\somename";
HANDLE hFile = CreateNamedPipeW(name,
PIPE_ACCESS_DUPLEX|FILE_READ_DATA|FILE_WRITE_DATA|FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 1, 0, 0, NMPWAIT_USE_DEFAULT_WAIT, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
IO_COUNT obj;
if (obj.Create(hFile) == NOERROR)
{
BOOL fOk = FALSE;
static SECURITY_ATTRIBUTES sa = { sizeof(sa), 0, TRUE };
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdError = CreateFileW(name, FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);
if (si.hStdError != INVALID_HANDLE_VALUE)
{
si.hStdInput = si.hStdOutput = si.hStdError;
WCHAR ApplicationName[MAX_PATH];
if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
{
if (CreateProcessW(ApplicationName , 0, 0, 0, TRUE, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
fOk = TRUE;
}
}
CloseHandle(si.hStdError);
}
if (fOk)
{
U_IRP* p;
if (p = new U_IRP(&obj))
{
p->Connect();
p->Release();
}
obj.EndIo();
//++ simulate user commands
static PCSTR commands[] = { "dir\r\n", "ver\r\n", "exit\r\n" };
ULONG n = RTL_NUMBER_OF(commands);
PCSTR* psz = commands;
do
{
if (p = new U_IRP(&obj))
{
PCSTR command = *psz++;
p->Write(command, (ULONG)strlen(command) * sizeof(CHAR));
p->Release();
}
} while (--n);
//--
obj.Wait();
}
}
CloseHandle(hFile);
}
}

Named Pipes, Server question

I'm hanging on the WaitNamedPipe function even though I called CreateNamedPipe right before. Since waitnamedpipe function just waits for the initiation of the pipe, why? code is below. thanks
PROCESS_INFORMATION po;
STARTUPINFO
s;
GetStartupInfo (&s);
if(CreateProcess ("c:\s2.exe", NULL, NULL, NULL, false, 0, NULL,
NULL, &s, &po) == FALSE)
{
printf("Error %d starting CC\n",
GetLastError());
exit(-1);
}
HANDLE pipe=CreateNamedPipe (pipe_name, 0x00000003,
FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_UNLIMITED_INSTANCES,128, 128, 0,
NULL);
while(WaitNamedPipe(pipe_name, INFINITE)==FALSE) Sleep(300);
HANDLE CC = CreateFile (pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);
bool fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE :
(GetLastError() ==
ERROR_PIPE_CONNECTED);
if(fConnected) printf("true");
else printf("false");
"C:\s2.exe" is not "C:\\s2.exe"

Using IOCTL_MOUNTMGR_QUERY_POINTS

I am not able to know how to use the IOCTL_MOUNTMGR_QUERY_POINTS .
I have searched the internet and found some sample code to try with.
but i am not sure whether its correct or not....
can you please let me know how to use the IOCTL_MOUNTMGR_QUERY_POINTS to get the drive letter
Thank you for your time
below is my source coode
HANDLE hUsbDevice = CreateFile( pDetData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
UCHAR Bytes[10000];
PMOUNTMGR_MOUNT_POINTS pMntPoints = (PMOUNTMGR_MOUNT_POINTS) Bytes;
MOUNTMGR_MOUNT_POINT mntPoint, *pmnt;
DWORD bytesReturned;
if (hUsbDevice == INVALID_HANDLE_VALUE) {
qDebug()<<"CreateFile failed with error: %d\n"<<GetLastError();
}
else {
qDebug ()<<"VALID DEVICE";
BOOL status = DeviceIoControl( hUsbDevice,
IOCTL_MOUNTMGR_QUERY_POINTS,
&mntPoint,
sizeof(MOUNTMGR_MOUNT_POINT),
pMntPoints,
10000,
&bytesReturned,
NULL);
wprintf(L"\tBOOL VALUE : %d\n", status);
qDebug ()<<pMntPoints->MountPoints;
}
OK! Here is a code example, but written without any error control to make it shorter:
#include <windows.h>
#include <C:\WinDDK\7600.16385.1\inc\ddk\mountmgr.h>
#include <tchar.h>
#include <stdio.h>
#pragma comment(lib, "Crypt32.lib")
int main()
{
TCHAR chDrive = 'N', szUniqueId[128];
TCHAR szDeviceName[7] = _T("\\\\.\\");
HANDLE hDevice, hMountMgr;
BYTE byBuffer[1024];
PMOUNTDEV_NAME pMountDevName;
DWORD cbBytesReturned, dwInBuffer, dwOutBuffer, ccb;
PMOUNTMGR_MOUNT_POINT pMountPoint;
BOOL bSuccess;
PBYTE pbyInBuffer, pbyOutBuffer;
LPTSTR pszLogicalDrives, pszDriveRoot;
// MOUNTMGR_DOS_DEVICE_NAME is defined as L"\\\\.\\MountPointManager"
hMountMgr = CreateFile (MOUNTMGR_DOS_DEVICE_NAME,
0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hMountMgr == INVALID_HANDLE_VALUE)
return 1;
cbBytesReturned = GetLogicalDriveStrings (0, NULL);
pszLogicalDrives = (LPTSTR) LocalAlloc (LMEM_ZEROINIT,
cbBytesReturned*sizeof(TCHAR));
cbBytesReturned = GetLogicalDriveStrings (cbBytesReturned,
pszLogicalDrives);
for (pszDriveRoot = pszLogicalDrives; *pszDriveRoot != TEXT('\0');
pszDriveRoot += lstrlen(pszDriveRoot) + 1) {
szDeviceName[4] = pszDriveRoot[0];
szDeviceName[5] = _T(':');
szDeviceName[6] = _T('\0');
//lstrcpy (&szDeviceName[4], TEXT("\\??\\USBSTOR\\DISK&VEN_SANDISK&PROD_CRUZER&REV_8.01\\1740030578903736&0"));
hDevice = CreateFile (szDeviceName, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
return 1;
bSuccess = DeviceIoControl (hDevice,
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
NULL, 0,
(LPVOID)byBuffer, sizeof(byBuffer),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
pMountDevName = (PMOUNTDEV_NAME) byBuffer;
_tprintf (TEXT("\n%.*ls\n"), pMountDevName->NameLength/sizeof(WCHAR),
pMountDevName->Name);
bSuccess = CloseHandle (hDevice);
dwInBuffer = pMountDevName->NameLength + sizeof(MOUNTMGR_MOUNT_POINT);
pbyInBuffer = (PBYTE) LocalAlloc (LMEM_ZEROINIT, dwInBuffer);
pMountPoint = (PMOUNTMGR_MOUNT_POINT) pbyInBuffer;
pMountPoint->DeviceNameLength = pMountDevName->NameLength;
pMountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
CopyMemory (pbyInBuffer + sizeof(MOUNTMGR_MOUNT_POINT),
pMountDevName->Name, pMountDevName->NameLength);
dwOutBuffer = 1024 + sizeof(MOUNTMGR_MOUNT_POINTS);
pbyOutBuffer = (PBYTE) LocalAlloc (LMEM_ZEROINIT, dwOutBuffer);
bSuccess = DeviceIoControl (hMountMgr,
IOCTL_MOUNTMGR_QUERY_POINTS,
pbyInBuffer, dwInBuffer,
(LPVOID)pbyOutBuffer, dwOutBuffer,
&cbBytesReturned,
(LPOVERLAPPED) NULL);
if (bSuccess) {
ULONG i;
PMOUNTMGR_MOUNT_POINTS pMountPoints = (PMOUNTMGR_MOUNT_POINTS) pbyOutBuffer;
for (i=0; i<pMountPoints->NumberOfMountPoints; i++) {
_tprintf (TEXT("#%i:\n"), i);
_tprintf (TEXT(" Device=%.*ls\n"),
pMountPoints->MountPoints[i].DeviceNameLength/sizeof(WCHAR),
pbyOutBuffer + pMountPoints->MountPoints[i].DeviceNameOffset);
_tprintf (TEXT(" SymbolicLink=%.*ls\n"),
pMountPoints->MountPoints[i].SymbolicLinkNameLength/sizeof(WCHAR),
pbyOutBuffer + pMountPoints->MountPoints[i].SymbolicLinkNameOffset);
ccb = sizeof(szUniqueId)/sizeof(szUniqueId[0]);
if (CryptBinaryToString (pbyOutBuffer + pMountPoints->MountPoints[i].UniqueIdOffset,
pMountPoints->MountPoints[i].UniqueIdLength,
CRYPT_STRING_BASE64,
szUniqueId, &ccb))
_tprintf (TEXT(" UniqueId=%s\n"), szUniqueId);
else
_tprintf (TEXT(" UniqueId=%.*ls\n"),
pMountPoints->MountPoints[i].UniqueIdLength/sizeof(WCHAR),
pbyOutBuffer + pMountPoints->MountPoints[i].UniqueIdOffset);
}
}
pbyInBuffer = (PBYTE) LocalFree (pbyInBuffer);
pbyOutBuffer = (PBYTE) LocalFree (pbyOutBuffer);
}
pszLogicalDrives = (LPTSTR) LocalFree (pszLogicalDrives);
bSuccess = CloseHandle (hMountMgr);
return 0;
}
if produce on my computer the output like
\Device\HarddiskVolume3
#0:
Device=\Device\HarddiskVolume3
SymbolicLink=\DosDevices\C:
UniqueId=O5TWlQAAwBRIAAAA
#1:
Device=\Device\HarddiskVolume3
SymbolicLink=\??\Volume{12703dc4-bf56-11db-8c6c-806e6f6e6963}
UniqueId=O5TWlQAAwBRIAAAA
...
\Device\CdRom2
#0:
Device=\Device\CdRom2
SymbolicLink=\DosDevices\L:
UniqueId=\??\USBSTOR#CdRom&Ven_HL-DT-ST&Prod_DVDRAM_GE20LU11&Rev_CL01#0010101640008B615&0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
#1:
Device=\Device\CdRom2
SymbolicLink=\??\Volume{2c5f6a93-2b50-11df-aa6a-005056c00008}
UniqueId=\??\USBSTOR#CdRom&Ven_HL-DT-ST&Prod_DVDRAM_GE20LU11&Rev_CL01#0010101640008B615&0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
\Device\HarddiskVolume8
#0:
Device=\Device\HarddiskVolume8
SymbolicLink=\DosDevices\N:
UniqueId=_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer&Rev_8.01#1740030578903736&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
#1:
Device=\Device\HarddiskVolume8
SymbolicLink=\??\Volume{ae08a3c8-71cf-11de-bc1d-005056c00008}
UniqueId=_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer&Rev_8.01#1740030578903736&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}