Skip to content

Commit

Permalink
Add APIs to fetch processes information
Browse files Browse the repository at this point in the history
- ntdll.NtQueryInformationProcess (internal/unsupported API!)
  PROCESS_BASIC_INFORMATION struct
  UNICODE_STRING struct
  RTL_USER_PROCESS_PARAMETERS struct
- kernel32.ReadProcessMemory
- psapi.GetProcessImageFileNameA
  • Loading branch information
adriansr committed Aug 2, 2018
1 parent f11b8c9 commit 5f20f19
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 10 deletions.
2 changes: 1 addition & 1 deletion doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ package windows

// Use "GOOS=windows go generate -v -x" to generate the sources.
// Add -trace to enable debug prints around syscalls.
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zsyscall_windows.go kernel32.go version.go psapi.go
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zsyscall_windows.go kernel32.go version.go psapi.go ntdll.go
19 changes: 19 additions & 0 deletions kernel32.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
//sys _GetTickCount64() (millis uint64, err error) = kernel32.GetTickCount64
//sys _GetSystemTimes(idleTime *syscall.Filetime, kernelTime *syscall.Filetime, userTime *syscall.Filetime) (err error) = kernel32.GetSystemTimes
//sys _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) = kernel32.GlobalMemoryStatusEx
//sys _ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, buffer uintptr, size uintptr, numRead *uintptr) (s bool) = kernel32.ReadProcessMemory

var (
sizeofMemoryStatusEx = uint32(unsafe.Sizeof(MemoryStatusEx{}))
Expand Down Expand Up @@ -67,6 +68,9 @@ const (
ProcessorArchitectureUnknown ProcessorArchitecture = 0xFFFF
)

// ErrReadFailed is returned by ReadProcessMemory on failure
var ErrReadFailed = errors.New("ReadProcessMemory failed")

func (a ProcessorArchitecture) String() string {
names := map[ProcessorArchitecture]string{
ProcessorArchitectureAMD64: "x86_64",
Expand Down Expand Up @@ -218,3 +222,18 @@ func GlobalMemoryStatusEx() (MemoryStatusEx, error) {

return memoryStatusEx, nil
}

// ReadProcessMemory reads from another process memory. The Handle needs to have
// the PROCESS_VM_READ right.
// On failure, ErrReadFailed is returned.
// A zero-byte read is a no-op, no error is returned.
func ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, dest []byte) (numRead uintptr, err error) {
n := len(dest)
if n == 0 {
return 0, nil
}
if !_ReadProcessMemory(handle, baseAddress, uintptr(unsafe.Pointer(&dest[0])), uintptr(n), &numRead) {
return numRead, ErrReadFailed
}
return numRead, nil
}
22 changes: 22 additions & 0 deletions psapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

// Syscalls
//sys _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCountersEx, cb uint32) (err error) = psapi.GetProcessMemoryInfo
//sys _GetProcessImageFileNameA(handle syscall.Handle, imageFileName *byte, nSize uint32) (len uint32, err error) = psapi.GetProcessImageFileNameA

var (
sizeofProcessMemoryCountersEx = uint32(unsafe.Sizeof(ProcessMemoryCountersEx{}))
Expand Down Expand Up @@ -60,3 +61,24 @@ func GetProcessMemoryInfo(process syscall.Handle) (ProcessMemoryCountersEx, erro
}
return info, nil
}

// GetProcessImageFileName retrieves the process main executable.
// The returned path is a device path, that is:
// "\Device\HardDisk0Volume1\Windows\notepad.exe"
// instead of
// "C:\Windows\notepad.exe"
// Use QueryDosDevice or equivalent to convert to a drive path.
func GetProcessImageFileName(handle syscall.Handle) (string, error) {
for bufLen, limit := syscall.MAX_PATH, syscall.MAX_PATH*4; bufLen <= limit; bufLen *= 2 {
buf := make([]byte, bufLen)
nameLen, err := _GetProcessImageFileNameA(handle, &buf[0], uint32(len(buf)))
if err == nil {
buf = buf[:nameLen]
return string(buf), nil
}
if err != syscall.ERROR_INSUFFICIENT_BUFFER {
return "", err
}
}
return "", syscall.ERROR_INSUFFICIENT_BUFFER
}
95 changes: 95 additions & 0 deletions vendor/github.com/elastic/go-windows/ntdll.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 38 additions & 9 deletions zsyscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@ var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
modversion = syscall.NewLazyDLL("version.dll")
modpsapi = syscall.NewLazyDLL("psapi.dll")

procGetNativeSystemInfo = modkernel32.NewProc("GetNativeSystemInfo")
procGetTickCount64 = modkernel32.NewProc("GetTickCount64")
procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
procGetFileVersionInfoW = modversion.NewProc("GetFileVersionInfoW")
procGetFileVersionInfoSizeW = modversion.NewProc("GetFileVersionInfoSizeW")
procVerQueryValueW = modversion.NewProc("VerQueryValueW")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
modntdll = syscall.NewLazyDLL("ntdll.dll")

procGetNativeSystemInfo = modkernel32.NewProc("GetNativeSystemInfo")
procGetTickCount64 = modkernel32.NewProc("GetTickCount64")
procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
procGetFileVersionInfoW = modversion.NewProc("GetFileVersionInfoW")
procGetFileVersionInfoSizeW = modversion.NewProc("GetFileVersionInfoSizeW")
procVerQueryValueW = modversion.NewProc("VerQueryValueW")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
procGetProcessImageFileNameA = modpsapi.NewProc("GetProcessImageFileNameA")
procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess")
)

func _GetNativeSystemInfo(systemInfo *SystemInfo) {
Expand Down Expand Up @@ -91,6 +95,12 @@ func _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) {
return
}

func _ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, buffer uintptr, size uintptr, numRead *uintptr) (s bool) {
r0, _, _ := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(handle), uintptr(baseAddress), uintptr(buffer), uintptr(size), uintptr(unsafe.Pointer(numRead)), 0)
s = r0 != 0
return
}

func _GetFileVersionInfo(filename string, reserved uint32, dataLen uint32, data *byte) (success bool, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(filename)
Expand Down Expand Up @@ -168,3 +178,22 @@ func _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCo
}
return
}

func _GetProcessImageFileNameA(handle syscall.Handle, imageFileName *byte, nSize uint32) (len uint32, err error) {
r0, _, e1 := syscall.Syscall(procGetProcessImageFileNameA.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(imageFileName)), uintptr(nSize))
len = uint32(r0)
if len == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}

func _NtQueryInformationProcess(handle syscall.Handle, infoClass uint32, info uintptr, infoLen uint32, returnLen *uint32) (ntStatus uint32) {
r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(handle), uintptr(infoClass), uintptr(info), uintptr(infoLen), uintptr(unsafe.Pointer(returnLen)), 0)
ntStatus = uint32(r0)
return
}

0 comments on commit 5f20f19

Please sign in to comment.