Skip to content

Instantly share code, notes, and snippets.

@chitoku-k
Created November 15, 2023 07:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chitoku-k/ec0843f9badbfef1fece175bfa57c8dc to your computer and use it in GitHub Desktop.
Save chitoku-k/ec0843f9badbfef1fece175bfa57c8dc to your computer and use it in GitHub Desktop.
Invoke Win32_Process::Create using github.com/go-ole/go-ole
package main
import (
"fmt"
"runtime"
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
"golang.org/x/sys/windows"
)
func main() {
processID, err := createProcess("cmd.exe", windows.SW_HIDE)
if err != nil {
panic(err)
}
fmt.Printf("Process ID: %d\n", processID)
}
// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/creating-a-wmi-script
func createProcess(commandLine string, showWindow uint16) (*int32, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
err := ole.CoInitializeEx(uintptr(0), ole.COINIT_MULTITHREADED)
if err != nil {
oleerr := err.(*ole.OleError)
if oleerr.Code() != uintptr(windows.S_FALSE) {
return nil, fmt.Errorf("failed to initialize COM: %w", err)
}
}
defer ole.CoUninitialize()
// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemlocator
unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
if err != nil {
return nil, fmt.Errorf("failed to create WbemScripting.SWbemLocator (%#x): %w", err.(*ole.OleError).Code(), err)
}
defer unknown.Release()
wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
if err != nil {
return nil, fmt.Errorf("failed to query interface (%#x): %w", err.(*ole.OleError).Code(), err)
}
defer wmi.Release()
// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemlocator-connectserver
swbemservicesVariant, err := oleutil.CallMethod(wmi, "ConnectServer", ".", `Root\CIMV2`)
if err != nil {
return nil, fmt.Errorf("failed to connect to server (%#x): %w", err.(*ole.OleError).Code(), err)
}
defer swbemservicesVariant.Clear()
// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemservices
swbemservices := swbemservicesVariant.ToIDispatch()
defer swbemservices.Release()
// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemservices-get
processVariant, err := swbemservices.CallMethod("Get", "Win32_Process")
if err != nil {
return nil, fmt.Errorf("failed to get Win32_Process (%#x): %w", err.(*ole.OleError).Code(), err)
}
defer processVariant.Clear()
// See: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-process
process := processVariant.ToIDispatch()
defer process.Release()
// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/swbemservices-get
processStartupVariant, err := swbemservices.CallMethod("Get", "Win32_ProcessStartup")
if err != nil {
return nil, fmt.Errorf("failed to get Win32_ProcessStartup (%#x): %w", err.(*ole.OleError).Code(), err)
}
// See: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processstartup
processStartup := processStartupVariant.ToIDispatch()
// See: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
showwindowVariant, err := processStartup.PutProperty("ShowWindow", showWindow)
if err != nil {
return nil, fmt.Errorf("failed to put Win32_ProcessStartup::ShowWindow (%#v): %w", err.(*ole.OleError).Code(), err)
}
defer showwindowVariant.Clear()
// See: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process
var processID int32
ret, err := process.CallMethod("Create", commandLine, nil, processStartupVariant, &processID)
if err != nil {
return nil, fmt.Errorf("failed to create a process (%#x): %w", err.(*ole.OleError).Code(), err)
}
defer ret.Clear()
retval := ret.Value().(int32)
if retval != 0 {
return nil, fmt.Errorf("failed to create a process (%d)", retval)
}
return &processID, nil
}
@chitoku-k
Copy link
Author

If the subsystem of the process is console that does not need console, this can be as simple as:

import (
	"os/exec"
	"syscall"

	"golang.org/x/sys/windows"
)

func main() {
	cmd := exec.Command("foobar.exe")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		CreationFlags: windows.CREATE_NEW_PROCESS_GROUP | windows.CREATE_NO_WINDOW,
	}
	err := cmd.Start()
	if err != nil {
		panic(err)
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment