第一次寫外掛就上手 - 使用Visual C++ 2010(二)
上一篇教了如何建立專案、建立檔案,並且實作了一個CRC數據功能。
本篇要教如何加入ICS數據功能,還沒有建立專案的請先照上一篇操作。
嵌入ASM數據需要使用內聯彙編(inline assembly),在Visual C++最基本的樣子如下:
void __declspec(naked) __stdcall 數據名稱() { __asm { } }
|
狀況一
我們拿v159.2 ICS 超級定怪
來示範,數據如下:
v159.2 ICS 超級定怪//Author: Onion [Enable] Alloc(HookEsp, 128)
HookEsp: Cmp [Esp], 00B32FAC Jne 00B32FCB Mov [Esp], 00B32FC3 Jmp 00B32FCB
00FCA738: DD HookEsp [Disable] 00FCA738: DD 00B32FCB DeAlloc(HookEsp)
|
我們要將數據改寫並且在FormMain.h
新增一個CheckBox
,比照上一篇的作法,然後加入程式碼到FormMain.cpp
:
FormMain.cppDWORD FreezeMobsAddress = 0x00FCA738; DWORD FreezeMobs_Disable = 0x00B32FCB; void __declspec(naked) __stdcall FreezeMobs() { __asm { Cmp dword ptr[Esp], 0x00B32FAC Jne FreezeMobsBack Mov dword ptr[Esp], 0x00B32FC3 FreezeMobsBack: Jmp FreezeMobs_Disable } }
DWORD FreezeMobs_Enable = (DWORD)FreezeMobs; void FormMain::checkBox2_CheckedChanged(System::Object^ sender, System::EventArgs^ e) { if (this->checkBox2->Checked) { memcpy((void *)FreezeMobsAddress, &FreezeMobs_Enable, sizeof(FreezeMobs_Enable)); } else { memcpy((void *)FreezeMobsAddress, &FreezeMobs_Disable, sizeof(FreezeMobs_Disable)); } }
|
請仔細觀察程式碼與數據之間的關聯,並試著加入其他功能測試。
注意dword ptr
與0x
狀況二
以v159.2 ICS 全職全圖打
示範,數據如下:
v159.2 ICS 全職全圖打[Enable] Registersymbol(SuperMapOnOff) Alloc(SuperMapOnOff, 4) Alloc(CheckESP, 256) Label(FullMapAttack)
SuperMapOnOff: DD 01
CheckESP: Cmp [SuperMapOnOff], 0 Je 0056D88A Cmp [Esp+124], 006A3489 Jne 0056D89C Mov [Esp+124], FullMapAttack Jmp 0056D89C
FullMapAttack: lea edi, [esi+00000728] push edi lea ecx, [esi+00000740] add Esp, 04 push esi mov esi, ecx mov eax, [011C7274] mov eax, [eax+94C8] push eax lea ecx, [esi+0c] call 0042C3F9 mov eax, [011C7274] mov eax, [eax+94CC] push eax mov ecx, esi call 0042C3F9 mov eax, esi pop esi Jmp 006A349B
00F282C8: DD CheckESP
[Disable] 00F282C8: DD 0056D89C DeAlloc(CheckESP)
|
程式碼如下:
DWORD FullMapAttack_OnOff = 0; DWORD FullMapAttack_Address = 0x00F282C8; DWORD FullMapAttack_Disable = 0x0056D89C; DWORD FullMapAttack_Call = 0x0042C3F9; DWORD FullMapAttack_Jmp = 0x006A349B; void __declspec(naked) FullMapAttack_Main() { __asm { lea edi,[esi+0x00000728] push edi lea ecx,[esi+0x00000740] add Esp, 0x04 push esi mov esi,ecx mov eax,[0x011C7274] mov eax,[eax+0x94C8] push eax lea ecx,[esi+0x0c] call FullMapAttack_Call mov eax,[0x011C7274] mov eax,[eax+0x94CC] push eax mov ecx,esi call FullMapAttack_Call mov eax,esi pop esi Jmp FullMapAttack_Jmp } } DWORD FullMapAttack_Main_Address = (DWORD)FullMapAttack_Main; void __declspec(naked) FullMapAttack() { __asm { Cmp dword ptr[FullMapAttack_OnOff], 0 Je FullMapAttackBack Cmp dword ptr[Esp+0x124], 0x006A3489 Jne FullMapAttackBack Push FullMapAttack_Main_Address Pop dword ptr[Esp+0x124] FullMapAttackBack: Jmp FullMapAttack_Disable } } DWORD FullMapAttack_Enable = (DWORD)FullMapAttack;
|
由於加上了開關FullMapAttack_OnOff
,我們可以改用更方便的寫法來寫開關。
先把HOOK程式碼移出來放到一個獨立的函數(function):
void InjectScript() { memcpy((void *)FullMapAttack_Address, &FullMapAttack_Enable, sizeof(FullMapAttack_Enable)); }
|
接著開關處可以直接這樣改:
FormMain.cppvoid FormMain::checkBox3_CheckedChanged(System::Object^ sender, System::EventArgs^ e) { if (this->checkBox3->Checked) { FullMapAttack_OnOff = 1; } else { FullMapAttack_OnOff = 0; } }
|
但要記得在Main()
中呼叫(call)InjectScript()
才會寫入數據。
在第三行先宣告(declare)函數原型(prototype),往後的程式碼才能呼叫InjectScript()
而不會產生編譯錯誤(compilation error)。
FormMain.cppvoid InjectScript();
void Main(void) { InjectScript(); }
|
進階:在寫入開關值時,也能直接將dynamic_cast<CheckBox ^>(sender)->Checked
賦值(assign)給變數(variable),程式碼將更為簡潔。
###警告:由於遊戲有記憶體保護,部分功能可能需在PLAY畫面打勾才有效,在遊戲內打勾可能造成沒有回應且會造成遊戲不正常結束,部分電腦在遊戲不正常結束後會有當機情形;關閉遊戲按鈕亦同,在部分電腦會有當機問題。以上問題均出自於遊戲本身,由於本程式只供學習之用,當機造成的風險請自行承擔,往後的教學會提到如何避免發生上述問題。
未完待續。
#第 1 2 3 頁