Windows API Error "The handle is invalid" - go

I'm trying to create a program that utilises the MiniDumpWriteDump Windows API to dump another process's memory. However, it keeps returning an error saying The handle is invalid. I'm pretty confident in my process handle because I've used the OpenProcess Windows API before, so I think it's how I'm using CreateFileW.
I have looked at examples online like this one but I can't get anything working.
Here is my code so far:
package main
import (
"fmt"
"os"
"strconv"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var procOpenProcess = kernel32.NewProc("OpenProcess")
var procCreateFileW = kernel32.NewProc("CreateFileW")
var procCloseHandle = kernel32.NewProc("CloseHandle")
var dbghelp = syscall.NewLazyDLL("Dbghelp.dll")
var procMiniDumpWriteDump = dbghelp.NewProc("MiniDumpWriteDump")
func main() {
fmt.Println("[ ] Starting Enum-DumpProcessMemory\n")
pid, _ := strconv.Atoi(os.Args[1])
fmt.Println("[-] PID :", pid)
processHandle, _, _ := procOpenProcess.Call(uintptr(0xFFFF), uintptr(1), uintptr(pid))
fmt.Println("[-] Process Handle :", processHandle)
path, _ := syscall.UTF16PtrFromString(os.Args[2])
fileHandle, _, _ := procCreateFileW.Call(uintptr(unsafe.Pointer(path)), syscall.GENERIC_READ, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, 0, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
fmt.Println("[-] File Handle :", fileHandle)
ret, _, err := procMiniDumpWriteDump.Call(uintptr(processHandle), uintptr(pid), uintptr(fileHandle), 0x00061907, 0, 0, 0)
if ret != 0 {
fmt.Println("[+] Process memory dump successful")
} else {
fmt.Println("[x] Process memory dump not successful")
fmt.Println(err)
}
}
Here is the output:
> .\Enum-DumpProcessMemory.exe 6892 C:\Users\user\Documents\dump.dmp
[ ] Starting Enum-DumpProcessMemory
[-] PID : 6892
[-] Process Handle : 236
[-] File Handle : 18446744073709551615
[x] Process memory dump not successful
The handle is invalid.

I got the code working thanks to the help from Jonathan Potter. The problem was that I was trying to create a handler to a file that didn't exist.
Here is my working code:
package main
import (
"fmt"
"os"
"strconv"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var procOpenProcess = kernel32.NewProc("OpenProcess")
var procCreateFileW = kernel32.NewProc("CreateFileW")
var dbghelp = syscall.NewLazyDLL("Dbghelp.dll")
var procMiniDumpWriteDump = dbghelp.NewProc("MiniDumpWriteDump")
func main() {
fmt.Println("[ ] Starting Enum-DumpProcessMemory\n")
pid, _ := strconv.Atoi(os.Args[1])
fmt.Println("[-] PID :", pid)
processHandle, _, _ := procOpenProcess.Call(uintptr(0xFFFF), uintptr(1), uintptr(pid))
fmt.Println("[-] Process Handle :", processHandle)
if _, err := os.Stat(os.Args[2]); os.IsNotExist(err) {
os.Create(os.Args[2])
}
path, _ := syscall.UTF16PtrFromString(os.Args[2])
fileHandle, _, _ := procCreateFileW.Call(uintptr(unsafe.Pointer(path)), syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, 0, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
fmt.Println("[-] File Handle :", fileHandle)
ret, _, err := procMiniDumpWriteDump.Call(uintptr(processHandle), uintptr(pid), uintptr(fileHandle), 0x00061907, 0, 0, 0)
if ret != 0 {
fmt.Println("[+] Process memory dump successful")
} else {
fmt.Println("[x] Process memory dump not successful")
fmt.Println(err)
}
}

Related

Go: Why do processes/Threads started using Win32API funcs seem to hijack and kill the parent proccess?

Now, the following code does what it's supposed to do, load calc.exe to memory and execute it, it does that fine.
I've stitched together this code to show CreateThread() Killing my program's execution flow right before popping calc.exe, Simply after CreateThread.Call(), No other instructions are executed after it
And i believe this isn't a memory allocation issue, because if i wrap CreateThread() in a goroutine (go runThread() ) It executes a few loop cycles before popping calc.exe
package main
import (
"fmt"
"encoding/hex"
"golang.org/x/sys/windows"
"log"
"unsafe"
)
func main(){
RunCreateThread()
for {
fmt.Println("Running infinitely")
}
}
func RunCreateThread() {
//calc.exe HEX
shellcode, _ :=hex.DecodeString("fc4883e4f0e8c0000000415141505251564831d265488b5260488b5218488b5220488b7250480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d4101c1e2ed524151488b52208b423c4801d08b80880000004885c074674801d0508b4818448b40204901d0e35648ffc9418b34884801d64d31c94831c0ac41c1c90d4101c138e075f14c034c24084539d175d858448b40244901d066418b0c48448b401c4901d0418b04884801d0415841585e595a41584159415a4883ec204152ffe05841595a488b12e957ffffff5d48ba0100000000000000488d8d0101000041ba318b6f87ffd5bbf0b5a25641baa695bd9dffd54883c4283c067c0a80fbe07505bb4713726f6a00594189daffd563616c632e65786500")
addr, errVirtualAlloc := windows.VirtualAlloc(uintptr(0), uintptr(len(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
if errVirtualAlloc != nil {11
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
ntdll := windows.NewLazySystemDLL("ntdll.dll")
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
_, _, errRtlCopyMemory := RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errRtlCopyMemory != nil && errRtlCopyMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling RtlCopyMemory:\r\n%s", errRtlCopyMemory.Error()))
}
var oldProtect uint32
errVirtualProtect := windows.VirtualProtect(addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, &oldProtect)
if errVirtualProtect != nil {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualProtect:\r\n%s", errVirtualProtect.Error()))
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
CreateThread := kernel32.NewProc("CreateThread")
thread, _, errCreateThread := CreateThread.Call(0, 0, addr, uintptr(0), 0, 0)
if errCreateThread != nil && errCreateThread.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CreateThread:\r\n%s", errCreateThread.Error()))
}
_, _ = windows.WaitForSingleObject(windows.Handle(thread), 0xFFFFFFFF)
}
I'm curious to why this happens?
As it turns out, it was indeed a shellcode issue, The code calls Fine, I didn't know that msfvenom payloads often mess with their host callers in weird ways sometimes.

ptracing long-running process hangs

I'm using Go's syscall package Ptrace interface to trace a process. The problem is, if the tracee is long-running, the tracing seems to hang. I tried replicating the issue with C implementation, but there everything seems to work fine.
Here's a Go code to reproduce the issue:
import (
"fmt"
"os"
"os/exec"
"syscall"
)
func main() {
len := "9999999"
cmd := exec.Command("openssl", "rand", "-hex", len)
cmd.SysProcAttr = &syscall.SysProcAttr{Ptrace: true}
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
cmd.Start()
pid, _ := syscall.Wait4(-1, nil, syscall.WALL, nil)
for {
syscall.PtraceSyscall(pid, 0)
_, err := syscall.Wait4(-1, nil, syscall.WALL, nil)
if err != nil {
fmt.Println(err)
break
}
}
}
When running the above code, the process never completes and it has to be interrupted. If the len variable is changed to something smaller, for example 9, the process will complete without issues and output will be something following:
$ go run main.go
d2ff963e65e8e1926b
no child processes
Found it. The program hangs when Go runtime changes the thread in which the goroutine is running. Can be verified in the example code by printing fmt.Println(syscall.Gettid()) inside the loop:
package main
import (
"fmt"
"os/exec"
"syscall"
)
func main() {
len := "9999999"
cmd := exec.Command("openssl", "rand", "-hex", len)
cmd.SysProcAttr = &syscall.SysProcAttr{Ptrace: true}
cmd.Start()
pid, _ := syscall.Wait4(-1, nil, syscall.WALL, nil)
for {
fmt.Println(syscall.Gettid())
syscall.PtraceSyscall(pid, 0)
_, err := syscall.Wait4(-1, nil, syscall.WALL, nil)
if err != nil {
fmt.Println(err)
break
}
}
}
Solution: lock the execution of the goroutine to its current thread by using runtime.LockOSThread():
....
func main() {
runtime.LockOSThread()
len := "9999999"
cmd := exec.Command("openssl", "rand", "-hex", len)
....

Weird channel behavior in go

package main
import (
"encoding/json"
"fmt"
"/something/models"
"os"
"path/filepath"
"runtime"
)
func WriteDeviceToFile(d chan *models.Device, fileName string) {
_, b, _, _ := runtime.Caller(0)
basepath := filepath.Dir(b)
filePath := basepath + "/dataFile/" + fileName
var f *os.File
var err error
f, _ = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0600)
defer f.Close()
for device := range d {
deviceB, err := json.Marshal(device)
fmt.Println(string(deviceB))
if err == nil {
if _, err = f.WriteString(string(deviceB)); err != nil {
panic(err)
}
} else {
panic(err)
}
}
}
func main() {
deviceChan := make(chan *models.Device)
go WriteDeviceToFile(deviceChan, "notalive.txt")
d := models.NewDevice("12346", "")
deviceChan <- d
d = models.NewDevice("abcd", "")
deviceChan <- d
close(deviceChan)
}
This only works with at least two devices sent to channel. With only one device in deviceChan, the function does not receive anything. Is the channel gone before the WriteDeviceToFile gets to it?
The program exits when main returns. Nothing prevents main from exiting before the files are written

Shutting down windows using golang code

I am making a program that automates some tedious tasks for me, after the program is done I want to shutdown windows. I know this can be done in for example C#
How can I shutdown window using golang?
There is no "Shutdown OS" function in the syscall package, because there is no common interface provided for that by all operating systems.
Note: there is a syscall.Shutdown() function, but that is to shutdown a socket, and not to shutdown the operating system.
The easiest would be to just execute the shutdown command using the os/exec package, e.g.
if err := exec.Command("cmd", "/C", "shutdown", "/s").Run(); err != nil {
fmt.Println("Failed to initiate shutdown:", err)
}
The above command initiates a shutdown sequence which usually takes 1 minute to really shut down the system (and there's room to abort it with shutdown /a). You may provide different arguments to the shutdown command to not wait 1 minute but proceed immediately: shutdown /t 0 /s (execute shutdown /? to get a list of all options).
There is also a Windows API call to shutdown the system: ExitWindowsEx(). It has 2 parameters, first is the flags to define the shutdown type (0x08 means Shuts down the system and turns off the power.), second is to provide a reason for the shutdown. To call this from Go, you can do that like this:
user32 := syscall.MustLoadDLL("user32")
defer user32.Release()
exitwin := user32.MustFindProc("ExitWindowsEx")
r1, _, err := exitwin.Call(0x08, 0)
if r1 != 1 {
fmt.Println("Failed to initiate shutdown:", err)
}
But know that you need SE_SHUTDOWN_NAME privilege to call ExitWindowsEx(), else you get an error message like:
Failed to initiate shutdown: A required privilege is not held by the client.
See this example how to acquire the required privilege.
Thanks for the post, very helpful.
here is a complete function that performs a reboot. It follows exactly the Microsoft example as noted before. should help saving time in figuring out the structs:
import (
"fmt"
"syscall"
"unsafe"
)
// error is nil on success
func reboot() error {
user32 := syscall.MustLoadDLL("user32")
defer user32.Release()
kernel32 := syscall.MustLoadDLL("kernel32")
defer user32.Release()
advapi32 := syscall.MustLoadDLL("advapi32")
defer advapi32.Release()
ExitWindowsEx := user32.MustFindProc("ExitWindowsEx")
GetCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
GetLastError := kernel32.MustFindProc("GetLastError")
OpenProdcessToken := advapi32.MustFindProc("OpenProcessToken")
LookupPrivilegeValue := advapi32.MustFindProc("LookupPrivilegeValueW")
AdjustTokenPrivileges := advapi32.MustFindProc("AdjustTokenPrivileges")
currentProcess, _, _ := GetCurrentProcess.Call()
const tokenAdjustPrivileges = 0x0020
const tokenQuery = 0x0008
var hToken uintptr
result, _, err := OpenProdcessToken.Call(currentProcess, tokenAdjustPrivileges|tokenQuery, uintptr(unsafe.Pointer(&hToken)))
if result != 1 {
fmt.Println("OpenProcessToken(): ", result, " err: ", err)
return err
}
//fmt.Println("hToken: ", hToken)
const SeShutdownName = "SeShutdownPrivilege"
type Luid struct {
lowPart uint32 // DWORD
highPart int32 // long
}
type LuidAndAttributes struct {
luid Luid // LUID
attributes uint32 // DWORD
}
type TokenPrivileges struct {
privilegeCount uint32 // DWORD
privileges [1]LuidAndAttributes
}
var tkp TokenPrivileges
result, _, err = LookupPrivilegeValue.Call(uintptr(0), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(SeShutdownName))), uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))))
if result != 1 {
fmt.Println("LookupPrivilegeValue(): ", result, " err: ", err)
return err
}
//fmt.Println("LookupPrivilegeValue luid: ", tkp.privileges[0].luid)
const SePrivilegeEnabled uint32 = 0x00000002
tkp.privilegeCount = 1
tkp.privileges[0].attributes = SePrivilegeEnabled
result, _, err = AdjustTokenPrivileges.Call(hToken, 0, uintptr(unsafe.Pointer(&tkp)), 0, uintptr(0), 0)
if result != 1 {
fmt.Println("AdjustTokenPrivileges() ", result, " err: ", err)
return err
}
result, _, _ = GetLastError.Call()
if result != 0 {
fmt.Println("GetLastError() ", result)
return err
}
const ewxForceIfHung = 0x00000010
const ewxReboot = 0x00000002
const shutdownReasonMajorSoftware = 0x00030000
result, _, err = ExitWindowsEx.Call(ewxReboot|ewxForceIfHung, shutdownReasonMajorSoftware)
if result != 1 {
fmt.Println("Failed to initiate reboot:", err)
return err
}
return nil
}

How can I read from `exec.Cmd` ExtraFiles fd in child process?

I read the explanation from golang.org, it says like below.
// ExtraFiles specifies additional open files to be inherited by the
// new process. It does not include standard input, standard output, or
// standard error. If non-nil, entry i becomes file descriptor 3+i.
//
// BUG: on OS X 10.6, child processes may sometimes inherit unwanted fds.
// http://golang.org/issue/2603
ExtraFiles []*os.File
I'm not very understand about it ? For example I have such code below.
cmd := &exec.Cmd{
Path: init,
Args: initArgs,
}
cmd.Stdin = Stdin
cmd.Stdout = Stdout
cmd.Stderr = Stderr
cmd.Dir = Rootfs
cmd.ExtraFiles = []*os.File{childPipe}
Is that mean, since I have written a childpipe in cmd.ExtraFiles = []*os.File{childPipe}, I can use it by writing fd 3 directly.
pipe = os.NewFile(uintptr(3), "pipe")
json.NewEncoder(pipe).Encode(newThing)
Thanks if anyone can give some help!
Correct; you can read from the pipe by creating a new *File whose file descriptor is that of the child pipe. Below is a example of piping data from the child process to the parent:
Parent:
package main
import (
"fmt"
"os/exec"
"os"
"encoding/json"
)
func main() {
init := "child"
initArgs := []string{"hello world"}
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
cmd := exec.Command(init, initArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.ExtraFiles = []*os.File{w}
if err := cmd.Start(); err != nil {
panic(err)
}
var data interface{}
decoder := json.NewDecoder(r)
if err := decoder.Decode(&data); err != nil {
panic(err)
}
fmt.Printf("Data received from child pipe: %v\n", data)
}
Child:
package main
import (
"os"
"encoding/json"
"strings"
"fmt"
)
func main() {
if len(os.Args) < 2 {
os.Exit(1)
}
arg := strings.ToUpper(os.Args[1])
pipe := os.NewFile(uintptr(3), "pipe")
err := json.NewEncoder(pipe).Encode(arg)
if err != nil {
panic(err)
}
fmt.Println("This message printed to standard output, not to the pipe")
}

Resources