植物大战僵尸C语言修改器

PvZ_modifier

一个自己研究了一段时间写的C语言修改器,代码规范严谨,但仍有不足,希望有能力的人和我一同研究。使用的ide是devcpp

本修改器也在github上开源,地址为:https://github.com/Liushui-Miaomiao/PvZ_modifier.git.

文件主体内容

一共5个.c源文件,一个.h头文件
c源文件名为:PvZ_modifier.c,g_op.c,g_msg.c,p_op.c,pm_op.c
h头文件名为:headgr.h

功能

修改器一览

第二页

修改效果

效果

全代码展示

PvZ_modifier.c

#include "headgr.h"

DWORD Pid;
HANDLE hProcess=0;
int command;

BOOL isRun=FALSE;
BOOL backStageRun=FALSE;
BOOL anyPosition=FALSE;
BOOL isLittle=FALSE; 

/*主函数*/
int main(void){
	initModifier();
	
	while(TRUE){
		menu();
		setColor(14);
		
		printf("\n请按下按键选择选项:");
		command=getchar();
		Choice();
	}
	
	return 0;
}

g_op.c

/*Game Operation*/

#include "headgr.h"

extern DWORD Pid;
extern HANDLE hProcess;
extern int command;

extern BOOL isRun;
extern BOOL backStageRun;
extern BOOL anyPosition;
extern BOOL isLittle; 

/*初始化修改器*/
void initModifier(void){
	SetConsoleTitle("【植物大战僵尸】 C语言修改器 v0.22");
	isRun=openGameProcess();
}

/*打开游戏进程*/
BOOL openGameProcess(void){
	setColor(14);
	printf("正在打开进程...\n");
	
	//寻找进程名称并返回pid
	if(FindProcessPid(PROCESS_NAME,Pid)){
		showProcessName("[","]");
		printf("[Pid:%d]\n",Pid);
		
		hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,Pid);
		
		if (hProcess!=0){
			setColor(10);
			showProcessName("\n成功打开游戏进程[","]!");
			printf("进程句柄:%d\n",hProcess);
			
			if(readMemory(hProcess,0x42748E,0,4)==0xFF563DE8){
				if(readMemory(hProcess,0x0054EBEF,0,1)==0xFF563DC3){
					backStageRun=TRUE;
				}
				if(readMemory(hProcess,0x0040FE30,0,1)==0xFF563D81&&readMemory(hProcess,0x00438E40,0,1)==0xFF563DEB&&readMemory(hProcess,0x0042A2D9,0,1)==0xFF563D8D){
					anyPosition=TRUE;
				}
				if(readMemory(hProcess,0x00523ED5,0,1)==0xFF563DEB){
					isLittle=TRUE;
				}
				
				return TRUE;
			}else{
				setColor(14);
				printf("\n不支持的游戏版本!\n");
				return FALSE;
			}
		}else{
			setColor(12);
			showProcessName("\n打开游戏进程[","]失败!\n");
		}
	}else{
		setColor(14);
		showProcessName("未找到游戏进程:","\n");
	}
	
	return FALSE;
}

/*是否已经读取游戏进程*/
BOOL openModify(void){
	if(hProcess==0){
		setColor(14);
		printf("\n请先打开修改器搜索游戏句柄!\n");
		return FALSE;
	}
	
	return TRUE;
}

/*选择流程*/
void Choice(void){
	//缓冲区
	int _tempValue;
	
	setColor(13);
	//根据字符判断应该执行什么流程
	switch(command){
		case 'O':
			isRun=openGameProcess();
			
			pause();
			break;
		#if DEBUG
			case 'T':
				if(openModify()){
					
				}
				break;
		#endif
		
		/*常规修改*/
		case 'a':
			if(!openModify()){
				pause();
				break;
			}
			
			getchar();
			setColor(14);
			printf("\n已进入【常规修改】菜单,请选择子选项:");
			command=getchar();
			setColor(13);
			switch(command){
				case '1':
					if(openModify()){
						printf("\n请输入要修改的阳光数量:");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,0,9990);
						cheatMsg(writeMemory(hProcess,0x006A9EC0,2,_tempValue,4,0x768,0x5560),"阳光");
					}
					break;
				case '2':
					if(openModify()){
						printf("\n请输入要修改的金钱数量:");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,0,99999);
						cheatMsg(writeMemory(hProcess,0x006A9EC0,2,_tempValue,4,0x82C,0x28),"金钱");
					}
					break;
				case '3':
					if(openModify())cheatMsg(writeMemory(hProcess,0x00487296,0,0x1477,2),"卡牌无冷却");
					break;
				case '4':
					if(openModify()){
						if(!backStageRun){
							cheatMsg(writeMemory(hProcess,0x0054EBEF,0,0xC3,1),"取消后台");
						}else{
							cheatMsg(writeMemory(hProcess,0x0054EBEF,0,0x57,1),"恢复后台");
						}
						backStageRun=!backStageRun;
					}
					break;
				case '5':
					if(openModify()){
						printf("\n请输入要修改的卡槽格数(1~10):");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,1,10);
						cheatMsg(writeMemory(hProcess,0x006A9EC0,3,_tempValue,4,0x768,0x144,0x24),"卡槽格数");
					}
					break;
				case '6':
					if(openModify())cheatMsg(writeMemory(hProcess,0x0043158F,0,0xEB,1),"自动收集开启");
					break;
				default :
					noOperation();
			}
			break;
		
		/*关卡修改*/
		case 'b':
			if(!openModify()){
				pause();
				break;
			}
			
			getchar();
			setColor(14);
			printf("\n已进入【关卡修改】菜单,请选择子选项:");
			command=getchar();
			setColor(13);
			switch(command){
				case '1':
					if(openModify()){
						printf("\n请输入要修改的冒险关卡(例如我要去4-3关卡,那么应该输入43):");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,11,99);
						_tempValue-=10;
						cheatMsg(writeMemory(hProcess,0x006A9EC0,2,_tempValue,4,0x82C,0x24),"冒险模式关卡");
					}
					break;
				case '2':
					if(openModify()){
						printf("\n需要先进入任意关卡然后点击菜单后(一定要这么做,否则会崩溃或者修改无效,此外重新开始会清除该模式下的存档,请注意备份存档),");
						printf("修改关卡代码然后点击重新开始,如果不重新开始的话将会产生混乱关卡的效果\n");
						printf("请输入要进入的迷你游戏ID(ID可通过查询【!】菜单的关卡代码(1~70)):");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,1,70);
						cheatMsg(writeMemory(hProcess,0x006A9EC0,1,_tempValue,4,0x7F8),"小游戏跳关");
					}
					break;
				default :
					noOperation();
			}
			break;
		
		/*植物修改*/
		case 'c':
			if(!openModify()){
				pause();
				break;
			}
			
			getchar();
			setColor(14);
			printf("\n已进入【植物修改】菜单,请选择子选项:");
			command=getchar();
			setColor(13);
			switch(command){
				case '1':
					if(openModify()){
						if(!anyPosition){
							cheatMsg(writeMemory(hProcess,0x0040FE30,0,0x81,1)&&writeMemory(hProcess,0x00438E40,0,0xEB,1)&&writeMemory(hProcess,0x0042A2D9,0,0x8D,1),"开启重叠放置");
						}else{
							cheatMsg(writeMemory(hProcess,0x0040FE30,0,0x84,1)&&writeMemory(hProcess,0x00438E40,0,0x74,1)&&writeMemory(hProcess,0x0042A2D9,0,0x84,1),"取消重叠放置");
						}
						anyPosition=!anyPosition;
					}
					break;
				case '2':
					if(openModify())cheatMsg(writeMemory(hProcess,0x0041D7D0,0,0xC301B0,3)&&writeMemory(hProcess,0x0040E477,0,0xEB,1),"紫卡种植无限制");
					break;
				default :
					noOperation();
			}
			break;
		
		/*僵尸修改*/
		case 'd':
			if(!openModify()){
				pause();
				break;
			}
			
			getchar();
			setColor(14);
			printf("\n已进入【僵尸修改】菜单,请选择子选项:");
			command=getchar();
			setColor(13);
			switch(command){
				case '1':
					if(openModify()){
						int i;
						BOOL kill=FALSE;
						printf("僵尸数量:%d\n",readMemory(hProcess,0x006A9EC0,2,4,0x768,0xA0));
						/*pvz最多有1024只僵尸*/
						for(i=0;i<1024;i++){
							if(readMemory(hProcess,0x006A9EC0,3,4,0x768,0x90,i*0x15C+0xEC)==0){
								kill=writeMemory(hProcess,0x006A9EC0,3,3,4,0x768,0x90,i*0x15C+0x28);
							}
						}
						cheatMsg(kill,"秒杀全部僵尸");
					}
					break;
				case '2':
					if(openModify()){
						if(!isLittle){
							cheatMsg(writeMemory(hProcess,0x00523ED5,0,0xEB,1),"开启小僵尸特效");
						}else{
							cheatMsg(writeMemory(hProcess,0x00523ED5,0,0x74,1),"关闭小僵尸特效");
						}
						isLittle=!isLittle;
					}
					break;
				default :
					noOperation();
			}
			break;
		
		/*花园修改*/
		case 'e':
			if(!openModify()){
				pause();
				break;
			}
			
			getchar();
			setColor(14);
			printf("\n已进入【花园修改】菜单,请选择子选项:");
			command=getchar();
			setColor(13);
			switch(command){
				case '1':
					if(openModify()){
						printf("\n请输入要修改的智慧树高度:");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,0,2147483647);
						cheatMsg(writeMemory(hProcess,0x006A9EC0,2,_tempValue,4,0x82C,0xF4),"智慧树高度");
					}
					break;
				case '2':
					if(openModify()){
						printf("\n请输入要修改的巧克力数量:");
						scanf("%d",&_tempValue);
						_tempValue=limit(_tempValue,0,999);
						_tempValue+=1000;
						cheatMsg(writeMemory(hProcess,0x006A9EC0,2,_tempValue,4,0x82C,0x228),"巧克力数量");
					}
					break;
				default :
					noOperation();
			}
			break;
		
		/*其他修改*/
		case 'f':
			if(!openModify()){
				pause();
				break;
			}
			
			getchar();
			setColor(14);
			printf("\n已进入【其他修改】菜单,请选择子选项:");
			command=getchar();
			setColor(13);
			switch(command){
				case '1':
					if(openModify())cheatMsg(writeMemory(hProcess,0x0044E5CC,0,0x0033B866,4),"花瓶透视开启");
					break;
				case '2':
					if(openModify())cheatMsg(writeMemory(hProcess,0x0042DF5D,0,0x38,1),"显示隐藏小游戏");
					break;
				default :
					noOperation();
			}
			break;
		//~
		case '\x7E':
			upData();
			break;
		//!
		case '\x21':
			showMiniGameList();
			break;
		//@
		case '\x40':
			cheatCode();
			break;
		//#
		case '\x23':
			showOpenCheat();
			break;
		case 'A':
			about();
			break;
		case 'E':
			close();
			break;
		default :
			noOperation();
	}
	
	//暂缓输入
	getchar();
}

/*规范数据范围*/
int limit(int value,int min,int max){
	if(value<min)return min;
	if(value>max)return max;
	
	return value;
}

g_msg.c

/*Game Message*/

#include "headgr.h"

extern BOOL isRun;
extern BOOL backStageRun;
extern BOOL anyPosition;
extern BOOL isLittle; 

/*主菜单*/
void menu(void){
	setColor(15);
	printf("\n————————————————————\n");
	printf("【植物大战僵尸】 C语言修改器\n\n");
	printf("O:重新打开/搜索进程\n");
	if(isRun){
		#if DEBUG
			printf("T:测试代码(Debug)\n");
		#endif
		printf("\na:常规修改:\n");
		printf("1:修改阳光\n");
		printf("2:修改金钱\n");
		printf("3:卡牌全部无冷却时间\n");
		printf("4:允许后台运行(再开一次取消)\n");
		printf("5:修改卡槽格数\n");
		printf("6:自动收集资源\n");

		printf("\nb:关卡修改:\n");
		printf("1:冒险模式跳关\n");
		printf("2:小游戏跳关(混乱关卡)\n");

		printf("\nc:植物修改:\n");
		printf("1:激活重叠放置(再开一次取消)\n");
		printf("2:紫卡种植无限制\n");

		printf("\nd:僵尸修改:\n");
		printf("1:秒杀场上所有僵尸\n");
		printf("2:小僵尸特效(再开一次恢复正常大小)\n");

		printf("\ne:花园修改:\n");
		printf("1:修改智慧树高度\n");
		printf("2:巧克力数量修改\n");

		printf("\nf:其他修改:\n");
		printf("1:花瓶透视\n");
		printf("2:显示隐藏小游戏\n");
	}
	printf("\n特殊功能:\n");
	printf("~:查看修改器更新公告\n");
	printf("!:查看迷你小游戏、解密模式、生存模式关卡代码\n");
	printf("@:查看PVZ小代码(彩蛋)大全\n");
	printf("#:查看目前已经开启的效果\n");
	printf("A:关于本修改器信息\n");
	printf("\nE:退出修改器");
	printf("\n————————————————————\n");
}

/*更新信息*/
void upData(void){
	setColor(9);
	printf("\n更新公告\n\n");
	printf("v0.1 [2019.03.04] 增加了最初的十个功能(1~0)\n");
	
	printf("v0.2 [2019.03.13] 新增以下功能:\n");
	printf("\t(1)自动收集资源\n\t(2)显示隐藏小游戏\n\t(3)重叠放置\n\t(4)巧克力修改\n\t(5)小僵尸特效\n\t(6)紫卡种植无限制\n");
	printf("修复/增强了以下功能:\n");
	printf("\t(1)花瓶透视不稳定性修复\n\t(2)秒杀僵尸不稳定性修复\n");
	
	printf("v0.21 [2019.07.28] 优化内存读写操作\n");
	
	printf("v0.22 [2019.09.16] 优化文件结构\n");
	
	pause();
}

/*小代码*/
void cheatCode(void){
	setColor(5);
	printf("\nPVZ小代码大全(培养智慧树到一定高度智慧树会告诉你的)\n\n");
	printf("future ------ 僵尸戴上时尚太阳眼镜\n");
	printf("mustache ---- 僵尸戴上两撇胡子\n");
	printf("trickedout -- 剪草机统一变成机车剪草机\n");
	printf("daisies ----- 当僵尸被杀后掉下一些雏菊(需要智慧树达到100米)\n");
	printf("dance ------- 让僵尸摆动身体跳舞(动次打次 动次打次)(需要智慧树达到500米)\n");
	printf("sukhbir ----- 切换僵尸呼唤大脑时的叫声φ(>ω<*) \n");
	printf("pinata ------ 僵尸死后散落一地的糖果(需要智慧树达到1000米)\n");
	
	pause();
}

/*显示迷你游戏列表*/
void showMiniGameList(void){
	setColor(11);
	
	printf("\n小游戏代码(红色加“*”标志的关卡不能跳关/混乱,会造成崩溃退出)\n\n");
	const char *MiniGame[]={"生存模式:白天","生存模式:黑夜","生存模式:泳池","生存模式:浓雾","生存模式:屋顶",
							"生存模式:白天(困难)","生存模式:黑夜(困难)","生存模式:泳池(困难)","生存模式:浓雾(困难)","生存模式:屋顶(困难)",
							"生存模式:白天(无尽)","生存模式:黑夜(无尽)","生存模式:泳池(无尽)","生存模式:浓雾(无尽)","生存模式:屋顶(无尽)",
							"植物僵尸","坚果保龄球模式","老虎机","雨中种植物","宝石迷阵",
							"隐形食脑者","看星星","僵尸水族馆","宝石迷阵转转看","小僵尸大麻烦",
							"保护传送门","你看,他们像柱子一样","雪橇区","僵尸快跑","锤僵尸",
							"谁笑到最后","植物僵尸2","坚果保龄球2","跳跳舞会","僵王博士的复仇",
							"坚果保龄球艺术锦标赛","晴天","无草皮之地(崩溃跳出,原因:少2道草皮)","重要时间","挑战种太阳花的艺术",
							"空袭","冰冻关卡","禅境花园(崩溃跳出)","超乎寻常的地心引力","坟墓模式",
							"你能把它挖出来吗","黑暗的暴风雨夜","蹦极闪电战","松鼠","智慧树(崩溃跳出)",
							"破罐者","全部留下","第三个罐子","连锁反应","M的意思是金属",
							"胆怯的制陶工","变戏法","另一个连锁反应","罐子王牌","无尽的试炼",
							"我是僵尸","我也是僵尸","你能铲了它么","完全傻了","死亡飞艇",
							"我烂了","僵尸摇摆","三连击","你的所有大脑都是属于我的","我是僵尸无尽版"
	};
	
	int i;
	int gameLength=sizeof(MiniGame)/sizeof(MiniGame[0]);
	for(i=0;i<gameLength;i++){
		if(i==37||i==42||i==49){
			setColor(12);
			printf("*");
		}else{
			setColor(11);
		}
		printf("%d.%s\n",i+1,MiniGame[i]);
	}
	
	pause();
}

/*暂停*/
void pause(void){
	setColor(14);
	printf("\n按任意键继续……\n");
	
	getch();
}

/*找不到操作*/
void noOperation(void){
	setColor(14);
	printf("\n找不到相关操作!请重新输入操作按键!\n");
	
	pause();
}

/*关于信息*/
void about(void){
	printf("\n关于:本程序是植物大战僵尸(Plants vs. Zombies)的修改器,使用【Dev-C++】开发编译");
	printf("\n修改器作者:流水“渺渺\n感谢大家的使用,有任何疑问和bug可以反馈给我\n\n");
	
	pause();
}

/*显示修改提示信息*/
void cheatMsg(BOOL isSuccess,const char msg[]){
	if(isSuccess){
		setColor(10);
		printf("\n修改【%s】成功!\n",msg);
	}else{
		setColor(12);
		printf("\n修改【%s】失败!\n",msg);
	}
	
	pause();
}

/*显示启动的修改项目*/
void showOpenCheat(void){
	setColor(11);
	printf("\n当前开启的修改项目\n\n");
	
	setColor(13);
	
	BOOL sign=FALSE;
	if(backStageRun){
		printf("取消后台功能已启用\n");
		sign=TRUE;
	}
	if(anyPosition){
		printf("重叠放置功能已启用\n");
		sign=TRUE;
	}
	if(isLittle){
		printf("小僵尸特效已启用\n");
		sign=TRUE;
	}
	
	if(!sign)printf("目前没有修改项目正在启动\n");
	
	pause();
}

/*显示进程名称*/
void showProcessName(const char msg1[],const char msg2[]){
	printf("%s",msg1);
	printf(PROCESS_NAME);
	printf("%s",msg2);
}
 

p_op.c

/*Process Operation*/

#include "headgr.h"

/*通过进程名返回pid*/
BOOL FindProcessPid(LPCSTR ProcessName,DWORD &dwPid){
	HANDLE hProcessSnap;
	PROCESSENTRY32 pe32;
	
	hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
	if(hProcessSnap==INVALID_HANDLE_VALUE){
		return FALSE;
	}
	
	pe32.dwSize=sizeof(PROCESSENTRY32);
	
	if(!Process32First(hProcessSnap,&pe32)){
		CloseHandle(hProcessSnap);
		return FALSE;
	}
	
	BOOL bRet=FALSE;
	do{
		if(strcmp(ProcessName,pe32.szExeFile)==0){
			dwPid=pe32.th32ProcessID;
			bRet=TRUE;
			break;
		}
	}while(Process32Next(hProcessSnap,&pe32));
	
	CloseHandle(hProcessSnap);
	return bRet;
}

/*置控制台颜色*/
void setColor(int c){
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),c);
}

/*退出程序*/
void close(void){
	exit(0);
}

pm_op.c

/*Process Memory Operation*/

#include <stdarg.h>
#include "headgr.h"

/*句柄,基址,偏移级数,数值类型,偏移地址参数列*/
static DWORD getMemory(HANDLE hProcess,DWORD BaseAddr,int level,SIZE_T Size,va_list argptr){
	DWORD tempAddr;
	tempAddr=BaseAddr;
	
	int i;
	if(level!=0){
		for(i=0;i<level;i++){
			ReadProcessMemory(hProcess,(LPVOID)tempAddr,(LPVOID)&tempAddr,(SIZE_T)Size,NULL);
			tempAddr+=va_arg(argptr,DWORD);
		}
	}
	
	va_end(argptr);
	
	#if DEBUG
		int value;
		ReadProcessMemory(hProcess,(LPVOID)tempAddr,(LPVOID)&value,(SIZE_T)Size,NULL);
		printf("偏移地址为:%x,读取的值为:%d\n",tempAddr,value);
	#endif
	
	return tempAddr;
}

/*句柄,基址,偏移级数,数值类型,偏移地址参数列*/
DWORD readMemory(HANDLE hProcess,DWORD BaseAddr,int level,SIZE_T Size,...){
	va_list argptr;
	va_start(argptr,Size);
	
	DWORD finalAddr;
	finalAddr=getMemory(hProcess,BaseAddr,level,Size,argptr);
	
	va_end(argptr);
	
	int value;
	ReadProcessMemory(hProcess,(LPVOID)finalAddr,(LPVOID)&value,(SIZE_T)Size,NULL);
	
	return value;
}

/*句柄,基址,偏移级数,写入值,数值类型,偏移地址参数列*/
BOOL writeMemory(HANDLE hProcess,DWORD BaseAddr,int level,DWORD value,SIZE_T Size,...){
	va_list argptr;
	va_start(argptr,Size);
	
	DWORD finalAddr;
	finalAddr=getMemory(hProcess,BaseAddr,level,Size,argptr);
	
	va_end(argptr);
	
	return WriteProcessMemory(hProcess,(LPVOID)finalAddr,(LPVOID)&value,(SIZE_T)Size,NULL);
}

headgr.h

#define DEBUG 0
#define PROCESS_NAME "PlantsVsZombies.exe" 

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <tlhelp32.h>


/*p_op - Process Operation*/
BOOL FindProcessPid(LPCSTR ProcessName,DWORD &dwPid);
void setColor(int c);
void close(void);

/*pm_op - Process Memory Operation*/
DWORD readMemory(HANDLE hProcess,DWORD BaseAddr,int level,SIZE_T Size,...);
BOOL writeMemory(HANDLE hProcess,DWORD BaseAddr,int level,DWORD value,SIZE_T Size,...);

/*g_msg - Game Message*/
void menu(void);
void upData(void);
void cheatCode(void);
void showMiniGameList(void);
void pause(void);
void noOperation(void);
void about(void);
void cheatMsg(BOOL isSuccess,const char msg[]);
void showOpenCheat(void);
void showProcessName(const char msg1[],const char msg2[]);

/*g_op - Game Operation*/
void initModifier(void);
BOOL openGameProcess(void);
BOOL openModify(void);
void Choice(void);
int limit(int value,int min,int max);


  • 10
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值