【前言】:
小弟我前幾天才剛剛接觸到《獸人必須死》這個游戲,發(fā)現(xiàn)主角真的很賤,不過玩起來很過癮。一直想下載個修改器來痛快虐虐獸人,但是下載的都報毒,不知道是真毒還是誤報,反正老婆大人是不同意在她電腦上用。無奈,自己動手豐衣足食吧。
【工具】
CE,這個就不說了,沒他啥也甭干了。
OD,就是OllyDbg,小弟我從事軟件安全工作,這個工具必不可少。
VC++,我就會C和匯編,其他不會。
【過程】
我打算就做2個功能,1個是鎖定錢,一個是鎖定魔法值。
先來做鎖定錢的,錢因為是數(shù)字,好分析。
1 先用CE找到金錢的地址,動態(tài)地址就可以,不用找基址。如圖1.這個過程巨簡單吧,我就不多說了。不會的童鞋可以看諸位大大的教程或者問我。
2.找到后,右鍵這個地址,選擇“什么改寫這個地址”。然后切換到游戲,花點錢,就能發(fā)現(xiàn)圖2的窗口。選擇顯示匯編,就是紅圈的那個。因為我們要分析匯編語言。
3.接下來,選擇顯示匯編后,我們看見這個界面:
大家注意到,被高亮顯示的那句話就是我們的錢被改寫的匯編指令。我們可以看到,這句話在內(nèi)存地址00794B77的位置。當(dāng)然,各位童鞋要注意,你們顯示的地址肯定和我不一樣,我每次顯示的都不一樣。因為這是一個動態(tài)鏈接庫(DLL),所以地址是動態(tài)的。不過沒關(guān)系,下面我教大家怎么確定他的動態(tài)地址。
4.知道了這個地址,我們就可以改了,但是,就像我說的,他每次都會在00794B77的位置上嗎?答案是否定的,退出游戲再進來,地址就變了,因此我們可以肯定的是,這部分代碼應(yīng)該在動態(tài)鏈接庫中。好,我們看看他在哪一個動態(tài)鏈接庫中。點擊如下圖的菜單:
會顯示《獸人必須死》這個游戲所有加載進來的動態(tài)鏈接庫。如圖:
5.從此圖中我們看到,動態(tài)鏈接庫SaberPlugin的開始地址是00730000,和我們的00794B77位置最近,因此,我們可以確定,剛才位于00794B77的指令在SaberPlugin的動態(tài)庫中。
6.對于windows系統(tǒng),我們不知道每次動態(tài)庫會被加載到內(nèi)存哪里,但是,我們可以通過系統(tǒng)一些功能函數(shù)得到動態(tài)庫加載的基址,然后根據(jù)基址+偏移,最后得到目的地址。接下來,我們計算偏移。請看公式1:
目的地址 = 基址 + 偏移
偏移 = 目的地址 – 基址, 所以我們的偏移地址 = 00794B77 – 00730000 = 64B77。
7.接下來,OD出場了,呵呵,久等了。用OD 附加到游戲進程,然后跳轉(zhuǎn)到指令00794B77的位置,童鞋們要注意了,這時候,要退出CE的調(diào)試,否者OD會報告進程被其他程序加載而失敗。如圖所示:
8.從OD中了解到,該地址的指令是把寄存器EDI中的數(shù)值放到EAX+70的地址中,可以肯定的是,EDI中的數(shù)值就是金錢。該地址的二進制指令從圖中可以看到,是:89 78 70。上圖紅圈處。為了簡單起見,我直接將二進制指令改成89 60 70,也就是把ESP中的數(shù)值放在EAX+70的地址中。肯定好多童鞋問為啥。說實話,就是我懶,因為這是個3字節(jié)的指令,如果我添加的指令長度超過3字節(jié),就會覆蓋程序正常的指令,導(dǎo)致游戲崩潰。如果實在想添加多于3字節(jié)的指令,大家可以去看看遠程代碼注入的知識,做起來比較復(fù)雜,100樓之內(nèi)也說不清。所以,為了省時間,我直接就修改成ESP了。又有童鞋問了,為啥是ESP?呵呵,其實EAX,EBP,ECX…..等等,都成。因為ESP數(shù)值肯定不會是0,所以錢肯定就不是0啊。我是偷懶。大家看我圖中,ESP的值是16進制的0018E554,換成10進制,大約是1631572這么多。好家伙,160多萬塊錢,夠了吧!
9.然后就是確定動態(tài)庫基址的問題,大家請看代碼:
HMODULE checkModuleAddr(DWORD id)
{
HMODULE addr = 0;
MODULEENTRY32 me32={0};
//在本進程中拍一個所有模塊的快照
HANDLE hModuleSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,id);
if(hModuleSnap==INVALID_HANDLE_VALUE)
return 0;
//遍歷快照中記錄模塊
me32.dwSize=sizeof(MODULEENTRY32);
//cout<<"模塊名稱及地址";
do
{
if(wcscmp(me32.szModule, modName) == 0)
{
addr = me32.hModule;
break;
}
}
while(::Module32Next(hModuleSnap,&me32));
CloseHandle(hModuleSnap);
return addr;
}
這段代碼就是獲得動態(tài)庫的代碼,得到動態(tài)地址后,加上剛才算的偏移(64B77),我們就能夠每次都算出目的地址啦,然后用WriteProcessMemory函數(shù)改寫成賦值ESP的二進制,就大功告成啦。如圖(注意左下角的金錢):