over 4 years ago

上一篇教了如何建立專案、建立檔案,並且實作了一個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.cpp
DWORD 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 ptr0x

狀況二

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.cpp
void FormMain::checkBox3_CheckedChanged(System::Object^  sender, System::EventArgs^  e)
{
    if (this->checkBox3->Checked)
    {
        // memcpy((void *)FullMapAttack_Address, &FullMapAttack_Enable, sizeof(FullMapAttack_Enable));
        FullMapAttack_OnOff = 1;
    }
    else
    {
        // memcpy((void *)FullMapAttack_Address, &FullMapAttack_Disable, sizeof(FullMapAttack_Disable));
        FullMapAttack_OnOff = 0;
    }
}

但要記得在Main()中呼叫(call)InjectScript()才會寫入數據。
在第三行先宣告(declare)函數原型(prototype),往後的程式碼才能呼叫InjectScript()而不會產生編譯錯誤(compilation error)。

FormMain.cpp
void InjectScript();
/* 略 */
void Main(void)
{
    InjectScript();
    /* 略 */
}

進階:在寫入開關值時,也能直接將dynamic_cast<CheckBox ^>(sender)->Checked賦值(assign)給變數(variable),程式碼將更為簡潔。

警告:由於遊戲有記憶體保護,部分功能可能需在PLAY畫面打勾才有效,在遊戲內打勾可能造成沒有回應且會造成遊戲不正常結束,部分電腦在遊戲不正常結束後會有當機情形;關閉遊戲按鈕亦同,在部分電腦會有當機問題。以上問題均出自於遊戲本身,由於本程式只供學習之用,當機造成的風險請自行承擔,往後的教學會提到如何避免發生上述問題。

未完待續。

1 2 3

← 第一次寫外掛就上手 - 使用Visual C++ 2010(一) TobyHack v169.1 →
 
comments powered by Disqus