亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Go 中調用 kernel32 的 ReadProcessMemory

在 Go 中調用 kernel32 的 ReadProcessMemory

Go
開滿天機 2021-11-08 19:23:38
我正在嘗試使用 Go 語言在 Windows 上操作進程,并且我通過使用ReadProcessMemory.但是,對于大多數地址,我都會Error: Only part of a ReadProcessMemory or WriteProcessMemory request was completed.出錯。也許我的參數列表是錯誤的,但我不知道為什么。誰能指出我在這里做錯了什么?package mainimport (  "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)}
查看完整描述

1 回答

?
阿波羅的戰車

TA貢獻1862條經驗 獲得超6個贊

uintptr(data)不正確:它從data(0 of type uint)獲取值并將其轉換為unitptrtype — 產生轉換為另一種類型的相同值 — 在 x86 上產生空指針。


請注意,Go 不是 C,并且您不能真正玩帶有指針的骯臟游戲,或者更確切地說,您可以,但只能通過使用unsafe內置包及其Pointer類型void*(指向數據存儲器中的某個位置)塊)在 C 中。


你需要的是類似的東西


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

觀察這里做了什么:

  1. 聲明了一個“兩字節數組”類型的變量;

  2. 取這個數組第一個元素的地址;

  3. 該地址被類型轉換為類型unsafe.Pointer;

  4. 然后將獲得的值類型轉換為uintptr。

需要最后兩個步驟,因為 Go 具有垃圾收集功能:

  • 在 Go 中,當你在內存中獲取一個值的地址并將其存儲在一個變量中時,GC 知道這個“隱式”指針,并且即使它變得無法訪問,該地址的值也不會被垃圾收集保存其地址的值是唯一的引用。

  • 即使您使該地址值丟失了它所維護的類型信息——通過將其類型轉換為unsafe.Pointer,新值仍會被 GC 考慮并且表現得像包含地址的“正?!敝怠缟纤觥?/p>

  • 通過將此類值類型轉換為uintptr您可以讓 GC 停止將其視為指針。因此,這種類型僅適用于 FFI/互操作。

    換句話說,在

    var data [2]byte
    a := &data[0]
    p := unsafe.Pointer(a)
    i := uintptr(p)

    中的值只有三個引用data:該變量本身ap,但不是i。

在處理調用外部代碼時,您應該考慮這些規則,因為您永遠不應該傳遞unitptr-typed 值:它們僅用于將數據編組到被調用的函數并將其解組回來,并且必須“在現場”使用 - 在與它們從/到類型轉換的值相同的范圍。

另請注意,在 Go 中,您不能只獲取整數類型變量的地址并將該地址提供給需要指向適當大小的內存塊的指針的函數。您必須處理字節數組,并且在被調用函數寫入數據后,您需要將其顯式轉換為所需類型的值。這就是為什么 Go 中沒有“類型轉換”而只有“類型轉換”:您不能通過類型轉換重新解釋值的數據類型,uintptr(unsafe.Pointer)對于 FFI/互操作而言,(和返回)是一個顯著的例外,即使在這種情況下,您也基本上將指針轉換為指針,只需將其通過 GC 邊界傳輸即可。

要“序列化”和“反序列化”整數類型的值,您可以使用encoding/binary標準包或手卷簡單的簡單函數,這些函數執行按位移位和or-s 等;-)


2015-10-05,根據 James Henstridge 的建議更新。

請注意,在函數返回并發出ret信號后,您必須檢查length變量的值沒有錯誤。


查看完整回答
反對 回復 2021-11-08
  • 1 回答
  • 0 關注
  • 537 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號