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

字號:


    一、制作背景和原理:
    在平時玩游戲的過程中,大家肯定會接觸過形形色色的修改,特別是看到一些高手出的某某全能修,x項修改器,煞是羨慕,其實制作這樣寫一個這樣的修改器一點也不神秘,  好了,請各位看官一同隨我去揭開修改器之謎......“修改器”程序的就是修改我們想要數(shù)據(jù)的地址里面的數(shù)值,這句話比較拗口,但是這是“修改器”程序的關(guān)鍵。下面就以時興的Normal tanks(坦克大戰(zhàn))為例,和大家討論怎樣去DIY一個游戲修改器請大家移步且隨我步驟慢慢來。
    二、找到我們想要的內(nèi)存地址:
    這是很關(guān)鍵的一步, 給大家介紹一款優(yōu)秀的內(nèi)存編輯工具)。
    在游戲中按熱Ctrl+Tab返回桌面,在Quick Memory Editor中點擊Add Task 。
    搜索炮彈的數(shù)量,當(dāng)前游戲中是50,在Search value中填入50,然后點擊Search,搜索速度很快,這會出來很結(jié)果,然后回到游戲里,隨便放幾炮,當(dāng)前炮彈數(shù)量變?yōu)榱?7,然后返回桌面,在Quick
    Memory Editor中的Search value中填入47,點擊Search, 這時候出來了幾個結(jié)果,結(jié)果還是不是很精確。返回游戲,再隨便放幾炮,當(dāng)前炮彈數(shù)量變成了43,再在Quick Memory
    Editor搜索43,這時候出來了僅一個結(jié)果,這就是我們需要的內(nèi)存地址了,記下來004C9C84,等會兒我們要用到。
    三、介紹兩個關(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ù)據(jù)大小地址
    ReadProcessMemory()用于讀取游戲進(jìn)程中制定的內(nèi)存數(shù)據(jù); 在實際操作中,我們用它來讀取存放炮彈數(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ù)據(jù)大小的地址
    WriteProcessMemory()和上面的ReadProcessMemory()用法一樣,在實際操作中,我們用它來修改存放炮彈數(shù)量地址中的數(shù)據(jù)。
    四、編程實現(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號
    hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);    //打開進(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,"游戲還沒有運行吧!","提示信息",MB_OK|MB_ICONINFORMATION);
    }
    default:
    return (DefWindowProc(hWnd,message,wParam,lParam));
    }
    return 0;
    }