• 如何讀寫外部程式的記憶體

說明

    這是我在留言版上看到的問題,其實就是要做一個簡單的記憶體修改器,我所公開的這個程式許多部分我已經把他簡化了,一方面關於記憶體有許許多多東西必須要先知道的,這要說明可是要用上許多篇幅,所以我只針對讀取及寫入的核心Read/WriteProcessMemory下手

    • Read/WriteProcessMemory(ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long

        hProcess:
              這是要讀取寫入的Process的Handle
        lpBaseAddress:
           
      這是要讀取或是寫入的基底位址
        lpBuffer:
             這是用來存取要讀取或寫入的資料
        nSize:
       
           這是lpBuffer的大小
        lpNumberOfBytesWritten:
       
           這是該程式執行後實際讀取的資料大小

    比較大的問題是如何取得Process的Handle,一般是從FindWindow開始取得該視窗的handle,如果要取得標題是"記事本"視窗的Handle只要這樣
         Dim hWnd As Long '視窗的Handle
         hWnd = FindWindow(vbNullString, "記事本")

    取得視窗的Handle後就可以用GetWindowThreadProcessId取得該Process的ID
         Dim ProcessID As Long
         GetWindowThreadProcessId hWnd, ProcessID

    之後只要用OpenProcess開啟該ProcessID即可取得Process的Handle
         Dim hProcess As Long
         hProcess = OpenProcess(PROCESS_ALL_ACCESS _
                           , 0, hProcessID)
    ' 由於要讀寫該Process所以必須加上PROCESS_VM_READ
    ' 和PROCESS_VM_WRITE 也可以直接以PROCESS_ALL_ACCESS取代全部


    有興趣的讀者可以下載此範例程式AccessProcessMemory.Imp
    這個範例中有個執行檔test.exe可以作為做讀寫的目標
    執行檔的按鈕上方文字顯示該變數的位址 只要在程式的Text2或Text4填入該位址即可對該變數做讀寫的動作 之後你可以按下test.exe的按鍵 實際確認變數的值 是否已被修改

程式

    '-----------------------------------------------------------------------------------------------
    '以下程式在模組
    Option Explicit
    Public Type SYSTEM_INFO
            dwOemID As Long
            dwPageSize As Long
            lpMinimumApplicationAddress As Long
            lpMaximumApplicationAddress As Long
            dwActiveProcessorMask As Long
            dwNumberOrfProcessors As Long
            dwProcessorType As Long
            dwAllocationGranularity As Long
            dwReserved As Long
    End Type
    Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Public Const SYNCHRONIZE = &H100000
    Public Const SPECIFIC_RIGHTS_ALL = &HFFFF
    Public Const STANDARD_RIGHTS_ALL = &H1F0000
    Public Const PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF
    Public Const PROCESS_VM_OPERATION = &H8&
    Public Const PROCESS_VM_READ = &H10&
    Public Const PROCESS_VM_WRITE = &H20&
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
    Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
    Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Public Declare Sub GetSystemInfo Lib "kernel32" (lpSystemInfo As SYSTEM_INFO)
    Public Declare Function GetWindowThreadProcessId Lib "user32" _
    (ByVal hWnd As Long, lpdwProcessId As Long) As Long
    Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    '----------------------------------------------------------------------------------------------
    '以下程式在Form中
    Option Explicit
    Dim hProcess As Long
    Dim hProcessID As Long
    Dim hThreadID As Long
    Dim hWndOfApp As Long
    Dim hSysInfo As SYSTEM_INFO
    Dim lBassAddr As Long
    Private Sub Command1_Click()
    List2.Clear
    Dim s() As Byte, n As Long, i As Long
    lBassAddr = Text2.Text
    n = Text3.Text
    ReDim s(n - 1)
    hWndOfApp = FindWindow(vbNullString, Text1.Text)
    If hWndOfApp = 0 Then
        MsgBox "無法找到該視窗"
        Exit Sub
    End If
    hThreadID = GetWindowThreadProcessId(hWndOfApp, hProcessID)
    If hProcessID = 0 Then
        MsgBox "無法取得ProcessID"
        Exit Sub
    End If
       
    hProcess = OpenProcess(PROCESS_ALL_ACCESS _
    , 0, hProcessID)

    If hProcess = 0 Then
        MsgBox "無法開啟該Process"
        Exit Sub
    End If
     
    ReadProcessMemory hProcess, ByVal lBassAddr, s(0), n, ByVal 0&
    For i = 0 To n - 1
        List2.AddItem "位址:" & (i + lBassAddr) & "= " & s(i)
    Next


    CloseHandle hProcess
    End Sub

    Private Sub Command2_Click()
    Dim s() As Byte, n As Long, i As Long
    Dim Data1 As Byte, Data2 As Integer, Data4 As Long
    lBassAddr = Text4.Text
    If Option1(0).Value Then
        n = 1
        ReDim s(0)
        Data1 = Text5.Text
        CopyMemory s(0), Data1, n
    ElseIf Option1(1).Value Then
        n = 2
        ReDim s(0 To 1)
        Data2 = Text5.Text
        CopyMemory s(0), Data2, n
    ElseIf Option1(2).Value Then
        n = 4
        ReDim s(0 To 3)
        Data4 = Text5.Text
        CopyMemory s(0), Data4, n
    End If

    hWndOfApp = FindWindow(vbNullString, Text1.Text)
    hThreadID = GetWindowThreadProcessId(hWndOfApp, hProcessID)
    hProcess = OpenProcess(PROCESS_ALL_ACCESS _
    , 0, hProcessID)
    WriteProcessMemory hProcess, ByVal lBassAddr, s(0), n, ByVal 0&
    CloseHandle hProcess
    End Sub

    Private Sub Form_Load()
    GetSystemInfo hSysInfo '取得應用程式最小及最大定址
    Text2.Text = hSysInfo.lpMinimumApplicationAddress '應用程式最小定址
    Text4.Text = hSysInfo.lpMinimumApplicationAddress '應用程式最小定址
    Label5.Caption = "可用位址從" & hSysInfo.lpMinimumApplicationAddress & _
    " 到 " & hSysInfo.lpMaximumApplicationAddress
    End Sub


    這個和市面上的遊戲修改器還有點差距,其實就少了搜尋的功能,不過這並不難,我有空會再把他加上。

文件出處

      Honey

整理時間

      2001'9,8.

VB心得筆記歡迎各位的指教,如果您有任何文章或資料願意提供給我們的,請來信到VBNote

如果對本站有任何建議,歡迎來信給Honey,我們會盡快給您答覆