轉載:從遊戲中得到動態記憶體資料(彙編+VC 例子:瘋狂坦克的X座標) (4千字)

看雪資料發表於2002-11-15

sbsummer(原作)

各位朋友大家好,嗷嗷,我第一次在這裡發文章,好高興
本人技術有限,不要笑話,如有錯誤請您告訴我一聲[em09]。

剛才我玩了幾把瘋狂坦克,輸了好幾盤,覺得無聊就搞搞這個,下面開始說說如何得到遊戲中的動態資料(

地址改變),以得到瘋狂坦克中坦克X座標為例

------------------------------------------------------------------------------
工具:
SoftICE動態除錯程式,遊戲修改工具(金山遊俠),反彙編(W32Dasm),Hex Workshop
------------------------------------------------------------------------------

一、找到記憶體中坦克X座標

  1、用金山遊俠搜尋,方法如下(金山遊俠的使用我就不說了)
      把坦克往左移動一些,就搜尋“減少”;坦克往右移動,就搜尋“增大”
      反覆搜尋將會找到一個地址(當然其他遊戲可能不止一個),這裡是08BFAACC
      注:動態的記憶體分配就是下次你如果再次搜尋,地址將不再是08BFAACC

  2、找到那條程式碼修改了這個資料(X座標)
      載入 SoftIce
      在遊戲狀態 Ctrl+D 調出SoftIce,輸入 BPM 08BFAACC W,這裡的W表示如果這個地址被寫將中斷
      回到遊戲,移動坦克,左移一下,程式中斷,SoftIce指向的上面一句是
      004640B3 MOV DWORD PTR [ESI+000001A4],EAX
      這句就是修改坦克座標的程式碼,當然右移也能找到一句,這裡就不重複了

  3、修改程式使動態的資料變成靜態
      這裡說點題外話,修改程式包括兩種,一種是直接修改程式,一種是修改記憶體中的程式(記憶體補丁)

,這裡由於我懶,所以用了第一種
      修改程式:
          瘋狂坦克程式存在Fortress2.dat當中,如果你把這個檔案改名為EXE檔案一樣可以執行,這裡我

們就把他修改成Fortress2.exe
          開啟W32Dasm反彙編,SHIFT+F12跳到004046B3,你看到這幾行

      004046B3 8986A4010000    MOV DWORD PTR [ESI+000001A4],EAX
      004046B9 8B8644020000    MOV EAX,DWORD PTR [ESI+00000244]
      004046BF C744241001000000 MOV [ESP+10],00000001

          剛才我們說了004046B3是修改X座標的那條語句,現在我們要讓他每次修改完程式就能夠把X座標

儲存到一個固定的地址
          現在要讓它執行到這裡就JMP到一個我們自己的程式碼的地方,於是在程式的尾部我們找到一段空

白的區域00465A52,於是我修改004046BF為程式碼 JMP 00465A52,機器碼為E98E130600,因為這句的長度不夠以前的那句長,所以要加入幾個NOP,機器碼為90,所以我們開啟HEX Workshop修改程式,CTRL+G跳到位移為000046BF的地方,看到了C744241001000000,我們把它修改為E98E130600909090,現在程式將一執行到這裡就跳到00465A52執行我們的程式碼。

    4、實現我們自己的程式碼,然後跳回
          我們的程式碼要做的是把動態變成靜態,
          PUSH EAX
          MOV EAX,[ESI+000001A4]
          MOV [00470000],EAX
          POP EAX
          JMP 004046C7
          這樣這個數值無論執行多少次,只要你移動(當然右移也要修改)就能在00470000中找到X座標

,這段機器碼為50 8B86A4010000 A300004700 58 E95BECF9FF

          忘了說剛才我們把004046BF替換掉的那句MOV [ESP+10],00000001也必須加上,所以開啟HEX

Workshop,CTRL+G跳到00465A52,修改加入
          C744241001000000 50 8B86A4010000 A300004700 58 E95BECF9FF
          這樣動態資料就變成了靜態
------------------------------------------------------------------------------

現在回顧一下
          .首先搜尋座標地址
          .找到改變這個地址的程式碼
          .修改程式碼讓他跳到自己的程式碼中執行
          .在程式的空白段加入自己的程式碼,當然要補上被替換了的那句,還有修改了暫存器,必須先

PUSH,再POP

          下面的工作就是寫一個程式讀取這個地址了,我用VC寫了一個,順便貼一下關鍵程式碼
------------------------------------------------------------------------------
         
CProcess m_process;
bool m_ret = m_process.FindProcess("FortressII");
if (m_ret)
{
  BYTE tank1xL = m_process.ReadByte(0x00470000);
  BYTE tank1xR = m_process.ReadByte(0x00470001);
  WORD tank1x = tank1xL+tank1xR*256;
  temp = tank1x;
  str.Format("%d",temp);
  m_tank1x=str;
  UpdateData(FALSE);
  return TRUE;
}
else return FALSE;
-----------------------------------------------------------------------------
CProcess是一個我編寫的修改類,這裡用到的函式程式碼如下
HANDLE CProcess::OpenProcess(char *p_ClassName, char *p_WindowTitle)
{
HWND hWindow;
DWORD pid;

hWindow = FindWindow(p_ClassName, p_WindowTitle);
if (hWindow) {
    GetWindowThreadProcessId(hWindow, &pid);
    return ::OpenProcess(PROCESS_ALL_ACCESS, false, pid);
}
return NULL;
}

bool CProcess::FindProcess(char *p_WindowTitle)
{
if (m_hProcess == NULL) {
    m_hProcess = this->OpenProcess(NULL, p_WindowTitle);
if (m_hProcess)
    m_bGameRunning = true;
return m_bGameRunning;
}
else
    return false;
}

BYTE CProcess::ReadByte(DWORD p_Address)
{
DWORD bytes;
BYTE tmpValue;

if (m_bGameRunning) {
    if (ReadProcessMemory(m_hProcess, (void*)p_Address,
        (void *)&tmpValue, 1, &bytes) == 0)
    return 0;
    else
        return tmpValue;
}
return 0;
}

相關文章