• 如何掃描外部程式的記憶體

說明

    這是市面上遊戲修改器常見的功能 實際上難度並不高 只要統合如何讀寫外部程式記憶體以及如何對應外部程式記憶體使用狀態 然後就可以輕鬆寫出來了 主要步驟如下

    定出記憶體區段

      因為要搜尋的是變數,記憶體屬性必須是可讀寫的,所以一般而言只要定出可讀寫的區段即可 就是屬性為ERW(可執行,可讀,可寫),RW(可讀,可寫)的記憶體區段

      另外 關於程式定址的範圍

      • Dos底下是4K到4MB的範圍
      • Win32底下應用程式是從&H400000到&H7FFFFFFF(2GB的範圍)
        這個值可以從GetSystemInfo中取得 NT會有點不同 不過為了相容一般應用程式還是會訂在&H400000以後
        • GetSystemInfo hSysInfo
          基底定址=hSysInfo.lpMinimumApplicationAddress
          最高定址=hSysInfo.lpMinimumApplicationAddress

      除非是用在Driver或是共享記憶體方面才有可能用到3GB以上的範圍 一般而言 只要定址2GB的應用程式位址即可

    搜尋

      其實這就是在一個陣列中找出某個值 這是在簡單不過了 只要這樣

        For i = 1 to N
           If b(i) = H Then
              '紀錄位址
           End If
        Next

    以下程式是示範搜尋Byte型態的變數 如果要搜尋Integer或是Long型態的變數就交給網友自行撰寫了 方法都一樣 只是byte只要比對一個Byte,Integer和Long分別要比對2和4個Byte..

程式

    '這個程式需要一個Command,兩個Text,一個ListBox
    Private Sub Command1_Click()
    Dim mbi As MEMORY_BASIC_INFORMATION
    Dim hwnd As Long, hProcessID As Long, hProcess As Long
    Dim tmpBassAddr As Double, lBassAddr As Long
    Dim BassAddr() As Long, PageSize() As Long, PageNum As Long

    List1.Clear

    'Text1輸入要搜尋視窗的標題
    hWnd = FindWindow(vbNullString, Text1.Text)
    If hWnd = 0 Then
        MsgBox "無法找到該視窗"
        Exit Sub
    End If

    '由視窗的Handle取得Process ID
    Call GetWindowThreadProcessId(hWnd, hProcessID)
    If hProcessID = 0 Then
        MsgBox "無法取得ProcessID"
        Exit Sub
    End If
       
    '開啟該Process
    hProcess = OpenProcess(PROCESS_ALL_ACCESS _
    , 0, hProcessID)
    If hProcess = 0 Then
        MsgBox "無法開啟該Process"
        Exit Sub
    End If

    '------------------以下是對應區塊的程式----------------------------
    '為了謹慎起見 定址由0開始 一直到&H7FFFFFFF
    Do While VirtualQueryEx(hProcess, ByVal lBassAddr, mbi, Len(mbi)) '若執行成功
       
        '預防溢位 由於Long型態最大值是&H7FFFFFFF
        '如果定址超出這個範圍就離開
        tmpBassAddr = mbi.BaseAddress
        tmpBassAddr = tmpBassAddr + mbi.RegionSize
        If tmpBassAddr > &H7FFFFFFF Then
            Exit Do
        End If
       
        '定出已配置解渴讀寫的區塊
        If mbi.State = MEM_COMMIT Then '已配置
            If mbi.Protect And (PAGE_READWRITE Or PAGE_EXECUTE_READWRITE Or PAGE_EXECUTE_WRITECOPY) Then
                '符合 紀錄基底位址以及區塊大小
               
    ReDim Preserve BassAddr(PageNum)
                ReDim Preserve PageSize(PageNum)
                BassAddr(PageNum) = mbi.BaseAddress '基底位址
                PageSize(PageNum) = mbi.RegionSize '區塊大小
                PageNum = PageNum + 1 '紀錄總區塊數
            End If
        End If
       
        lBassAddr = tmpBassAddr '對應下一筆
    Loop
    '-----------------------結束對應區塊-----------------------

    '-----------------------以下是搜尋的部分-----------------
    Dim data() As Byte, i As Long, j As Long, k As Long
    Dim finded As Long, fio As Byte
    fio = CByte(Text2.Text) '要搜尋的數值
    For i = 0 To PageNum - 1
        ReDim data(1 To PageSize(i)) '根據區塊大小配置記憶體
        '讀取記憶體
        ReadProcessMemory hProcess, ByVal BassAddr(i), data(1), PageSize(i), ByVal 0&

        '比對
        For j = 1 To PageSize(i)
            If data(j) = fio Then
                List1.AddItem BassAddr(i) + j - 1
                DoEvents
                finded = finded + 1
            End If
        Next
    Next
    '-----------------------結束搜尋的部分-----------------

    MsgBox "執行完畢 一共找到 " & finded & "筆資料"

    '關閉該Process
    CloseHandle hProcess

    '釋放陣列配置的記憶體
    Erase BassAddr
    Erase PageSize
    Erase data
    End Sub

範例程式下載

文件出處

    Honey

整理時間

    2002'3,30.

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

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