我试图使用Go语言在Windows上操作进程,
我开始阅读其他流程'记忆使用ReadProcessMemory
。
但是,对于大多数地址,我收到Error: Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
错误。也许我的论据清单是错误的,但我找不到原因。
有谁可以指出我在这里做错了什么?
package main
import (
"fmt"
)
import (
windows "golang.org/x/sys/windows"
)
func main() {
handle, _ := windows.OpenProcess(0x0010, false, 6100) // 0x0010 PROCESS_VM_READ, PID 6100
procReadProcessMemory := windows.MustLoadDLL("kernel32.dll").MustFindProc("ReadProcessMemory")
var data uint = 0
var length uint = 0
for i := 0; i < 0xffffffff; i += 2 {
fmt.Printf("0x%x\n", i)
// BOOL ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead)
ret, _, e := procReadProcessMemory.Call(uintptr(handle), uintptr(i), uintptr(data), 2, uintptr(length)) // read 2 bytes
if (ret == 0) {
fmt.Println(" Error:", e)
} else {
fmt.Println(" Length:", length)
fmt.Println(" Data:", data)
}
}
windows.CloseHandle(handle)
}
答案 0 :(得分:6)
uintptr(data)
不正确:它取data
的值(类型为uint
的0)并将其转换为unitptr
类型 - 产生转换为其他类型的相同值 - 在x86上生成一个空指针。
注意Go不是C,你不能真正玩指针中的脏游戏,或者你可以,但只能通过使用unsafe
内置包及其{{1类似于Pointer
(指向数据存储块中的某个位置)的C语言。
您需要的是
void*
观察这里做了什么:
import "unsafe"
var (
data [2]byte
length uint32
)
ret, _, e := procReadProcessMemory.Call(uintptr(handle), uintptr(i),
uintptr(unsafe.Pointer(&data[0])),
2, uintptr(unsafe.Pointer(&length))) // read 2 bytes
; unsafe.Pointer
。最后两步是必需的,因为Go功能垃圾收集:
uintptr
,GC仍会考虑新值,并且行为类似于包含地址的“正常”值 - 如上所述通过将此类值转换为unsafe.Pointer
,可以使GC停止将其视为指针。因此,这种类型只适用于FFI /互操作。
换句话说,在
中uintptr
var data [2]byte
a := &data[0]
p := unsafe.Pointer(a)
i := uintptr(p)
中的值只有三个引用:该变量本身,data
和a
,但不是p
。
在处理调用外部代码时,您应该考虑这些规则,因为您永远不应该传递i
- 类型的值:它们仅用于将数据封送到被调用的函数并将其解组,并且必须是“在现场”使用 - 与从/到它们的类型转换的值在相同的范围内。
另请注意,在Go中,您不能只获取整数类型变量的地址,并将该地址提供给需要指向适当大小的内存块的指针的函数。您必须处理字节数组,并且在被调用函数写入数据之后,您需要将其显式转换为您需要的类型的值。这就是Go中没有“类型转换”但只有“类型转换”的原因:你不能通过类型转换重新解释值的数据类型,unitptr
(和)作为FFI / interop目的的一个值得注意的例外,即使在这种情况下,你基本上将指针转换为指针,只是通过GC边界传输它。
要“序列化”和“反序列化”整数类型的值,您可以使用encoding/binary
标准包或手动滚动简单函数,这些函数执行按位移位和uintptr(unsafe.Pointer)
- s和等等; - )
2015-10-05,根据James Henstridge的建议更新。
请注意,函数返回后,or
表示没有错误
你必须检查ret
变量的值。