天天看點

C語言實作植物大戰僵屍自動收集陽光(二) C語言控制台程式的實作

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 讀寫程序記憶體的流程大體如下:

  1. 使用FindWindow(),通過視窗名獲得視窗句柄
  2. 使用GetWindowThreadProcessId(),通過視窗句柄獲得程序ID
  3. 使用OpenProcess(),打開指定程序ID,獲得程序句柄
  4. 使用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語言控制台程式的實作

雖然現在已經實作自動收集了,但是在該系列的第一篇中也說了,目測的自動收集存在兩個問題

1.無差别收集會自動收集通關獎杯,使遊戲卡住

2.存在一寫陽光陽光沒被自動收集

針對這兩個問題的分析和解決方案我将在下一篇給出,敬請期待。

繼續閱讀