|
|
@ -3,17 +3,19 @@
|
|
|
|
package process
|
|
|
|
package process
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
|
|
|
|
"bufio"
|
|
|
|
"context"
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
|
|
|
|
cpu "github.com/shirou/gopsutil/v3/cpu"
|
|
|
|
"github.com/shirou/gopsutil/v3/cpu"
|
|
|
|
"github.com/shirou/gopsutil/v3/internal/common"
|
|
|
|
"github.com/shirou/gopsutil/v3/internal/common"
|
|
|
|
net "github.com/shirou/gopsutil/v3/net"
|
|
|
|
"github.com/shirou/gopsutil/v3/net"
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
@ -98,6 +100,55 @@ type processBasicInformation64 struct {
|
|
|
|
Reserved4 uint64
|
|
|
|
Reserved4 uint64
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type processEnvironmentBlock32 struct {
|
|
|
|
|
|
|
|
Reserved1 [2]uint8
|
|
|
|
|
|
|
|
BeingDebugged uint8
|
|
|
|
|
|
|
|
Reserved2 uint8
|
|
|
|
|
|
|
|
Reserved3 [2]uint32
|
|
|
|
|
|
|
|
Ldr uint32
|
|
|
|
|
|
|
|
ProcessParameters uint32
|
|
|
|
|
|
|
|
// More fields which we don't use so far
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type processEnvironmentBlock64 struct {
|
|
|
|
|
|
|
|
Reserved1 [2]uint8
|
|
|
|
|
|
|
|
BeingDebugged uint8
|
|
|
|
|
|
|
|
Reserved2 uint8
|
|
|
|
|
|
|
|
_ [4]uint8 // padding, since we are 64 bit, the next pointer is 64 bit aligned (when compiling for 32 bit, this is not the case without manual padding)
|
|
|
|
|
|
|
|
Reserved3 [2]uint64
|
|
|
|
|
|
|
|
Ldr uint64
|
|
|
|
|
|
|
|
ProcessParameters uint64
|
|
|
|
|
|
|
|
// More fields which we don't use so far
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type rtlUserProcessParameters32 struct {
|
|
|
|
|
|
|
|
Reserved1 [16]uint8
|
|
|
|
|
|
|
|
Reserved2 [10]uint32
|
|
|
|
|
|
|
|
ImagePathNameLength uint16
|
|
|
|
|
|
|
|
_ uint16
|
|
|
|
|
|
|
|
ImagePathAddress uint32
|
|
|
|
|
|
|
|
CommandLineLength uint16
|
|
|
|
|
|
|
|
_ uint16
|
|
|
|
|
|
|
|
CommandLineAddress uint32
|
|
|
|
|
|
|
|
EnvironmentAddress uint32
|
|
|
|
|
|
|
|
// More fields which we don't use so far
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type rtlUserProcessParameters64 struct {
|
|
|
|
|
|
|
|
Reserved1 [16]uint8
|
|
|
|
|
|
|
|
Reserved2 [10]uint64
|
|
|
|
|
|
|
|
ImagePathNameLength uint16
|
|
|
|
|
|
|
|
_ uint16 // Max Length
|
|
|
|
|
|
|
|
_ uint32 // Padding
|
|
|
|
|
|
|
|
ImagePathAddress uint64
|
|
|
|
|
|
|
|
CommandLineLength uint16
|
|
|
|
|
|
|
|
_ uint16 // Max Length
|
|
|
|
|
|
|
|
_ uint32 // Padding
|
|
|
|
|
|
|
|
CommandLineAddress uint64
|
|
|
|
|
|
|
|
EnvironmentAddress uint64
|
|
|
|
|
|
|
|
// More fields which we don't use so far
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type winLUID struct {
|
|
|
|
type winLUID struct {
|
|
|
|
LowPart winDWord
|
|
|
|
LowPart winDWord
|
|
|
|
HighPart winLong
|
|
|
|
HighPart winLong
|
|
|
@ -603,6 +654,14 @@ func (p *Process) KillWithContext(ctx context.Context) error {
|
|
|
|
return process.Kill()
|
|
|
|
return process.Kill()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
|
|
|
|
|
|
|
|
envVars, err := getProcessEnvironmentVariables(p.Pid, ctx)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("could not get environment variables: %s", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return envVars, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// retrieve Ppid in a thread-safe manner
|
|
|
|
// retrieve Ppid in a thread-safe manner
|
|
|
|
func (p *Process) getPpid() int32 {
|
|
|
|
func (p *Process) getPpid() int32 {
|
|
|
|
p.parentMutex.RLock()
|
|
|
|
p.parentMutex.RLock()
|
|
|
@ -729,39 +788,46 @@ func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
|
|
|
|
return times, err
|
|
|
|
return times, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func is32BitProcess(procHandle syscall.Handle) bool {
|
|
|
|
|
|
|
|
var wow64 uint
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret, _, _ := common.ProcNtQueryInformationProcess.Call(
|
|
|
|
func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) {
|
|
|
|
uintptr(procHandle),
|
|
|
|
pebAddress, err := queryPebAddress(syscall.Handle(handle), true)
|
|
|
|
uintptr(common.ProcessWow64Information),
|
|
|
|
if err != nil {
|
|
|
|
uintptr(unsafe.Pointer(&wow64)),
|
|
|
|
return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB: %w", err)
|
|
|
|
uintptr(unsafe.Sizeof(wow64)),
|
|
|
|
|
|
|
|
uintptr(0),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if int(ret) >= 0 {
|
|
|
|
|
|
|
|
if wow64 != 0 {
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
//if the OS does not support the call, we fallback into the bitness of the app
|
|
|
|
|
|
|
|
if unsafe.Sizeof(wow64) == 4 {
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func getProcessCommandLine(pid int32) (string, error) {
|
|
|
|
buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
|
|
|
|
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
|
|
|
|
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB")
|
|
|
|
return "", nil
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
|
|
|
|
|
|
|
|
userProcessAddress := uint64(peb.ProcessParameters)
|
|
|
|
|
|
|
|
buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
|
|
|
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
|
|
|
|
|
|
|
|
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) {
|
|
|
|
|
|
|
|
pebAddress, err := queryPebAddress(syscall.Handle(handle), false)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
defer syscall.CloseHandle(syscall.Handle(h))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
|
|
|
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
|
|
|
|
|
|
|
|
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
|
|
|
|
|
|
|
|
userProcessAddress := peb.ProcessParameters
|
|
|
|
|
|
|
|
buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
|
|
|
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
|
|
|
|
|
|
|
|
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func is32BitProcess(h windows.Handle) bool {
|
|
|
|
const (
|
|
|
|
const (
|
|
|
|
PROCESSOR_ARCHITECTURE_INTEL = 0
|
|
|
|
PROCESSOR_ARCHITECTURE_INTEL = 0
|
|
|
|
PROCESSOR_ARCHITECTURE_ARM = 5
|
|
|
|
PROCESSOR_ARCHITECTURE_ARM = 5
|
|
|
@ -770,86 +836,165 @@ func getProcessCommandLine(pid int32) (string, error) {
|
|
|
|
PROCESSOR_ARCHITECTURE_AMD64 = 9
|
|
|
|
PROCESSOR_ARCHITECTURE_AMD64 = 9
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
procIs32Bits := true
|
|
|
|
var procIs32Bits bool
|
|
|
|
switch processorArchitecture {
|
|
|
|
switch processorArchitecture {
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
fallthrough
|
|
|
|
fallthrough
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM:
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM:
|
|
|
|
procIs32Bits = true
|
|
|
|
procIs32Bits = true
|
|
|
|
|
|
|
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM64:
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM64:
|
|
|
|
fallthrough
|
|
|
|
fallthrough
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
|
fallthrough
|
|
|
|
fallthrough
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
procIs32Bits = is32BitProcess(syscall.Handle(h))
|
|
|
|
var wow64 uint
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret, _, _ := common.ProcNtQueryInformationProcess.Call(
|
|
|
|
|
|
|
|
uintptr(h),
|
|
|
|
|
|
|
|
uintptr(common.ProcessWow64Information),
|
|
|
|
|
|
|
|
uintptr(unsafe.Pointer(&wow64)),
|
|
|
|
|
|
|
|
uintptr(unsafe.Sizeof(wow64)),
|
|
|
|
|
|
|
|
uintptr(0),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if int(ret) >= 0 {
|
|
|
|
|
|
|
|
if wow64 != 0 {
|
|
|
|
|
|
|
|
procIs32Bits = true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
//if the OS does not support the call, we fallback into the bitness of the app
|
|
|
|
|
|
|
|
if unsafe.Sizeof(wow64) == 4 {
|
|
|
|
|
|
|
|
procIs32Bits = true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
//for other unknown platforms, we rely on process platform
|
|
|
|
//for other unknown platforms, we rely on process platform
|
|
|
|
if unsafe.Sizeof(processorArchitecture) == 8 {
|
|
|
|
if unsafe.Sizeof(processorArchitecture) == 8 {
|
|
|
|
procIs32Bits = false
|
|
|
|
procIs32Bits = false
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
procIs32Bits = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return procIs32Bits
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pebAddress := queryPebAddress(syscall.Handle(h), procIs32Bits)
|
|
|
|
func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, error) {
|
|
|
|
if pebAddress == 0 {
|
|
|
|
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
|
|
|
|
return "", errors.New("cannot locate process PEB")
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defer syscall.CloseHandle(syscall.Handle(h))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
procIs32Bits := is32BitProcess(h)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var processParameterBlockAddress uint64
|
|
|
|
|
|
|
|
|
|
|
|
if procIs32Bits {
|
|
|
|
if procIs32Bits {
|
|
|
|
buf := readProcessMemory(syscall.Handle(h), procIs32Bits, pebAddress+uint64(16), 4)
|
|
|
|
peb, err := getUserProcessParams32(h)
|
|
|
|
if len(buf) != 4 {
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.New("cannot locate process user parameters")
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24)
|
|
|
|
processParameterBlockAddress = uint64(peb.EnvironmentAddress)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
//read CommandLine field from PRTL_USER_PROCESS_PARAMETERS
|
|
|
|
peb, err := getUserProcessParams64(h)
|
|
|
|
remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams+uint64(64), 8)
|
|
|
|
if err != nil {
|
|
|
|
if len(remoteCmdLine) != 8 {
|
|
|
|
return nil, err
|
|
|
|
return "", errors.New("cannot read cmdline field")
|
|
|
|
}
|
|
|
|
|
|
|
|
processParameterBlockAddress = peb.EnvironmentAddress
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
envvarScanner := bufio.NewScanner(&processReader{
|
|
|
|
|
|
|
|
processHandle: h,
|
|
|
|
|
|
|
|
is32BitProcess: procIs32Bits,
|
|
|
|
|
|
|
|
offset: processParameterBlockAddress,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
envvarScanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error){
|
|
|
|
|
|
|
|
if atEOF && len(data) == 0 {
|
|
|
|
|
|
|
|
return 0, nil, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for UTF-16 zero character
|
|
|
|
|
|
|
|
for i := 0; i < len(data) - 1; i+=2 {
|
|
|
|
|
|
|
|
if data[i] == 0 && data[i+1] == 0 {
|
|
|
|
|
|
|
|
return i+2, data[0:i], nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if atEOF {
|
|
|
|
|
|
|
|
return len(data), data, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Request more data
|
|
|
|
|
|
|
|
return 0, nil, nil
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
var envVars []string
|
|
|
|
|
|
|
|
for envvarScanner.Scan() {
|
|
|
|
|
|
|
|
entry := envvarScanner.Bytes()
|
|
|
|
|
|
|
|
if len(entry) == 0 {
|
|
|
|
|
|
|
|
break // Block is finished
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
envVars = append(envVars, convertUTF16ToString(entry))
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := envvarScanner.Err(); err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return envVars, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type processReader struct {
|
|
|
|
|
|
|
|
processHandle windows.Handle
|
|
|
|
|
|
|
|
is32BitProcess bool
|
|
|
|
|
|
|
|
offset uint64
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *processReader) Read(buf []byte) (int, error) {
|
|
|
|
|
|
|
|
processMemory := readProcessMemory(syscall.Handle(p.processHandle), p.is32BitProcess, p.offset, uint(len(buf)))
|
|
|
|
|
|
|
|
if len(processMemory) == 0 {
|
|
|
|
|
|
|
|
return 0, io.EOF
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(buf, processMemory)
|
|
|
|
|
|
|
|
p.offset += uint64(len(processMemory))
|
|
|
|
|
|
|
|
return len(processMemory), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//remoteCmdLine is actually a UNICODE_STRING32
|
|
|
|
func getProcessCommandLine(pid int32) (string, error) {
|
|
|
|
//the first two bytes has the length
|
|
|
|
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
|
|
|
|
cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8)
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
if cmdLineLength > 0 {
|
|
|
|
return "", nil
|
|
|
|
//and, at offset 4, is the pointer to the buffer
|
|
|
|
}
|
|
|
|
bufferAddress := uint32(remoteCmdLine[4]) | (uint32(remoteCmdLine[5]) << 8) |
|
|
|
|
if err != nil {
|
|
|
|
(uint32(remoteCmdLine[6]) << 16) | (uint32(remoteCmdLine[7]) << 24)
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
defer syscall.CloseHandle(syscall.Handle(h))
|
|
|
|
|
|
|
|
|
|
|
|
cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(bufferAddress), cmdLineLength)
|
|
|
|
procIs32Bits := is32BitProcess(h)
|
|
|
|
if len(cmdLine) != int(cmdLineLength) {
|
|
|
|
|
|
|
|
|
|
|
|
if procIs32Bits {
|
|
|
|
|
|
|
|
userProcParams, err := getUserProcessParams32(h)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if userProcParams.CommandLineLength > 0 {
|
|
|
|
|
|
|
|
cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength))
|
|
|
|
|
|
|
|
if len(cmdLine) != int(userProcParams.CommandLineLength) {
|
|
|
|
return "", errors.New("cannot read cmdline")
|
|
|
|
return "", errors.New("cannot read cmdline")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return convertUTF16ToString(cmdLine), nil
|
|
|
|
return convertUTF16ToString(cmdLine), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
buf := readProcessMemory(syscall.Handle(h), procIs32Bits, pebAddress+uint64(32), 8)
|
|
|
|
userProcParams, err := getUserProcessParams64(h)
|
|
|
|
if len(buf) != 8 {
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.New("cannot locate process user parameters")
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24) |
|
|
|
|
|
|
|
|
(uint64(buf[4]) << 32) | (uint64(buf[5]) << 40) | (uint64(buf[6]) << 48) | (uint64(buf[7]) << 56)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//read CommandLine field from PRTL_USER_PROCESS_PARAMETERS
|
|
|
|
|
|
|
|
remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams+uint64(112), 16)
|
|
|
|
|
|
|
|
if len(remoteCmdLine) != 16 {
|
|
|
|
|
|
|
|
return "", errors.New("cannot read cmdline field")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if userProcParams.CommandLineLength > 0 {
|
|
|
|
//remoteCmdLine is actually a UNICODE_STRING64
|
|
|
|
cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))
|
|
|
|
//the first two bytes has the length
|
|
|
|
if len(cmdLine) != int(userProcParams.CommandLineLength) {
|
|
|
|
cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8)
|
|
|
|
|
|
|
|
if cmdLineLength > 0 {
|
|
|
|
|
|
|
|
//and, at offset 8, is the pointer to the buffer
|
|
|
|
|
|
|
|
bufferAddress := uint64(remoteCmdLine[8]) | (uint64(remoteCmdLine[9]) << 8) |
|
|
|
|
|
|
|
|
(uint64(remoteCmdLine[10]) << 16) | (uint64(remoteCmdLine[11]) << 24) |
|
|
|
|
|
|
|
|
(uint64(remoteCmdLine[12]) << 32) | (uint64(remoteCmdLine[13]) << 40) |
|
|
|
|
|
|
|
|
(uint64(remoteCmdLine[14]) << 48) | (uint64(remoteCmdLine[15]) << 56)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, bufferAddress, cmdLineLength)
|
|
|
|
|
|
|
|
if len(cmdLine) != int(cmdLineLength) {
|
|
|
|
|
|
|
|
return "", errors.New("cannot read cmdline")
|
|
|
|
return "", errors.New("cannot read cmdline")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|