windows: Add low level memory related syscalls

This commit is contained in:
Weilu Jia
2021-09-25 19:43:29 -07:00
parent 92d5a993a6
commit 2bb1585ee9
4 changed files with 173 additions and 0 deletions

View File

@@ -35,3 +35,14 @@ const (
QUOTA_LIMITS_HARDWS_MAX_DISABLE = 0x00000008
QUOTA_LIMITS_HARDWS_MAX_ENABLE = 0x00000004
)
type MemoryBasicInformation struct {
BaseAddress uintptr
AllocationBase uintptr
AllocationProtect uint32
PartitionId uint16
RegionSize uintptr
State uint32
Protect uint32
Type uint32
}

View File

@@ -274,6 +274,11 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys VirtualAlloc(address uintptr, size uintptr, alloctype uint32, protect uint32) (value uintptr, err error) = kernel32.VirtualAlloc
//sys VirtualFree(address uintptr, size uintptr, freetype uint32) (err error) = kernel32.VirtualFree
//sys VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect *uint32) (err error) = kernel32.VirtualProtect
//sys VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect uint32, oldProtect *uint32) (err error) = kernel32.VirtualProtectEx
//sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery
//sys VirtualQueryEx(process Handle, address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQueryEx
//sys ReadProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uint32, numberOfBytesRead *uintptr) (err error) = kernel32.ReadProcessMemory
//sys WriteProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uint32, numberOfBytesWritten *uintptr) (err error) = kernel32.WriteProcessMemory
//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
//sys FindFirstChangeNotification(path string, watchSubtree bool, notifyFilter uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.FindFirstChangeNotificationW

View File

@@ -777,3 +777,115 @@ func TestProcessModules(t *testing.T) {
t.Fatalf("module size does not match executable: %v != %v", moduleInfo.SizeOfImage, peSizeOfImage)
}
}
func TestReadWriteProcessMemory(t *testing.T) {
testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D}
process, err := windows.GetCurrentProcess()
if err != nil {
t.Fatalf("unable to get current process: %v", err)
}
buffer := make([]byte, len(testBuffer))
err = windows.ReadProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uint32(len(buffer)), nil)
if err != nil {
t.Errorf("ReadProcessMemory failed: %v", err)
}
if !bytes.Equal(testBuffer, buffer) {
t.Errorf("bytes read does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
}
buffer = []byte{0xDE, 0xAD, 0xBE, 0xEF}
err = windows.WriteProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uint32(len(buffer)), nil)
if err != nil {
t.Errorf("WriteProcessMemory failed: %v", err)
}
if !bytes.Equal(testBuffer, buffer) {
t.Errorf("bytes written does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
}
}
func TestVirtualProtect(t *testing.T) {
testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D}
memBasicInfo := windows.MemoryBasicInformation{}
err := windows.VirtualQuery(uintptr(unsafe.Pointer(&testBuffer[0])), &memBasicInfo, unsafe.Sizeof(memBasicInfo))
if err != nil {
t.Fatalf("VirtualQuery failed: %v", err)
}
origProtect := memBasicInfo.Protect
var oldProtect uint32
var newProtect uint32 = windows.PAGE_EXECUTE_READWRITE
err = windows.VirtualProtect(uintptr(unsafe.Pointer(&testBuffer[0])), uintptr(len(testBuffer)), newProtect, &oldProtect) // NB: Golang does not like it if you remove permissions
if err != nil {
t.Fatalf("VirtualProtect failed: %v", err)
}
if origProtect != oldProtect {
t.Errorf("VirtualQuery Protect does not match oldProtect: 0x%X != 0x%X", origProtect, oldProtect)
}
err = windows.VirtualQuery(uintptr(unsafe.Pointer(&testBuffer[0])), &memBasicInfo, unsafe.Sizeof(memBasicInfo))
if err != nil {
t.Errorf("VirtualQuery failed: %v", err)
}
if memBasicInfo.Protect != newProtect {
t.Errorf("VirtualQuery Protect does not match newProtect: 0x%X != 0x%X", memBasicInfo.Protect, newProtect)
}
// Restore state
newProtect = oldProtect
err = windows.VirtualProtect(uintptr(unsafe.Pointer(&testBuffer[0])), uintptr(len(testBuffer)), newProtect, &oldProtect)
if err != nil {
t.Fatalf("VirtualProtect failed during restore: %v", err)
}
}
func TestVirtualProtectEx(t *testing.T) {
testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D}
process, err := windows.GetCurrentProcess()
if err != nil {
t.Fatalf("unable to get current process: %v", err)
}
memBasicInfo := windows.MemoryBasicInformation{}
err = windows.VirtualQueryEx(process, uintptr(unsafe.Pointer(&testBuffer[0])), &memBasicInfo, unsafe.Sizeof(memBasicInfo))
if err != nil {
t.Fatalf("VirtualQueryEx failed: %v", err)
}
origProtect := memBasicInfo.Protect
var oldProtect uint32
var newProtect uint32 = windows.PAGE_EXECUTE_READWRITE
err = windows.VirtualProtectEx(process, uintptr(unsafe.Pointer(&testBuffer[0])), uintptr(len(testBuffer)), newProtect, &oldProtect) // NB: Golang does not like it if you remove permissions
if err != nil {
t.Fatalf("VirtualProtectEx failed: %v", err)
}
if origProtect != oldProtect {
t.Errorf("VirtualQueryEx Protect does not match oldProtect: 0x%X != 0x%X", origProtect, oldProtect)
}
err = windows.VirtualQueryEx(process, uintptr(unsafe.Pointer(&testBuffer[0])), &memBasicInfo, unsafe.Sizeof(memBasicInfo))
if err != nil {
t.Errorf("VirtualQueryEx failed: %v", err)
}
if memBasicInfo.Protect != newProtect {
t.Errorf("VirtualQueryEx Protect does not match newProtect: 0x%X != 0x%X", memBasicInfo.Protect, newProtect)
}
// Restore state
newProtect = oldProtect
err = windows.VirtualProtectEx(process, uintptr(unsafe.Pointer(&testBuffer[0])), uintptr(len(testBuffer)), newProtect, &oldProtect)
if err != nil {
t.Fatalf("VirtualProtectEx failed during restore: %v", err)
}
}

View File

@@ -303,6 +303,7 @@ var (
procReadConsoleW = modkernel32.NewProc("ReadConsoleW")
procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
procReadFile = modkernel32.NewProc("ReadFile")
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
procReleaseMutex = modkernel32.NewProc("ReleaseMutex")
procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
procResetEvent = modkernel32.NewProc("ResetEvent")
@@ -345,12 +346,16 @@ var (
procVirtualFree = modkernel32.NewProc("VirtualFree")
procVirtualLock = modkernel32.NewProc("VirtualLock")
procVirtualProtect = modkernel32.NewProc("VirtualProtect")
procVirtualProtectEx = modkernel32.NewProc("VirtualProtectEx")
procVirtualQuery = modkernel32.NewProc("VirtualQuery")
procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx")
procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId")
procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects")
procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
procWriteFile = modkernel32.NewProc("WriteFile")
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
procAcceptEx = modmswsock.NewProc("AcceptEx")
procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
procTransmitFile = modmswsock.NewProc("TransmitFile")
@@ -2636,6 +2641,14 @@ func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (
return
}
func ReadProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uint32, numberOfBytesRead *uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesRead)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ReleaseMutex(mutex Handle) (err error) {
r1, _, e1 := syscall.Syscall(procReleaseMutex.Addr(), 1, uintptr(mutex), 0, 0)
if r1 == 0 {
@@ -2990,6 +3003,30 @@ func VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect
return
}
func VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect uint32, oldProtect *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procVirtualProtectEx.Addr(), 5, uintptr(process), uintptr(address), uintptr(size), uintptr(newProtect), uintptr(unsafe.Pointer(oldProtect)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) {
r1, _, e1 := syscall.Syscall(procVirtualQuery.Addr(), 3, uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func VirtualQueryEx(process Handle, address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procVirtualQueryEx.Addr(), 4, uintptr(process), uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func VirtualUnlock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := syscall.Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if r1 == 0 {
@@ -3046,6 +3083,14 @@ func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped)
return
}
func WriteProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uint32, numberOfBytesWritten *uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesWritten)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) {
r1, _, e1 := syscall.Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {