pull/1434/merge
Sharon 3 months ago committed by GitHub
commit e8ba11d2d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -12,6 +12,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"runtime"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@ -90,7 +91,7 @@ type ioCounters struct {
type processBasicInformation32 struct { type processBasicInformation32 struct {
Reserved1 uint32 Reserved1 uint32
PebBaseAddress uint32 PebBaseAddress uintptr
Reserved2 uint32 Reserved2 uint32
Reserved3 uint32 Reserved3 uint32
UniqueProcessId uint32 UniqueProcessId uint32
@ -99,7 +100,7 @@ type processBasicInformation32 struct {
type processBasicInformation64 struct { type processBasicInformation64 struct {
Reserved1 uint64 Reserved1 uint64
PebBaseAddress uint64 PebBaseAddress uintptr
Reserved2 uint64 Reserved2 uint64
Reserved3 uint64 Reserved3 uint64
UniqueProcessId uint64 UniqueProcessId uint64
@ -112,7 +113,7 @@ type processEnvironmentBlock32 struct {
Reserved2 uint8 Reserved2 uint8
Reserved3 [2]uint32 Reserved3 [2]uint32
Ldr uint32 Ldr uint32
ProcessParameters uint32 ProcessParameters uintptr
// More fields which we don't use so far // More fields which we don't use so far
} }
@ -123,7 +124,7 @@ type processEnvironmentBlock64 struct {
_ [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) _ [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 Reserved3 [2]uint64
Ldr uint64 Ldr uint64
ProcessParameters uint64 ProcessParameters uintptr
// More fields which we don't use so far // More fields which we don't use so far
} }
@ -136,18 +137,18 @@ type rtlUserProcessParameters32 struct {
StdErrorHandle uint32 StdErrorHandle uint32
CurrentDirectoryPathNameLength uint16 CurrentDirectoryPathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
CurrentDirectoryPathAddress uint32 CurrentDirectoryPathAddress uintptr
CurrentDirectoryHandle uint32 CurrentDirectoryHandle uint32
DllPathNameLength uint16 DllPathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
DllPathAddress uint32 DllPathAddress uintptr
ImagePathNameLength uint16 ImagePathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
ImagePathAddress uint32 ImagePathAddress uintptr
CommandLineLength uint16 CommandLineLength uint16
_ uint16 // Max Length _ uint16 // Max Length
CommandLineAddress uint32 CommandLineAddress uintptr
EnvironmentAddress uint32 EnvironmentAddress uintptr
// More fields which we don't use so far // More fields which we don't use so far
} }
@ -161,21 +162,21 @@ type rtlUserProcessParameters64 struct {
CurrentDirectoryPathNameLength uint16 CurrentDirectoryPathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
CurrentDirectoryPathAddress uint64 CurrentDirectoryPathAddress uintptr
CurrentDirectoryHandle uint64 CurrentDirectoryHandle uint64
DllPathNameLength uint16 DllPathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
DllPathAddress uint64 DllPathAddress uintptr
ImagePathNameLength uint16 ImagePathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
ImagePathAddress uint64 ImagePathAddress uintptr
CommandLineLength uint16 CommandLineLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
CommandLineAddress uint64 CommandLineAddress uintptr
EnvironmentAddress uint64 EnvironmentAddress uintptr
// More fields which we don't use so far // More fields which we don't use so far
} }
@ -404,13 +405,13 @@ func (p *Process) CwdWithContext(_ context.Context) (string, error) {
procIs32Bits := is32BitProcess(h) procIs32Bits := is32BitProcess(h)
if procIs32Bits { if procIs32Bits && !strings.Contains(runtime.GOARCH, "64") {
userProcParams, err := getUserProcessParams32(h) userProcParams, err := getUserProcessParams32(h)
if err != nil { if err != nil {
return "", err return "", err
} }
if userProcParams.CurrentDirectoryPathNameLength > 0 { if userProcParams.CurrentDirectoryPathNameLength > 0 {
cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength)) cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))
if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) { if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
return "", errors.New("cannot read current working directory") return "", errors.New("cannot read current working directory")
} }
@ -956,39 +957,39 @@ func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
} }
func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) { func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) {
pebAddress, err := queryPebAddress(syscall.Handle(handle), true) pebAddress, err, queryFrom64Bit := queryPebAddress(syscall.Handle(handle), true)
if err != nil { if err != nil {
return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB: %w", err) return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB for 64-bit-initiator: %t, 32-bit-proc: %t : %w", queryFrom64Bit, true, err)
} }
buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{}))) buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) { if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB") return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB for 64-bit-initiator: %t, 32-bit-proc: %t", queryFrom64Bit, true)
} }
peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0])) peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
userProcessAddress := uint64(peb.ProcessParameters) userProcessAddress := peb.ProcessParameters
buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{}))) buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) { if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters") return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters for 64-bit-initiator: %t, 32-bit-proc: %t", queryFrom64Bit, true)
} }
return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
} }
func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) { func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) {
pebAddress, err := queryPebAddress(syscall.Handle(handle), false) pebAddress, err, queryFrom64Bit := queryPebAddress(syscall.Handle(handle), false)
if err != nil { if err != nil {
return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB: %w", err) return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB for 64-bit-initiator: %t, 32-bit-proc: %t : %w", queryFrom64Bit, false, err)
} }
buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{}))) buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) { if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB") return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB for 64-bit-initiator: %t, 32-bit-proc: %t", queryFrom64Bit, false)
} }
peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0])) peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
userProcessAddress := peb.ProcessParameters userProcessAddress := peb.ProcessParameters
buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{}))) buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) { if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters") return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters for 64-bit-initiator: %t, 32-bit-proc: %t", queryFrom64Bit, false)
} }
return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
} }
@ -1050,14 +1051,14 @@ func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, e
procIs32Bits := is32BitProcess(h) procIs32Bits := is32BitProcess(h)
var processParameterBlockAddress uint64 var processParameterBlockAddress uintptr
if procIs32Bits { if procIs32Bits && !strings.Contains(runtime.GOARCH, "64") {
peb, err := getUserProcessParams32(h) peb, err := getUserProcessParams32(h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
processParameterBlockAddress = uint64(peb.EnvironmentAddress) processParameterBlockAddress = peb.EnvironmentAddress
} else { } else {
peb, err := getUserProcessParams64(h) peb, err := getUserProcessParams64(h)
if err != nil { if err != nil {
@ -1065,6 +1066,7 @@ func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, e
} }
processParameterBlockAddress = peb.EnvironmentAddress processParameterBlockAddress = peb.EnvironmentAddress
} }
envvarScanner := bufio.NewScanner(&processReader{ envvarScanner := bufio.NewScanner(&processReader{
processHandle: h, processHandle: h,
is32BitProcess: procIs32Bits, is32BitProcess: procIs32Bits,
@ -1109,7 +1111,7 @@ func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, e
type processReader struct { type processReader struct {
processHandle windows.Handle processHandle windows.Handle
is32BitProcess bool is32BitProcess bool
offset uint64 offset uintptr
} }
func (p *processReader) Read(buf []byte) (int, error) { func (p *processReader) Read(buf []byte) (int, error) {
@ -1118,7 +1120,7 @@ func (p *processReader) Read(buf []byte) (int, error) {
return 0, io.EOF return 0, io.EOF
} }
copy(buf, processMemory) copy(buf, processMemory)
p.offset += uint64(len(processMemory)) p.offset += uintptr(len(processMemory))
return len(processMemory), nil return len(processMemory), nil
} }
@ -1134,15 +1136,15 @@ func getProcessCommandLine(pid int32) (string, error) {
procIs32Bits := is32BitProcess(h) procIs32Bits := is32BitProcess(h)
if procIs32Bits { if procIs32Bits && !strings.Contains(runtime.GOARCH, "64") {
userProcParams, err := getUserProcessParams32(h) userProcParams, err := getUserProcessParams32(h)
if err != nil { if err != nil {
return "", err return "", err
} }
if userProcParams.CommandLineLength > 0 { if userProcParams.CommandLineLength > 0 {
cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength)) cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))
if len(cmdLine) != int(userProcParams.CommandLineLength) { if len(cmdLine) != int(userProcParams.CommandLineLength) {
return "", errors.New("cannot read cmdline") return "", fmt.Errorf("cannot read cmdline for 32-bit-proc: %t, len: %d and %d", procIs32Bits, len(cmdLine), int(userProcParams.CommandLineLength))
} }
return convertUTF16ToString(cmdLine), nil return convertUTF16ToString(cmdLine), nil
@ -1155,7 +1157,7 @@ func getProcessCommandLine(pid int32) (string, error) {
if userProcParams.CommandLineLength > 0 { if userProcParams.CommandLineLength > 0 {
cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength)) cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))
if len(cmdLine) != int(userProcParams.CommandLineLength) { if len(cmdLine) != int(userProcParams.CommandLineLength) {
return "", errors.New("cannot read cmdline") return "", fmt.Errorf("cannot read cmdline for 32-bit-proc: %t, len: %d and %d", procIs32Bits, len(cmdLine), int(userProcParams.CommandLineLength))
} }
return convertUTF16ToString(cmdLine), nil return convertUTF16ToString(cmdLine), nil

@ -25,7 +25,8 @@ type PROCESS_MEMORY_COUNTERS struct {
PeakPagefileUsage uint32 PeakPagefileUsage uint32
} }
func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) { func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uintptr, error, bool) {
var queryFrom64Bit bool
if is32BitProcess { if is32BitProcess {
// we are on a 32-bit process reading an external 32-bit process // we are on a 32-bit process reading an external 32-bit process
var info processBasicInformation32 var info processBasicInformation32
@ -38,9 +39,9 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, er
uintptr(0), uintptr(0),
) )
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS { if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return uint64(info.PebBaseAddress), nil return info.PebBaseAddress, nil, queryFrom64Bit
} else { } else {
return 0, windows.NTStatus(ret) return 0, windows.NTStatus(ret), queryFrom64Bit
} }
} else { } else {
// we are on a 32-bit process reading an external 64-bit process // we are on a 32-bit process reading an external 64-bit process
@ -55,17 +56,17 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, er
uintptr(0), uintptr(0),
) )
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS { if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return info.PebBaseAddress, nil return info.PebBaseAddress, nil, queryFrom64Bit
} else { } else {
return 0, windows.NTStatus(ret) return 0, windows.NTStatus(ret), queryFrom64Bit
} }
} else { } else {
return 0, errors.New("can't find API to query 64 bit process from 32 bit") return 0, errors.New("can't find API to query 64 bit process from 32 bit"), queryFrom64Bit
} }
} }
} }
func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte { func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uintptr, size uint) []byte {
if is32BitProcess { if is32BitProcess {
var read uint var read uint

@ -24,25 +24,10 @@ type PROCESS_MEMORY_COUNTERS struct {
PeakPagefileUsage uint64 PeakPagefileUsage uint64
} }
func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) { func queryPebAddress(procHandle syscall.Handle, _ bool) (uintptr, error, bool) {
if is32BitProcess { var queryFrom64Bit bool = true
// we are on a 64-bit process reading an external 32-bit process
var wow64 uint
ret, _, _ := common.ProcNtQueryInformationProcess.Call( // we are in a 64-bit process
uintptr(procHandle),
uintptr(common.ProcessWow64Information),
uintptr(unsafe.Pointer(&wow64)),
uintptr(unsafe.Sizeof(wow64)),
uintptr(0),
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return uint64(wow64), nil
} else {
return 0, windows.NTStatus(ret)
}
} else {
// we are on a 64-bit process reading an external 64-bit process
var info processBasicInformation64 var info processBasicInformation64
ret, _, _ := common.ProcNtQueryInformationProcess.Call( ret, _, _ := common.ProcNtQueryInformationProcess.Call(
@ -53,14 +38,13 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, er
uintptr(0), uintptr(0),
) )
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS { if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return info.PebBaseAddress, nil return info.PebBaseAddress, nil, queryFrom64Bit
} else { } else {
return 0, windows.NTStatus(ret) return 0, windows.NTStatus(ret), queryFrom64Bit
}
} }
} }
func readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte { func readProcessMemory(procHandle syscall.Handle, _ bool, address uintptr, size uint) []byte {
var read uint var read uint
buffer := make([]byte, size) buffer := make([]byte, size)

Loading…
Cancel
Save