小華的部落格: 2007/7/29 - 2007/8/5

搜尋此網誌

星期一, 7月 30, 2007

動態記憶體(3)-撰寫輔助程式

前面兩篇文章提到如何去找到動態記憶體指標的程式碼位址,然後注入一段程式碼來取得指標ESI的位址,如果你在Softice 中修改後,並且回到遊戲中去驗證沒問題後(驗證的方式就是回到遊戲中隨便更新一下血量,或是重新啟動遊戲讓他重新配置一個指標位址,接著你可以利用GameMaster直接去讀取57BF30h這個位址的內容,這個內容=ESI,所以你要自己加上228h 的位址才會存放你的血量值),你就可以開始動手寫輔助程式了。

ESI+228h=血量位址

如何撰寫輔助程式呢? 這邊會用到的工具:
VC6 or VB6 or...等 (看你自己習慣用哪一種)
Windosw API (自己翻手冊查相關說明)
Softice (用來看機器碼)

簡單說就是利用ReadProcessMemory 或是WriteProcessMemory方式去對記憶體寫入值,而寫入的值是一堆的機器碼(因為你沒辦法像Softice一樣直接修改,所以只好用機器碼的方式注入你的程式碼到修改的位址去),所以你透過SoftIce 去修改好程式碼後,要記得把機器碼抄錄下來(例如: D 44717A),然後用這兩個API寫進去你要修改的位址。

VC6的方式 :
#define MY_CODE1 0xE9
#define MY_CODE2 0x34 //這部分是要寫入的機器碼的常量定義
.........................

//-----------------------------------------------------------------------------//
DWORD A1 =MY_CODE1;
DWORD A2 =MY_CODE2;
..............

//0x0044717A
WriteProcessMemory(nOK,(LPVOID)0x0044717A+0,&A1,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0044717A+1,&A2,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0044717A+2,&A3,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0044717A+3,&A4,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0044717A+4,&A5,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0044717A+5,&A6,1,NULL);
//0057BF00
WriteProcessMemory(nOK,(LPVOID)0x0057BF00+0,&B1,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0057BF00+1,&B2,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0057BF00+2,&B3,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0057BF00+3,&B4,1,NULL);
WriteProcessMemory(nOK,(LPVOID)0x0057BF00+4,&B5,1,NULL);
....

VB6方式:
A_Start = &H0044717A '要修改成JMP的地址
A_End = &H0057BF00 '跳躍JMP到的地址

'&H0044717A
Call WriteProcessMemory(A_Start + 0, &HE9, 1)
Call WriteProcessMemory(A_Start + 1, &H3D, 1)
Call WriteProcessMemory(A_Start + 2, &H31, 1)
Call WriteProcessMemory(A_Start + 3, &H30, 1)
...

動態記憶體(2)-修改流程

前一篇文章中我們介紹了如何透過一些工具去取得你的遊戲程式碼的位址,接著就說明一下整個修改的概念:

1. 先找到程式碼存放的位址,前面我們已經找到了程式碼存放的位址是在44717Ah:
001B:44717A MOV [ESI+228],EDX
001b:44717E ....

2. 修改44717A這個位址的程式碼
001B:44717A JMP 57BF00 <--跳到我們指定的一塊記憶體位址
001B:44717D NOP <--由於修改的JMP 57BF00 指令長度不足原來的,所以增加NOP來補足長度
001b:44717E ....

3. 修改57BF00
001B:57BF00 MOV [ESI+228],EDX <--還原原來被我們破壞掉的程式碼
001B:57BFxx MOV DWORD PTR [57BF30],ESI
001B:57BFxx JMP 44717E
001B:57BFxx

由上面的範例中可以看到整個修改的流程大致上就是如此,先找到他的程式碼的位址,修改它的程式碼,然後跳躍到我們指定的記憶體中,跳躍後我們先去還原原來的程式碼以免造成原來遊戲程式當機,接著把ESI的值存放到我們指定的記憶體位址,那麼當遊戲程式重新分配記憶體位址時,他的位址會放在ESI,而ESI的值會被我們放到我們指定的記憶體中,而我們寫的遊戲輔助程式就直接去我們指定的記憶體中就可以讀到ESI的值了。

※ Softice 修改程式碼的方式鍵入 "A 44717A" ,跟DOS的Debug.com 很像

在上述的方式中,要如何找到一塊可以使用的記憶體? 下面我就提供一個方式:
進入Softice 中,找到你的遊戲視窗名稱,接著鍵入MAP32 指令,如下所示:

:map32 lineage <--lineage 是你遊戲的名稱,這邊是範例,你看的值會不一樣
Owner Obj Name Obj# Address Size Type
lineage .text 0001 017F:00401000 ....
lineage .data 0002 0187:00560000 ....
lineage .rsrc 0005 0187:0057C000 ....

你會看到他把遊戲程式的PE檔頭的一些資訊列印出來給你看,其中.data 後面的560000h代表你的遊戲會把一些資料從記憶體位置560000h 開始存放,而我的方式是從後面自己找一塊來用,例如下一個區塊是從57C000h開始,因此我找57BF00h~57BFFFh 這一塊來當我要使用的地方。

你可以利用Softice 鍵入D 57BF00的方式去看那一塊記憶體有沒有人使用,如果沒有的話你就可以自己拿來用。

動態記憶體(1)-搜尋程式碼

玩過PC遊戲的都知道市面上有一些遊戲修改器可以做一些修改遊戲記憶體內的資訊來達到你的主角能力值變強或是有用不完的金錢...等。

今天我們要探討的是網路遊戲的修改,其實不能算是修改啦,因為對於網路遊戲來說,你無法使用這種方式去修改相關資訊,因為你的主角資訊是放在伺服器端,然後透過網路傳送資訊到你的主機,接著再更新到你的主機上面的記憶體中,例如: 血量:
CMP EDX,EDX
JZ LABLE1
MOV [ESI+228],EDX
...
LABEL1:
...
例如上面的範例,他會去檢查血量有沒有變化,如果有他才會放進去[ESI+228]的記憶體位址中,因此EDX存放著伺服器端傳送過來的血量資料,然後放到你的主機的記憶體位址[ESI+228]的地方,這邊的記憶體位址指的是位址空間,所謂的位址空間是指每個行程都有4G的虛擬記憶體位址,就好比說VC寫的程式在載入記憶體的時候會被固定放在某個位址上去,然後我們就可以知道某段位址範圍放的是"程式碼"。

上面有看到一個[ESI+228]的記憶體位址,由於網路遊戲怕你很容易就找到他的記憶體位址,所以一般會把這個位址用指標方式來重新配置記憶體,簡單說就是你每次找到血量存放的位址會不一樣,所以稱為動態記憶體方式來存放人物資訊,也因此我們要討論的是如何得到這個指標指向的位址,那麼就不用怕他一直變動了,所以由上面的範例可以知道ESI會一直變動,所以我們的目標就是得到ESI的值。

※ESI+228h = 血量位址,每個遊戲不一樣,所以不見得都是用ESI來存放,另外也不見得是+228h

在進入正題前先說明如何去得知你的遊戲是如何把這些資訊放進去記憶體中,我們會使用的工具如下:
1.WinXP
2.SoftIce
3.任何遊戲修改工具 ex: FPE, GameMaster...等

(Step 1): 首先先開啟你的網路遊戲,然後利用遊戲修改工具找到你的血量的記憶體位址(找的方式跟以前一樣,就是先找一次血量,然後進入遊戲改變一下血量,然後再找一次,一直重複到剩下來的位址,或是利用人物ID去搜尋也可以),例如找到的位址是12ABAC00h, 然後按下Ctrl+D 進入SoftIce,進入SoftIce後鍵入BPM 12ABAC00 W ,意思是說設定一個中斷點,當這個記憶體位址12ABAC00 被寫入Write的時候要中斷,接著按下Ctrl+D 回到遊戲中

(Step 2): 回到遊戲後隨便改變一下你的血量(喝藥水或是放法術),然後你就會看到SoftIce 產生了一個中斷,然後進入到SoftIce 畫面(如果有攔截到,就會自動進入SoftIce,如果沒攔截到就可以能你找到的位址不對)

(Step 3): 在SoftIce 中你會看到類似下面的程式碼:
001B:44717A MOV [ESI+228],EDX
001b:44717E ....

他所代表的意思是說你的遊戲主程式載入到記憶體後負責更新血量到記憶體位址12ABAC00h的程式碼是被放在xxxx:44717A ,而程式碼是 MOV [ESI+228],EDX,
你可以在Softice 中鍵入指令 D ESI+228 ,他會把ESI+228的記憶體位址傾印出來,所以你可以在螢幕上看到你的血量值。

(Step 4) : 拿筆把44717A 這個位址抄下來,然後把你的遊戲關閉掉然後重新啟動,重新進入遊戲後重複放面的Step1~3 ,如果每次都是停在44717A,那麼就恭喜你,你已經找到他的動態指標的程式碼的地方,接著就可以想辦法取得ESI 的值了。