Search code examples
windowsgoprocesshandlesuspend

How do I get a handle uintptr of a child process?


I want to start a child process (i'm on windows 10) and I would like to be able to suspend and resume the process at will.

I found this neat undocumented windows function NtSuspendProcess from ntdll.dll that should do the job but now I need to get the handle of the process to issue the suspend command.

this is an example:

modntdll = syscall.NewLazyDLL("ntdll.dll")
procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
procNtResumeProcess  = modntdll.NewProc("NtResumeProcess")
_, _, err = procNtSuspendProcess.Call(uintptr(handle))
_, _, err = procNtResumeProcess.Call(uintptr(handle))

To start the process I would normally use the exec.Command function but I can't find a way to retrieve the handle of the process.

Is there a way to get the handle when starting a process?
If not with exec.Command, what other library should I use to start a process that returns also the process handle?

As a side note:
I've looked into syscall.StartProcess but it's quite low level and I don't feel able to handle such a raw implementation.

_, handle, err := syscall.StartProcess("C:\\WINDOWS\\system32\\cmd.exe", []string{}, procAttr)

Solution

  • Go does not publicly expose the handle in exec.Command, you will have to access it either by.

    Reflection

    cmd := exec.Command("cmd.exe")
    cmd.Start()
    handle := uintptr(reflect.ValueOf(cmd.Process).Elem().FieldByName("handle").Uint())
    

    or by creating an identical Process type and casting the Cmd.Process to your own type to access the private fields.

    type Process struct {
       Pid int
       handle uintptr
       isdone uint32
       sigMu sync.RWMutex
    }
    
    cmd := exec.Command("cmd.exe")
    cmd.Start()
    proc := (*Process)(unsafe.Pointer(cmd.Process))
    println(proc.handle)