mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
windows: Add low level memory related syscalls
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user