1

I am wanting to pass an anonymous Pipe HANDLE to a Child Process. This answer seems to explain it well for C++, however I am wanting to do this in C.

Do I convert the handle into an integer? Or do I pass the memory address of the HANDLE to the child process, and then make another HANDLE pointing to that?

For example:

Parent:

    BOOL bCreatePipe, bReadFile;
    HANDLE hRead = NULL;
    HANDLE hWrite = NULL;
    SECURITY_ATTRIBUTES lpPipeAttributes;
    lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
    lpPipeAttributes.lpSecurityDescriptor = NULL;
    lpPipeAttributes.bInheritHandle = TRUE;

    // Create pipe file descriptors for parent and child
    bCreatePipe = CreatePipe(&hRead, &hWrite, &lpPipeAttributes, (DWORD)BUFFER_SIZE);
    if (bCreatePipe == FALSE) {
        printf("[-]Error creating IPC pipe : %d", GetLastError());
        exit(-1);
    }

    // Create command line arguments for child process
    snprintf(child_cmd, CMD_LINE_SIZE, "%d", &hWrite);

    // Create child process to handle request
    if ( !CreateProcess(
         "C:\\Users\\Child.exe",        // No module name (use command line)
         child_cmd,      // Command line
         NULL,           // Process handle not inheritable
         NULL,           // Thread handle not inheritable
         TRUE,           // Set handle inheritance to TRUE (for pipe)
         0,              // No creation flags
         NULL,           // Use parent's environment block
         NULL,           // Use parent's starting directory
         &si,            // Pointer to STARTUPINFO structure
         &pi)            // Pointer to PROCESS_INFORMATION structure
         )
    {
        printf("[-]CreateProcess failed : %d\n", GetLastError());
        exit(-1);
    }

Child:

// Set variables to arguments passed by parent 
HANDLE hWrite = atoi(argv[0]);
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Wizard
  • 1,533
  • 4
  • 19
  • 32
  • 1
    It might be easier to just use a named pipe. – Shawn Sep 05 '18 at 05:25
  • @Shawn: this appears to be using Windows, where named pipes are a lot more complicated than on UNIX-type systems. – cdarke Sep 05 '18 at 07:15
  • There is very little on the answer you link to that is C++ specific, just the `cout` (replace with `printf`) and ignore the `::` at the start of global API calls. The include files will probably be `stdio.h` and `windows.h`. A `HANDLE` is an `unsigned int` by the way. Passing an address to a child process is *usually* pointless, since it has a different address space. – cdarke Sep 05 '18 at 07:18
  • @cdarke - `HANDLE` is not `unsigned int` (32 bit always) - it is `void*` so `UINT_PTR` if want (64 bit in 64 bit system) – RbMm Sep 05 '18 at 07:25
  • @RbMm: sorry, that's changed then. – cdarke Sep 05 '18 at 08:03

1 Answers1

1

yes, this is ok pass HANDLE by value. in practice currently your code will be work ok. however need remember that HANDLE is 64-bit size on 64-bit system - so not fit in int which is 32-bit size (now user mode handle values in practice fit to 32bit). so need use say %I64x format to encode handle value and _atoi64 or _wcstoi64 to decode.

for example in parent:

WCHAR child_cmd[32];
swprintf(child_cmd, L"<%I64x>", (ULONG64)(ULONG_PTR)hWrite);

and in child:

HANDLE hWrite = 0;
if (PWSTR sz = wcschr(GetCommandLineW(), '<'))
{
    hWrite = (HANDLE)(ULONG_PTR)_wcstoi64(sz + 1, &sz, 16);
    if (*sz != '>')
    {
        hWrite = 0;
    }
}

as separate note - use CreatePipe not the best choice - this api very bad design, say one handle only for write, another only for read, can not select asynchronous I/O, can not make one handle inherit and another not (as need in this case) - better use CreateNamedPipeW + CreateFileW for create pipe pair. or this way if you want no name on pipe (work from win7)

RbMm
  • 31,280
  • 3
  • 35
  • 56