植物大戰僵屍:代碼實現自動收集陽光


本次實驗內容:通過陽光增加的值為切入點,找到自動收集陽光的關鍵判斷並實現自動收集陽光,首先我們猜測當陽光出現后,我們是否會去點擊,這個過程必然是由一個判斷和一個時鍾周期事件來控制的,那么當我們點擊下落的陽光以后,則該判斷條件實現,會執行收集陽光的CALL,否則的話繼續執行陽光下落的過場動畫,這正是正向開發的一種開發手段,此時我們也僅僅是猜測,接下來我們將去驗證這個大膽的想法。

為了找到陽光自動收集的關鍵跳轉,我們需要以陽光增加作為切入點,為啥以它作為切入點呢?我們可以這樣思考,當我們點擊陽光后陽光增加了,說明已經完成了判斷,下一步就是寫入變量從而增加陽光,那么我們先來找到陽光的動態地址,並在該動態地址上按下F6鍵查找寫入,然后回到游戲等待陽光出現並點擊陽光,此時CE會出現以下代碼,我們只需要記下00430A11這個內存地址,然后直接關閉CE。

接着打開X64dbg附加到游戲進程,附加完成后,游戲會被X64dbg暫停運行,此時我們直接按下F12讓游戲運行起來,然后按下Ctrl + G輸入00430A11跳轉到剛才找到的代碼位置,過去以后直接F2下一個斷點。

此時我們需要逆向思考一個問題add dword ptr ds:[eax+0x5560],ecx這條指令是在我們陽光被點擊后執行的,也就是說我們已經點擊了陽光現在開始賦值了,那判斷陽光是否被回收肯定是在這條指令之前出現,所以我們向上找,觀察代碼我們不難看出執行add dword ptr ds:[eax+0x5560],ecx指令之前有一個無條件跳轉jmp 0x00430A0E跳過來的。

繼續向上查找跳轉來源,可知在jmp跳轉之前有一個je 0x004309EF跳轉,經過測試這個地方具體控制陽光是否增加,在向上找就到段首了,此處代碼中並沒有出現自動收集陽光的關鍵跳轉,因此推斷這里應該是一個控制陽光是否增加的子過程(子過程:過程中調用的過程,稱為子過程),所以我們繼續回朔到上一層。

為了能夠回朔到上一層,我們需要取消陽光遞增處的斷點,並在段尾00430AB3處下一個F2斷點防止程序跑飛,回到游戲等待陽光的出現,然后X64dbg就會斷下,斷下后直接取消00430AB3處的斷點,執行到Ret處即可返回到上一層。

返回到上一層以后,可以看到我們正是在call <plantsvszombies.sub_4309D0> 這里出來的,而上方就有一個jne plantsvszombies.4313FD關鍵跳,此處的關鍵跳轉也並不是控制是否回收陽光的關鍵跳轉,而此處的代碼量比較少,因此判斷此處還是一個子過程,我們繼續回溯到上一層。

我們直接單步F8運行到返回,並出這個CALL,出CALL以后會看到call <plantsvszombies.sub_430E40>沒錯!我們正是從這個子過程里出來的,接着向上找跳轉會看到有一個jne plantsvszombies.431599此處如果將其改為jmp的話即可實現自動收集陽光,也就是說如果jne跳轉實現則執行收集陽光,否則繼續執行陽光下落的過場動畫。

注意:如果我們在關鍵跳jne plantsvszombies.4313FD處下斷點時,會發現當陽光出現后程序會被無限的斷下,這說明是有一個定時器線程在不斷的執行判斷代碼,每次都會判斷你是否點擊了陽光,所以X64dbg才會被一直斷下。

知道了修改流程,那我們就通過編程的方式來實現修改程序的硬編碼,首先我們可以通過以下代碼完成字節集的讀取。

#include <stdio.h>
#include <Windows.h>

byte *ReadByteSet(DWORD Pid, DWORD Base, DWORD Size)
{
  HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, 0, Pid);
  byte *buf = new byte[Size];
  ReadProcessMemory(handle, (LPVOID)Base, buf, Size, NULL);
  return buf;
}

int main()
{
  	byte *Buff = new byte[10];
  	Buff = ReadByteSet(2232, 0x00401000, 10);
  	for (int i = 0; i < 10; i++)
  		printf("%02X ", Buff[i]);
  return 0;
}

既然有讀取內存字節集,那么就有寫入字節集,如下代碼就是一種字節集寫入的實現方式。

#include <stdio.h>
#include <Windows.h>

BOOL WriteByteSet(DWORD Pid, DWORD Base, unsigned char *ShellCode, DWORD Size)
{
  BYTE *Buff = new BYTE[Size];
  memset(Buff, *ShellCode, Size);
  HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, 0, Pid);
  BOOL Ret = WriteProcessMemory(handle, (LPVOID)Base, Buff, Size, NULL);
  if (Ret)
  	return TRUE;
  else
  	return FALSE;
}

int main()
{
  unsigned char shell[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
  BOOL temp = WriteByteSet(3772, 0x00401010, shell, 8);
  return 0;
}

想要實現陽光自動收集,只需要將0x0043158F機器碼0x75 0x08修改為0xEB 0x08即可實現效果。

  unsigned char shell[] = { 0xEB };
  BOOL temp = WriteByteSet(9744, 0x0043158F, shell, 1);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM