魚骨頭的雲端圖書館's Archiver

mhfo 發表於 2012-12-11 08:42

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

[url]http://sunh.hosp.ncku.edu.tw/~cww/html/q00486.html[/url]

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


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

頁: [1]

Powered by Discuz! Archiver 7.0.0  © 2001-2009 Comsenz Inc.