C语言实现植物大战僵尸自动收集阳光(一) 问题分析与寻找基址
C语言实现植物大战僵尸自动收集阳光(二) C语言控制台程序的实现
C语言实现植物大战僵尸自动收集阳光(三) 解决收集不全与收集奖杯卡死的问题
在上一篇,我已经在巧合下找到了实现自动收集的基地址
在本篇将着重讲解如何用c语言控制台程序实现植物大战僵尸的自动收集
C语言实现植物大战僵尸自动收集阳光(一) 问题分析与锁定基址
C语言调用windows api : 简单的说,直接#include
即可,更多请详见百度
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
#include
#include
#include
//通过窗口名获取进程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,可查阅MSDN进行了解。
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
}
随后将上述代码循环执行即可实现自动收集。
虽然现在已经实现自动收集了,但是在该系列的第一篇中也说了,目测的自动收集存在两个问题
1.无差别收集会自动收集通关奖杯,使游戏卡住
2.存在一写阳光阳光没被自动收集
针对这两个问题的分析和解决方案我将在下一篇给出,敬请期待。