1. 程式人生 > >遊戲修改器製作教程三:記憶體與Cheat Engine

遊戲修改器製作教程三:記憶體與Cheat Engine

本教程面向有C\C++基礎的人,最好還要懂一些Windows程式設計知識
程式碼一律用Visual Studio 2013編譯,如果你還在用VC6請趁早丟掉它...
寫這個教程只是為了讓玩家更好地體驗所愛的單機遊戲,順便學到些逆向知識,我不會用網路遊戲做示範,請自重

本章介紹記憶體與Cheat Engine

計算機程式所有的變數、程式碼都是儲存在記憶體裡的,包括遊戲裡那些HP、MP、金錢等,那麼只要能修改記憶體就能自由改變玩家的HP、金錢了(當然對於網遊是沒用的,這些資料都儲存在伺服器,客戶端裡的只是一個副本),常見的滿血、金錢無限等遊戲修改器大部分就是這個原理

想要修改指定的變數你要知道變數在記憶體裡的地址,這時會用到記憶體搜尋工具

Cheat Engine

Cheat Engine(以下簡稱CE)是最常用的開源的記憶體搜尋軟體,它還包括了很多除錯工具

雖然看這名字就知道是用來遊戲作弊的,但是也可以用於普通程式的記憶體搜尋和除錯

它的官網和GitHub庫:
官網
GitHub庫

你可以在官網或我的網盤下載到CE,我的網盤裡的整合了中文補丁和一箇中文版練習程式

本文通過CE自帶的練習程式介紹用CE搜尋記憶體的方法和常用的作弊手段,現在開啟CE的練習程式,點選Next來到Step2

Step 2

這關是查詢精確數值的練習,首先在CE中開啟練習程式的程序:點選右上角選擇程序的按鈕,選中練習程式,開啟程序

然後看看練習程式裡的HP是100,那麼搜尋精確值100,型別選4位元組(也就是int型)

左邊會出來一堆記憶體地址,因為有很多地址的值為100嘛
然後在練習程式裡點Hit me,HP變成了95,回到CE裡再次掃描95

左邊只剩下一個地址了,雙擊它把它加入下面的列表,然後再雙擊列表中的值,改為1000

回到練習程式裡,Next按鈕可以點了,過關~(這時你可以再點Hit me看看HP是多少)

Step3

這關沒有給你精確數值了,只有一個血條,只知道HP範圍是0到500

因為不知道數值,這次掃描型別選擇未知的初始值,假設數值型別為4位元組,點首次掃描

然後左邊出現檢索:365,568個地址,但是不顯示在列表裡(因為並沒有什麼用)

在練習程式裡點Hit me,閃過個-5
既然知道減了5HP,CE裡掃描型別選數值減少了...,值填5(如果連減少了多少值都不知道掃描型別就選減少的數值),再次掃描

只剩下6個地址了(其實可以看出就是第二個,因為HP範圍為0到500)

重複上一步直到只剩下一個地址(或者你能看出是哪個地址),然後把值改成5000過關

Step 4

這關是練習浮點數的搜尋,方法和Step 2一樣,只是把數值型別換成浮點數和雙浮點數,我就不重複說了,把HP和子彈都改成5000過關

浮點數運算是有誤差的,CE也允許搜尋的浮點數的值有一定誤差

Step 5

既然程式碼也是儲存在記憶體的,那麼能修改記憶體就能修改程式碼了
當然記憶體裡儲存的可不是C語言,而是編譯後的機器語言,它很難翻譯成高階語言但是可以很容易翻譯成組合語言(反彙編),所以修改程式碼需要學習一些彙編知識
本章可以不用學彙編,照著做留個印象就好了

這關的要求是點選Change value後值不變,也就是把修改值的程式碼替換成什麼也不幹(彙編裡的nop指令)

首先找到值的地址(同Step 2),然後右鍵,選擇找出是什麼改寫了這個地址

然後再點一下練習程式裡的Change value,指令列表裡會出現改寫了這個地址的指令

選中它,點右邊的替換就會把它換成什麼也不幹的指令
關閉這個視窗,回到練習程式裡點Change value過關

Step 6

有些變數的地址會變,比如動態申請記憶體的變數 int* p = (int*)malloc(10 * sizeof(int)); int* p = new int[10]; 但是不管怎麼變總會有個靜態的地址儲存它的指標

本關要求是改變指標後值還是5000

首先找到值的地址,然後右鍵選擇找出是什麼訪問了這個地址

再點選Change value,出現很多條指令,先雙擊第一條

(其實熟悉彙編的話這裡就可以看出指標地址是Tutorial-x86_64.exe+0x2F7A50了,其中Tutorial-x86_64.exe表示這個模組的基址)

這是一條讀取0x01250C30的指令,這裡顯示指標的值可能是0x118,一看就很不靠譜,和0x01250C30差太多了,再看下一條

這是一條寫入0x01250C30的指令,顯示指標的值可能是0x01250C30,正好和值的地址一樣,就是它了

然後搜尋十六進位制01250C30,出來一個地址,這就是指標的地址,並且地址是綠色的說明它是靜態的
點手動新增地址,勾上指標,填指標的地址

然後把值改成5000,勾上鎖定

回到練習程式點選Change pointer過關

為什麼不直接搜尋0x01250C30而要看彙編程式碼呢?因為指標的值不一定是0x01250C30,比如這個變數在一個struct裡而且不是第一個成員,比如是下面這個struct的v2
struct Foo
{
    int v1;
    int v2;
};
那麼應該搜尋0x01250C2C並且新增地址時偏移量要填4

如果搜尋出來的不是靜態地址怎麼辦?說明這是多級指標,比如p1->p2->p3->p4->v,你要一直找到指標p1...

Step 7

這關要求是點選Hit me你的HP會+2,就是把HP-1的程式碼換成HP+2

按照Step 5找到寫入HP的程式碼

點選右邊的顯示反彙編工具,雙擊這行程式碼,把前面的sub改成add,後面的01改成02

然後點選Hit me就過關了

不過這裡add指令和sub指令的長度剛好一樣,如果add的長度大於sub的長度就會破壞後面的指令了,這時要用到CE的程式碼注入功能

點選選單裡的工具-自動彙編

然後點選單裡的模板-程式碼注入

填入在哪條地址上跳轉,這裡是"Tutorial-x86_64.exe"+2C77B,就是那條sub指令的地址

然後把原始碼的sub指令去掉,在newmem裡寫入add指令

點執行,完成程式碼注入

你可以看到原來的sub指令變成了jmp指令,就是跳到我們的程式碼

跟過去看看裡面是我們的程式碼,執行完後跳回去繼續執行後面的程式碼

Step 8

這關就是傳說中的多級指標,目標是點Change pointer後值還是5000

和Step 6一樣先找值的地址,找訪問這個地址的指令

(其實會彙編的話看看前面的程式碼就知道結果了,但不是經常有讀取指標的指令連在一起的情況,更多的是某個類中某個方法訪問了成員物件中的某個成員...這樣)

偏移量為0x18,搜尋0x012A3B00得到一級指標,再找訪問這個指標的指令

偏移量為0,搜尋0x0123CA60得到二級指標,再找訪問這個指標的指令

偏移量為0x18,搜尋0x0123C220得到三級指標,再找訪問這個指標的指令

偏移量為0x10,搜尋0x0125B620得到四級指標,顯示為綠色,是靜態地址,終於不用找了...

點手動新增地址,勾上指標,點三次Add offset,填入頂級指標的地址和各級指標的偏移量

把值改成5000,勾上鎖定,點Change pointer過關

Step 9

可能你和你的敵人減血用同一個程式碼,如果你刪除了這個程式碼你的敵人也會受到影響

這一關你要注入程式碼分辨出減血的是你的隊伍還是敵人,讓你的隊伍勝利,而且不能用鎖定血量

先找出各玩家的HP地址(根據提示HP是浮點數)

其中在找第一個HP的二級指標時出了點問題,CE的反彙編是這樣的

估計CE的x64反彙編還不完善,這裡我用IDA反彙編是這樣的

可以看出偏移量是0x7F8,應該搜尋RBX暫存器的值0x0113CB90
(其實知道了後面三個HP的偏移量也能猜出第一個HP的偏移量,這明顯是一個指標陣列)

然後為了分辨出玩家還要分析一下玩家的資料結構,開啟記憶體瀏覽器點選單的工具-分析資料/結構

然後點檔案-Add new group新增3個group,每個group填入各HP的地址(準確來說應該填入指向HP指標的值,這裡也就是減去偏移量0x08,不過我已經知道前8個位元組是沒用的)

點選結構-定義新的結構並且讓CE嘗試填入基本型別

可以看出第一個是HP,第4個是隊伍ID,第5個是玩家名字

那麼分辨的方法有很多種,可以判斷HP>100的是敵人,或者隊伍ID不等於1的是敵人,或者判斷名字,或者判斷指標指向哪個玩家...

這裡我就判斷隊伍ID吧,在減HP的地方注入程式碼:

點Restart game and autoplay過關~~