2017年計(jì)算機(jī)等級(jí)考試二級(jí)C++輔導(dǎo):制作一個(gè)簡(jiǎn)單的游戲修改器

字號(hào):


    一、制作背景和原理:
    在平時(shí)玩游戲的過(guò)程中,大家肯定會(huì)接觸過(guò)形形色色的修改,特別是看到一些高手出的某某全能修,x項(xiàng)修改器,煞是羨慕,其實(shí)制作這樣寫一個(gè)這樣的修改器一點(diǎn)也不神秘,  好了,請(qǐng)各位看官一同隨我去揭開(kāi)修改器之謎......“修改器”程序的就是修改我們想要數(shù)據(jù)的地址里面的數(shù)值,這句話比較拗口,但是這是“修改器”程序的關(guān)鍵。下面就以時(shí)興的Normal tanks(坦克大戰(zhàn))為例,和大家討論怎樣去DIY一個(gè)游戲修改器請(qǐng)大家移步且隨我步驟慢慢來(lái)。
    二、找到我們想要的內(nèi)存地址:
    這是很關(guān)鍵的一步, 給大家介紹一款優(yōu)秀的內(nèi)存編輯工具)。
    在游戲中按熱Ctrl+Tab返回桌面,在Quick Memory Editor中點(diǎn)擊Add Task 。
    搜索炮彈的數(shù)量,當(dāng)前游戲中是50,在Search value中填入50,然后點(diǎn)擊Search,搜索速度很快,這會(huì)出來(lái)很結(jié)果,然后回到游戲里,隨便放幾炮,當(dāng)前炮彈數(shù)量變?yōu)榱?7,然后返回桌面,在Quick
    Memory Editor中的Search value中填入47,點(diǎn)擊Search, 這時(shí)候出來(lái)了幾個(gè)結(jié)果,結(jié)果還是不是很精確。返回游戲,再隨便放幾炮,當(dāng)前炮彈數(shù)量變成了43,再在Quick Memory
    Editor搜索43,這時(shí)候出來(lái)了僅一個(gè)結(jié)果,這就是我們需要的內(nèi)存地址了,記下來(lái)004C9C84,等會(huì)兒我們要用到。
    三、介紹兩個(gè)關(guān)鍵 API函數(shù)ReadProcessMemory()和 WriteProcessMemory():
    詳細(xì)的注釋我表明在函數(shù)里
    ①BOOL ReadProcessMemory(
    HANDLE hProcess, // 目標(biāo)進(jìn)程句柄
    LPCVOID lpBaseAddress, // 讀取數(shù)據(jù)的起始地址
    LPVOID lpBuffer, // 存放數(shù)據(jù)的緩存區(qū)地址
    DWORD nSize, // 要讀取的字節(jié)數(shù)
    LPDWORD lpNumberOfBytesRead ); // 實(shí)際讀取的數(shù)據(jù)大小地址
    ReadProcessMemory()用于讀取游戲進(jìn)程中制定的內(nèi)存數(shù)據(jù); 在實(shí)際操作中,我們用它來(lái)讀取存放炮彈數(shù)量地址中的數(shù)據(jù)。
    ②BOOL WriteProcessMemory(
    HANDLE hProcess, // 目標(biāo)進(jìn)程句柄
    LPVOID lpBaseAddress, // 進(jìn)程的起始地址
    LPVOID lpBuffer, // 數(shù)據(jù)內(nèi)容
    DWORD nSize, // 需要寫入的字節(jié)數(shù)
    LPDWORD lpNumberOfBytesWritten); // 實(shí)際寫入的數(shù)據(jù)大小的地址
    WriteProcessMemory()和上面的ReadProcessMemory()用法一樣,在實(shí)際操作中,我們用它來(lái)修改存放炮彈數(shù)量地址中的數(shù)據(jù)。
    四、編程實(shí)現(xiàn)游戲修改(完整代碼):
    #include 
    HINSTANCE g_hInst;
    HWND  g_hWnd;
    char szAppName[]="TankFix"; //The name of the exe
    char szTitle[]="坦克大戰(zhàn)修改";
    DWORD  addr=0x004C9C84;   //存放炮彈數(shù)量的內(nèi)存地址
    DWORD  pid;      //坦克大戰(zhàn)的PID
    int  val=1000;    //炮彈要修改的數(shù)量
    //-------------------------------------------------------------------------------------------------
    // WndProc- 窗口函數(shù)
    //-------------------------------------------------------------------------------------------------
    LRESULT CALLBACK WndProc(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
    {
    // int wmId,wmEvent;
    switch (message)
    {
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    case WM_TIMER:
    {
    HWND  hw=FindWindow(NULL,"Normal-tanks");  //FindWindow()得到坦克大戰(zhàn)程序的句柄
    HANDLE hProcess;    //定義坦克大戰(zhàn)的進(jìn)程句柄
    if (hw!=0)
    {
    SetForegroundWindow(hw);    //使我們的坦克大戰(zhàn)設(shè)置為當(dāng)前窗口
    GetWindowThreadProcessId(hw,&pid);    //得到游戲的PID號(hào)
    hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);    //打開(kāi)進(jìn)程PROCESS_ALL_ACCESS參數(shù),制定進(jìn)程可讀可寫
    WriteProcessMemory(hProcess,(LPVOID)addr,&val,4,0);    //向坦克大戰(zhàn)進(jìn)程內(nèi)存中寫入數(shù)據(jù)
    }
    else
    MessageBox(g_hWnd,"游戲還沒(méi)有運(yùn)行吧!","提示信息",MB_OK|MB_ICONINFORMATION);
    }
    default:
    return (DefWindowProc(hWnd,message,wParam,lParam));
    }
    return 0;
    }