C語言實作植物大戰僵屍自動收集陽光(一) 問題分析與尋找基址
C語言實作植物大戰僵屍自動收集陽光(二) C語言控制台程式的實作
C語言實作植物大戰僵屍自動收集陽光(三) 解決收集不全與收集獎杯卡死的問題
前言
在上一篇,我已經在巧合下找到了實作自動收集的基位址
在本篇将着重講解如何用c語言控制台程式實作植物大戰僵屍的自動收集
前置内容
C語言實作植物大戰僵屍自動收集陽光(一) 問題分析與鎖定基址
C語言調用windows api : 簡單的說,直接
#include<window.h>
即可,更多請詳見百度
windows api讀記憶體與寫記憶體:WriteProcessMemory與ReadProcessMemory
BOOL ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead );
ReadProcessMemory
hProcess [in]遠端程序句柄。 被讀取者
pvAddressRemote [in]遠端程序中記憶體位址。 從具體何處讀取
pvBufferLocal [out]本地程序中記憶體位址. 函數将讀取的内容寫入此處
dwSize [in]要傳送的**位元組數。**要寫入多少
pdwNumBytesRead [out]實際傳送的位元組數. 函數傳回時報告實際寫入多少
BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten );
hProcess
由OpenProcess傳回的程序句柄。
如參數傳資料為 INVALID_HANDLE_VALUE 【即-1】目标程序為自身程序
lpBaseAddress
要寫的記憶體首位址
在寫入之前,此函數将先檢查目标位址是否可用,并能容納待寫入的資料。
lpBuffer
指向要寫的資料的指針。
nSize
要寫入的位元組數。
傳回值
非零值代表成功。
完整代碼
#include<stdio.h>
#include <Windows.h>
#include <string>
#include <pthread.h>
//通過視窗名擷取程序id
HANDLE GetProcessH(char windowName[]){
HWND hwnd=FindWindow(NULL,windowName);
DWORD processid;
GetWindowThreadProcessId(hwnd, &processid);
return OpenProcess(PROCESS_ALL_ACCESS,false,processid);
}
//讀程序記憶體
DWORD GetMemory(HANDLE processid,DWORD addr){
DWORD res;
LPCVOID pbase=(LPCVOID)addr;
LPVOID buffer=(LPVOID)&res;
ReadProcessMemory(processid,pbase,buffer,sizeof(DWORD),NULL);
return res;
}
//寫程序記憶體
int SetMemory(HANDLE processid,DWORD addr,DWORD value){
LPVOID pbase=(LPVOID)addr;
LPCVOID buffer=(LPCVOID)&value;
SIZE_T res;
return WriteProcessMemory(processid,pbase,buffer,sizeof(DWORD),&res);
}
//自動收集陽光
void AutomaticCollection(HANDLE processH){
DWORD addr=GetMemory(processH,0x006A9EC0);
addr=GetMemory(processH,addr+0x00000768);
addr=GetMemory(processH,addr+0xE4);
DWORD sun=addr+0x50;
if(GetMemory(processH,sun)==0)
SetMemory(processH,sun,1);
}
int main(int argc, char** argv) {
HANDLE processH=GetProcessH("植物大戰僵屍中文版");
while(1){
AutomaticCollection(processH);
Sleep(500);
}
}
關鍵代碼講解
使用 windows api 讀寫程序記憶體的流程大體如下:
- 使用FindWindow(),通過視窗名獲得視窗句柄
- 使用GetWindowThreadProcessId(),通過視窗句柄獲得程序ID
- 使用OpenProcess(),打開指定程序ID,獲得程序句柄
- 使用WriteProcessMemory()、ReadProcessMemory(),對程序進行讀寫
上述函數均為windows api,可查閱MSDN進行了解。
GetProcessH()函數
GetProcessH()函數對上述流程的1、2兩點進行封裝,輸入視窗名,即可獲得對應的程序句柄
HANDLE GetProcessH(char windowName[]){
HWND hwnd=FindWindow(NULL,windowName);
DWORD processid;
GetWindowThreadProcessId(hwnd, &processid);
return OpenProcess(PROCESS_ALL_ACCESS,false,processid);
}
讀寫記憶體程序函數
用兩個函數封裝了讀寫記憶體的過程,隻需要輸入程序句柄和對應位址即可。(參數名用processid其實描述的并不準确,此處應該用參數名processh)
//讀程序記憶體
DWORD GetMemory(HANDLE processid,DWORD addr){
DWORD res;
LPCVOID pbase=(LPCVOID)addr;
LPVOID buffer=(LPVOID)&res;
ReadProcessMemory(processid,pbase,buffer,sizeof(DWORD),NULL);
return res;
}
//寫程序記憶體
int SetMemory(HANDLE processid,DWORD addr,DWORD value){
LPVOID pbase=(LPVOID)addr;
LPCVOID buffer=(LPCVOID)&value;
SIZE_T res;
return WriteProcessMemory(processid,pbase,buffer,sizeof(DWORD),&res);
}
對收集狀态進行修改
我們在上一篇已經确定陽光的"收集狀态"的位址為:
[[[6A9EC0]+00000768]+E4]+50
,将該位址的内容鎖定為1時,陽光會被自動收集。
//自動收集陽光
void AutomaticCollection(HANDLE processH){
DWORD addr=GetMemory(processH,0x006A9EC0); // 即addr=[6A9EC0]
addr=GetMemory(processH,addr+0x00000768); // 即addr=[[6A9EC0]+00000768]
addr=GetMemory(processH,addr+0xE4); // 即addr=[[[6A9EC0]+00000768]+E4]
DWORD sun=addr+0x50; // 即sun=[[[6A9EC0]+00000768]+E4]+50
if(GetMemory(processH,sun)==0) // 如果該位址是0
SetMemory(processH,sun,1); // 就把它改為1
}
随後将上述代碼循環執行即可實作自動收集。
運作測試
C語言實作植物大戰僵屍自動收集陽光(二) C語言控制台程式的實作
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmL1kjM1QDNzQTM3EzNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
雖然現在已經實作自動收集了,但是在該系列的第一篇中也說了,目測的自動收集存在兩個問題
1.無差别收集會自動收集通關獎杯,使遊戲卡住
2.存在一寫陽光陽光沒被自動收集
針對這兩個問題的分析和解決方案我将在下一篇給出,敬請期待。