首页
社区
课程
招聘
植物大战僵尸修改器制作--从入门到入土
发表于: 2023-8-3 09:52 19116

植物大战僵尸修改器制作--从入门到入土

2023-8-3 09:52
19116

CheatEngine工具的基本使用

推荐视频你能学会的Cheat Engine零基础入门教程

将ce官方给的闯关游戏通关即可

C/C++和汇编语言基础

附上汇编代码转换网站

WIN32开发基础

了解WIN32命名规则,会使用GPT和查找微软官方文档即可

推荐通过看微软官方文档Win32 和 C++ 入门 能创建第一个windows程序即可

示例游戏版本: 中文年度加强版1.1.0.1056

主要参考资料

【补档】豪哥植物大战僵尸修改教程视频合集

C/C++全栈软件安全课(调试、反调试、游戏反外挂、软件逆向)持续更新中~~~~

逆向工程实战 揭秘汇编/反汇编(win32+游戏逆向实战)

部分参考: 公布我所找到的所有基址及各种功能实现方法

基址 0x00355E0C

阳光 +868 +5578

金钱 +950 +50

花肥 +950 +220

巧克力 +950 +250

树肥 +950 +258

树高 +950 +11C

杀虫剂 +950 +224

卡槽数 +868 +15C +24

卡槽栏 +868 +15C +5C 此后每个植物栏相隔0x50

植物当前冷却值 +868 +15C +4C 此后每个植物冷却相隔0x50

植物冷却值上限 +868 +15C +50 此后每个植物冷却上限相隔0x50

植物当前数量 +868 +D4

植物种植函数EBP +868

僵尸当前数量 +868 +B8

僵尸种植函数EBP +868 +178

根据变量的变化使用CE寻找,找到之后再通过指针扫描寻找可用的基址

阳光 内存实际值=游戏显示值

智慧树高度 内存实际值=游戏显示值

金钱 内存实际值=游戏显示值/10

花肥,杀虫剂,巧克力,树肥 内存实际值=游戏显示值+1000

关键函数和变量

十个卡槽,每个卡槽对应一个植物,可以在坚果保龄球2中根据卡槽1(最左边的卡槽)的坚果变化来找到卡槽的地址,之后再寻找基址

具体方法: 初值未知,如果卡槽1的植物和新的卡槽1(原卡槽2)的植物相同,则扫不变的值,否则扫变化的值

卡槽之间的偏移可以通过浏览卡槽1内存区域看出,为0x50

坚果植物卡槽编号:

普通坚果 3

爆炸坚果 49

巨型坚果 50

设置卡槽植物函数

具体方法: 仅针对一个卡槽,初始值未知,种植后持续变化,冷却完毕后不变,反复扫描并查找基址,查看对应内存区域再对照植物编号可以发现卡槽间的偏移为0x50

冷却特点: 可种植状态冷却值为0,种植后冷却值持续增长,到达冷却上限后,冷却值清零,植物重新可种植

注意: 直接将冷却值置0会导致无法种植

修改方法:

以方法2为例

7E 16 对应汇编指令为 jle 0x18

修改为jmp $+2 即 eb 00 (相对当前指令2字节后的指令)

直接执行冷却值达到冷却上限后的函数(冷却值清零,植物冷却完毕可种植)

附上汇编代码转换网站

关键代码

前文已经给出了阳光的地址 基址为0x355E0C 偏移+868 +5578

查找对阳光修改的代码即可

阳光减少代码

阳光增加代码

基本过程:

设置阳光值为9999

修改阳光减少代码使得种植物不消耗阳光

修改阳光增加代码使得阳光不变化(防止阳光过多导致溢出)

具体方法: 在生存模式浓雾进行,初值未知,通过在雾区种植和铲除路灯花引起的变化来判断,最终可以发现是4字节数据,数值代表雾的浓度,255代表浓雾,0代表没雾,再查找修改雾值的代码

寻找浓雾地址

浓雾修改代码

mov [ecx],edx这行代码修改了雾值,可以改为mov [ecx],0

注意硬编码为0xc7,0x01,0x00,0x00,0x00,0x00 由于较长无法直接修改代码,所以这里选择使用hook技术

hook的基本过程

值得一提的是jmp指令后跟的偏移值是以jmp的下一条指令首地址计算

jmp指令偏移值=目的地址-(jmp指令首地址+5) 这里的5是jmp指令本身的长度 +5便是下一条指令

offset=desAddr-(jmpAddr+5)

hook前 指令为mov [ecx],edx add ecx,04

hook后 指令被修改为jmp

hookcode 新分配空间前5个字节正是原始代码 之后是hook代码和jmp返回代码

程序是执行种植植物的函数后再执行增加植物数量的功能

首先查找草坪上的植物数量,初值0,随着种植个数增加 基址0x355E0C 偏移+868 +D4

再查找是什么修改了植物数量,下断点之后再种植一个植物

断下后查看调用堆栈中的返回地址,即可找到种植函数

这个功能最初使用远程线程注入dll来实现,注入dll虽然比较简单但是却并不通用,在此仅做介绍,比较推荐使用远程代码注入的方式实现

远程线程是当前进程在目标进程中创建一个线程并执行特定代码(这段代码必须在目标进程中而不是当前进程中)

注入dll是因为dll在被进程或线程加载时执行dll的DllMain函数,通过这一特点我们可以实现一些特殊功能

优点: 便于实现

缺点: dll注入容易被检测到

基本过程:

很多教程只给出了如何注入dll,没有演示如何卸载

如果只注入不卸载会导致下次再注入时不会执行特定函数(由于dll已经被加载过) 不方便实时调试更新dll等问题

基本过程:

这里使用了三种方法

注意: 不要将代码写入switch(reason)之外,否则可能会导致多次执行

执行结果

这是写dll函数时遇到的问题 如果直接用 mov ecx,[BaseAddr+0x355E0C]会导致代码执行失败,推测是这条指令访存过慢所以无效

建议mov ecx,BaseAddr之后通过对寄存器操作达到目的

和远程线程dll注入类似,CreateRemoteThread函数要求的函数原型是

基本过程:

与种植植物思路类似

首先在头脑风暴中通过种植僵尸来找到僵尸数量地址

然后找到僵尸数量增加代码

再通过查看调用堆栈和参数找到种植僵尸call

参数应该也是x y type ebp (注意没有-1)

僵尸种植函数的x值在一个call上方,这个call是个switch结构,没有参数,所以x值也没被修改

DLL代码

enum Type {
    Sunlight, Money, TreeHeight, Chocolate, TreeFood, FlowerFood, Insecticide
};
 
//定义映射表用于保存各项偏移值
unsigned int offsetTable[10] = { 0x5578,0x50,0x11c,0x250,0x258,0x220,0x224 };
 
//获取某些项目的值
unsigned int getSomething(HANDLE handle, DWORD BaseAddr,unsigned int type) {
    unsigned int num = 0;
    DWORD addr = BaseAddr + 0x00355E0C;
    ReadProcessMemory(handle, addr, &addr, sizeof(DWORD), NULL);
    if (type == Sunlight)
        addr += 0x868;
    else
        addr += 0x950;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    addr += offsetTable[type];
    ReadProcessMemory(handle, (LPVOID)addr, &num, sizeof(DWORD), 0);
    return num;
}
 
//设置某些项目的值
void setSomething(HANDLE handle, DWORD BaseAddr,unsigned int type, unsigned int num) {
    DWORD addr = BaseAddr + 0x00355E0C;
    ReadProcessMemory(handle, addr, &addr, sizeof(DWORD), NULL);
    if (type == Sunlight)
        addr += 0x868;
    else
        addr += 0x950;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    addr += offsetTable[type];
    WriteProcessMemory(handle, (LPVOID)addr, &num, sizeof(DWORD), 0);
}
enum Type {
    Sunlight, Money, TreeHeight, Chocolate, TreeFood, FlowerFood, Insecticide
};
 
//定义映射表用于保存各项偏移值
unsigned int offsetTable[10] = { 0x5578,0x50,0x11c,0x250,0x258,0x220,0x224 };
 
//获取某些项目的值
unsigned int getSomething(HANDLE handle, DWORD BaseAddr,unsigned int type) {
    unsigned int num = 0;
    DWORD addr = BaseAddr + 0x00355E0C;
    ReadProcessMemory(handle, addr, &addr, sizeof(DWORD), NULL);
    if (type == Sunlight)
        addr += 0x868;
    else
        addr += 0x950;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    addr += offsetTable[type];
    ReadProcessMemory(handle, (LPVOID)addr, &num, sizeof(DWORD), 0);
    return num;
}
 
//设置某些项目的值
void setSomething(HANDLE handle, DWORD BaseAddr,unsigned int type, unsigned int num) {
    DWORD addr = BaseAddr + 0x00355E0C;
    ReadProcessMemory(handle, addr, &addr, sizeof(DWORD), NULL);
    if (type == Sunlight)
        addr += 0x868;
    else
        addr += 0x950;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    addr += offsetTable[type];
    WriteProcessMemory(handle, (LPVOID)addr, &num, sizeof(DWORD), 0);
}
//设置卡槽植物
BOOL SetPlantCard(HANDLE hProcess,DWORD BaseAddr,DWORD nCard,DWORD plantType) {
    DWORD cardAddr = BaseAddr + 0x355E0C;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x868;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x15C;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x5C+nCard*0x50;//卡槽偏移
    return WriteProcessMemory(hProcess, cardAddr, &plantType, sizeof(DWORD), NULL);
}
//设置卡槽植物
BOOL SetPlantCard(HANDLE hProcess,DWORD BaseAddr,DWORD nCard,DWORD plantType) {
    DWORD cardAddr = BaseAddr + 0x355E0C;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x868;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x15C;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x5C+nCard*0x50;//卡槽偏移
    return WriteProcessMemory(hProcess, cardAddr, &plantType, sizeof(DWORD), NULL);
}
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
 
//无限冷却
BOOL Uncooled(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char code[2] = { 0xeb,0x00 };
    return WriteProcessCodeMemory(hProcess, BaseAddr + 0x9ce02, code, 2);//jle 0x18修改为jmp $+2
}
 
//恢复冷却
BOOL RecoveryCooling(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char OriginalCode[2] = { 0x7E ,0x16 };//jmp $+2恢复为jle 0x18
    return WriteProcessCodeMemory(hProcess, BaseAddr + 0x9ce02, OriginalCode, 2);
}
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
 
//无限冷却
BOOL Uncooled(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char code[2] = { 0xeb,0x00 };
    return WriteProcessCodeMemory(hProcess, BaseAddr + 0x9ce02, code, 2);//jle 0x18修改为jmp $+2
}
 
//恢复冷却
BOOL RecoveryCooling(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char OriginalCode[2] = { 0x7E ,0x16 };//jmp $+2恢复为jle 0x18
    return WriteProcessCodeMemory(hProcess, BaseAddr + 0x9ce02, OriginalCode, 2);
}
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
//无限阳光,锁定阳光为9999
BOOL UnlimitedSun(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char Code[3] = { 0x29,0xdb,0 };//cmp ebx,eax 修改为sub ebx,ebx   and ecx,0x32修改为and ecx,0
    BOOL flag;
    flag = setSomething(hProcess, BaseAddr, Sunlight, 9999);//修改阳光
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x27690, Code, 2);//修改阳光减少代码
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x3C0AB, &Code[2], 1);//修改阳光增加代码
    return flag;
}
 
//恢复阳光消耗
BOOL RecoverySunConsume(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char OriginalCode[3] = { 0x3B,0xD8,0x32 };//sub ebx,ebx恢复为cmp ebx,eax and ecx,0恢复为and ecx,0x32
    BOOL flag = WriteProcessCodeMemory(hProcess, BaseAddr + 0x27690, OriginalCode, 2);//恢复阳光减少代码
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x3C0AB, &OriginalCode[2], 1);//恢复阳光增加代码
    return flag;
}
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
//无限阳光,锁定阳光为9999
BOOL UnlimitedSun(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char Code[3] = { 0x29,0xdb,0 };//cmp ebx,eax 修改为sub ebx,ebx   and ecx,0x32修改为and ecx,0
    BOOL flag;
    flag = setSomething(hProcess, BaseAddr, Sunlight, 9999);//修改阳光
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x27690, Code, 2);//修改阳光减少代码
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x3C0AB, &Code[2], 1);//修改阳光增加代码
    return flag;
}
 
//恢复阳光消耗
BOOL RecoverySunConsume(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char OriginalCode[3] = { 0x3B,0xD8,0x32 };//sub ebx,ebx恢复为cmp ebx,eax and ecx,0恢复为and ecx,0x32
    BOOL flag = WriteProcessCodeMemory(hProcess, BaseAddr + 0x27690, OriginalCode, 2);//恢复阳光减少代码
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x3C0AB, &OriginalCode[2], 1);//恢复阳光增加代码
    return flag;
}
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
 
//hook指定地址,申请新空间保存原始代码并写入hookcode,返回申请空间的地址
LPVOID SetHook(HANDLE hProcess, LPVOID desAddr, LPCVOID hookCode, SIZE_T hookCodeSize, SIZE_T origCodeSize) {
    BYTE origCode[10] = { 0 }, jmpCode[5] = { 0xE9,0,0,0,0 };
    //1. 读取并保存原始代码
    if (!ReadProcessMemory(hProcess, desAddr, origCode, origCodeSize, NULL))
        return NULL;
 
    //2. 申请空间用于存储原始代码,hook代码,jmp返回代码
    LPVOID allocAddr = VirtualAllocEx(hProcess, NULL, hookCodeSize + origCodeSize + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!allocAddr)
        return NULL;
 
    //3. 向申请空间写入原始代码,hook代码,jmp返回代码  jmp xxx 偏移为目的地址-jmp下一条指令地址
    *(DWORD*)(jmpCode + 1) = (DWORD)desAddr + 5 - ((DWORD)allocAddr + hookCodeSize + origCodeSize + 5);//hook返回地址的偏移
    if (!WriteProcessCodeMemory(hProcess, allocAddr, origCode, origCodeSize)                      //写入原始代码
        || !WriteProcessCodeMemory(hProcess, (DWORD)allocAddr + origCodeSize, hookCode, hookCodeSize)//写入hook代码
        || !WriteProcessCodeMemory(hProcess, (DWORD)allocAddr + origCodeSize + hookCodeSize, jmpCode, 5))//写入jmpcode
    {
        VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);//写入失败则释放空间
        return NULL;
    }
 
    //4. 修改目的地址处的代码  jmp xxx偏移 原始代码后才是需要执行的hook代码
    *(DWORD*)(jmpCode + 1) = ((DWORD)allocAddr + origCodeSize) - ((DWORD)desAddr + 5);
    WriteProcessCodeMemory(hProcess, desAddr, jmpCode, 5);//在源地址处写入跳转代码
    if (origCodeSize > 5)//原始代码长度大于5时nop多余字节
    {
        BYTE nopCode[5] = { 0x90,0x90,0x90,0x90,0x90 };
        if (!WriteProcessCodeMemory(hProcess, (DWORD)desAddr + 5, nopCode, origCodeSize - 5))
        {
            VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);//写入nopcode失败则释放空间并返回
            return NULL;
        }
    }
 
    //5. hook成功则返回hookCode所在地址
    return allocAddr;
}
 
//取消hook指定地址,写回原始代码并释放申请空间
BOOL UnHook(HANDLE hProcess, LPVOID desAddr, SIZE_T origCodeSize, LPVOID allocAddr) {
    BYTE origCode[10] = { 0 };
    //1. 从申请空间中读出原始代码
    if (!ReadProcessMemory(hProcess, allocAddr, origCode, origCodeSize, NULL))
        return FALSE;
    //2. 将原始代码写回目的地址
    if (!WriteProcessCodeMemory(hProcess, desAddr, origCode, origCodeSize))
        return FALSE;
    //3. 释放申请空间
    if (!VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE))
        return FALSE;
    return TRUE;
}
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
 
//hook指定地址,申请新空间保存原始代码并写入hookcode,返回申请空间的地址
LPVOID SetHook(HANDLE hProcess, LPVOID desAddr, LPCVOID hookCode, SIZE_T hookCodeSize, SIZE_T origCodeSize) {
    BYTE origCode[10] = { 0 }, jmpCode[5] = { 0xE9,0,0,0,0 };
    //1. 读取并保存原始代码
    if (!ReadProcessMemory(hProcess, desAddr, origCode, origCodeSize, NULL))
        return NULL;
 
    //2. 申请空间用于存储原始代码,hook代码,jmp返回代码
    LPVOID allocAddr = VirtualAllocEx(hProcess, NULL, hookCodeSize + origCodeSize + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!allocAddr)
        return NULL;
 
    //3. 向申请空间写入原始代码,hook代码,jmp返回代码  jmp xxx 偏移为目的地址-jmp下一条指令地址
    *(DWORD*)(jmpCode + 1) = (DWORD)desAddr + 5 - ((DWORD)allocAddr + hookCodeSize + origCodeSize + 5);//hook返回地址的偏移
    if (!WriteProcessCodeMemory(hProcess, allocAddr, origCode, origCodeSize)                      //写入原始代码
        || !WriteProcessCodeMemory(hProcess, (DWORD)allocAddr + origCodeSize, hookCode, hookCodeSize)//写入hook代码
        || !WriteProcessCodeMemory(hProcess, (DWORD)allocAddr + origCodeSize + hookCodeSize, jmpCode, 5))//写入jmpcode
    {
        VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);//写入失败则释放空间
        return NULL;
    }
 
    //4. 修改目的地址处的代码  jmp xxx偏移 原始代码后才是需要执行的hook代码
    *(DWORD*)(jmpCode + 1) = ((DWORD)allocAddr + origCodeSize) - ((DWORD)desAddr + 5);
    WriteProcessCodeMemory(hProcess, desAddr, jmpCode, 5);//在源地址处写入跳转代码
    if (origCodeSize > 5)//原始代码长度大于5时nop多余字节
    {
        BYTE nopCode[5] = { 0x90,0x90,0x90,0x90,0x90 };
        if (!WriteProcessCodeMemory(hProcess, (DWORD)desAddr + 5, nopCode, origCodeSize - 5))
        {
            VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);//写入nopcode失败则释放空间并返回
            return NULL;
        }
    }
 
    //5. hook成功则返回hookCode所在地址
    return allocAddr;
}
 
//取消hook指定地址,写回原始代码并释放申请空间
BOOL UnHook(HANDLE hProcess, LPVOID desAddr, SIZE_T origCodeSize, LPVOID allocAddr) {
    BYTE origCode[10] = { 0 };
    //1. 从申请空间中读出原始代码
    if (!ReadProcessMemory(hProcess, allocAddr, origCode, origCodeSize, NULL))
        return FALSE;
    //2. 将原始代码写回目的地址
    if (!WriteProcessCodeMemory(hProcess, desAddr, origCode, origCodeSize))
        return FALSE;
    //3. 释放申请空间
    if (!VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE))
        return FALSE;
    return TRUE;
}
//除雾 注意保留hook代码首地址
LPVOID DeFogByHook(HANDLE hProcess, LPVOID BaseAddr) {
 
    unsigned char hookCode[9] = {
        0xc7,0x01,0x00,0x00,0x00,0x00,  //mov [ecx],0
        0x83,0xc1,0x04                  //add ecx,0x4
    };
    //写入hook代码进行hook
    return SetHook(hProcess, (DWORD)BaseAddr + 0x26173, hookCode, sizeof(hookCode), 5);
}
 
//恢复雾
BOOL RecoveryFogByUnHook(HANDLE hProcess, LPVOID BaseAddr, LPVOID allocAddr) {
    return UnHook(hProcess, (DWORD)BaseAddr + 0x26173, 5, allocAddr);
}
//除雾 注意保留hook代码首地址
LPVOID DeFogByHook(HANDLE hProcess, LPVOID BaseAddr) {
 
    unsigned char hookCode[9] = {
        0xc7,0x01,0x00,0x00,0x00,0x00,  //mov [ecx],0
        0x83,0xc1,0x04                  //add ecx,0x4
    };
    //写入hook代码进行hook
    return SetHook(hProcess, (DWORD)BaseAddr + 0x26173, hookCode, sizeof(hookCode), 5);
}
 
//恢复雾
BOOL RecoveryFogByUnHook(HANDLE hProcess, LPVOID BaseAddr, LPVOID allocAddr) {
    return UnHook(hProcess, (DWORD)BaseAddr + 0x26173, 5, allocAddr);
}
//创建远程线程方式向指定进程注入dll
BOOL InjectDllByRemoteThread(DWORD desProcId,WCHAR* dllPath) {
    //打开进程获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, desProcId);
    if (!hProcess)
        return FALSE;
 
    //申请空间
    DWORD pathSize = (wcslen(dllPath) + 1) * 2;
    LPVOID newMemAddr = VirtualAllocEx(hProcess, 0, pathSize, MEM_COMMIT, PAGE_READWRITE);
    if (!newMemAddr)
        return FALSE;
 
    //写入dll路径
    if (!WriteProcessMemory(hProcess, newMemAddr, dllPath, pathSize, NULL))
    {
        VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
        return FALSE;
    }
        
    //创建远程线程
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, newMemAddr, 0, NULL);
    if (!hThread)
    {
        VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
        return FALSE;
    }
 
    WaitForSingleObject(hThread, INFINITE);//等待线程信号,保证成功注入
 
    //回收资源
    VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
    CloseHandle(hThread);
    CloseHandle(hProcess);
 
    //返回成功
    return TRUE;
}
//创建远程线程方式向指定进程注入dll
BOOL InjectDllByRemoteThread(DWORD desProcId,WCHAR* dllPath) {
    //打开进程获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, desProcId);
    if (!hProcess)
        return FALSE;
 
    //申请空间
    DWORD pathSize = (wcslen(dllPath) + 1) * 2;
    LPVOID newMemAddr = VirtualAllocEx(hProcess, 0, pathSize, MEM_COMMIT, PAGE_READWRITE);
    if (!newMemAddr)
        return FALSE;
 
    //写入dll路径
    if (!WriteProcessMemory(hProcess, newMemAddr, dllPath, pathSize, NULL))
    {
        VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
        return FALSE;
    }
        
    //创建远程线程
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, newMemAddr, 0, NULL);
    if (!hThread)
    {
        VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
        return FALSE;
    }
 
    WaitForSingleObject(hThread, INFINITE);//等待线程信号,保证成功注入
 
    //回收资源
    VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
    CloseHandle(hThread);
    CloseHandle(hProcess);
 
    //返回成功
    return TRUE;
}
BOOL UnLoadDllByRemoteThread(DWORD dwProcessId, LPCWSTR lpDllName)
{
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess == NULL)
        return FALSE;
 
    // 在目标进程中申请一块内存,并将需要卸载的DLL模块的名称写入该内存
    LPVOID lpRemoteDllName = VirtualAllocEx(hProcess, NULL, (wcslen(lpDllName) + 1) * sizeof(WCHAR), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (lpRemoteDllName == NULL)
    {
        CloseHandle(hProcess);
        return FALSE;
    }
    if (!WriteProcessMemory(hProcess, lpRemoteDllName, lpDllName, (wcslen(lpDllName) + 1) * sizeof(WCHAR), NULL))
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    //查找dll模块
    HMODULE hModules[1024],DesModule=NULL;
    DWORD dwSize = 0;
    if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &dwSize))
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    // 遍历模块列表,查找需要卸载的DLL模块
    for (DWORD i = 0; i < (dwSize / sizeof(HMODULE)); i++)
    {
        WCHAR szModuleName[MAX_PATH] = { 0 };
        if (GetModuleFileNameExW(hProcess, hModules[i], szModuleName, MAX_PATH) > 0)
        {
            // 获取模块句柄
            if (wcsicmp(szModuleName, lpDllName) == 0)
            {
                DesModule = hModules[i];
            }
        }
    }
    //没有查找到模块
    if (!DesModule) {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    // 在目标进程中创建远程线程,执行FreeLibrary函数
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, DesModule, 0, NULL);
    if (hThread == NULL)
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    // 等待线程执行完成
    WaitForSingleObject(hThread, INFINITE);
 
    // 关闭句柄
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
    CloseHandle(hProcess);
 
    return TRUE;
}
BOOL UnLoadDllByRemoteThread(DWORD dwProcessId, LPCWSTR lpDllName)
{
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess == NULL)
        return FALSE;
 
    // 在目标进程中申请一块内存,并将需要卸载的DLL模块的名称写入该内存
    LPVOID lpRemoteDllName = VirtualAllocEx(hProcess, NULL, (wcslen(lpDllName) + 1) * sizeof(WCHAR), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (lpRemoteDllName == NULL)
    {
        CloseHandle(hProcess);
        return FALSE;
    }
    if (!WriteProcessMemory(hProcess, lpRemoteDllName, lpDllName, (wcslen(lpDllName) + 1) * sizeof(WCHAR), NULL))
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    //查找dll模块
    HMODULE hModules[1024],DesModule=NULL;
    DWORD dwSize = 0;
    if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &dwSize))
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    // 遍历模块列表,查找需要卸载的DLL模块
    for (DWORD i = 0; i < (dwSize / sizeof(HMODULE)); i++)
    {
        WCHAR szModuleName[MAX_PATH] = { 0 };
        if (GetModuleFileNameExW(hProcess, hModules[i], szModuleName, MAX_PATH) > 0)
        {
            // 获取模块句柄
            if (wcsicmp(szModuleName, lpDllName) == 0)
            {
                DesModule = hModules[i];
            }
        }
    }
    //没有查找到模块
    if (!DesModule) {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    // 在目标进程中创建远程线程,执行FreeLibrary函数
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, DesModule, 0, NULL);
    if (hThread == NULL)
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    // 等待线程执行完成
    WaitForSingleObject(hThread, INFINITE);
 
    // 关闭句柄
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
    CloseHandle(hProcess);
 
    return TRUE;
}
#include<windows.h>
#include<stdio.h>
 
//调用函数
BOOL GrowPlant(DWORD BaseAddr, DWORD x, DWORD y, DWORD TypePlant) {
    LPVOID PlantFunc = BaseAddr + 0x18D70;
    __asm {
        pushad
        push -1         //-1
        push TypePlant   //植物类型
        mov eax, y       //y
        push x           //x
        mov ecx, BaseAddr
        mov ecx, [ecx+0x355E0C]
        mov ecx, [ecx + 0x868]
        push ecx        //植物种植ebp
        call PlantFunc
        popad
    }
    return TRUE;
}
 
 
BOOL WINAPI DllMain(HMODULE hInstance, DWORD fdwReason, LPVOID lpReserved) {
    DWORD BaseAddr = GetModuleHandle(NULL);
    DWORD pid = GetCurrentProcessId();
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    LPVOID PlantFunc = BaseAddr + 0x18D70;
    DWORD ebpAddr = BaseAddr+0x355E0C,num=0;
    ReadProcessMemory(hProcess, ebpAddr, &ebpAddr, sizeof(DWORD), NULL);
    ebpAddr += 0x868;
    ReadProcessMemory(hProcess, ebpAddr, &ebpAddr, sizeof(DWORD), NULL);//必须使用带hProcess参数的才能正确读取到地址,NULL不可以
    DWORD x = 1, y = 1, TypePlant = 16;
     
    //注意不要写到switch外,否则可能会一次种多株植物,猜测是dll被多个线程加载导致的
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:    //当进程加载dll模块时执行
        //MessageBoxW(0, L"ProcessAttach!", L"window2", 0);
        //1.直接通过使用ReadProcessMemory函数读取内存获取ebp参数
        __asm {
            pushad
            push - 1         //-1
            push TypePlant   //植物类型
            mov eax, y       //y
            push x           //x
            push  ebpAddr    //ebp
            call PlantFunc  
            popad
        }
 
        //2.通过利用寄存器获取ebp(推荐)
        x = 3, y = 2, TypePlant = 18;
        __asm {
            pushad
            push - 1         //-1
            push TypePlant   //植物类型
            mov eax, y       //y
            push x           //x
            mov ecx, BaseAddr
            mov ecx, [ecx+0x355E0C]
            mov ecx, [ecx + 0x868]
            push ecx
            call PlantFunc
            popad
        }
       //3. 通过调用函数(推荐)    
        GrowPlant(BaseAddr,7,3,23);        
                      
        break;
    //case DLL_THREAD_ATTACH:       
    //    printf("ThreadAttach!\n");
    //    break;
    //case DLL_THREAD_DETACH:      
    //  if (lpReserved == NULL)
    //    {
    //        FreeLibrary(hInstance);
    //    }
        break;
    case DLL_PROCESS_DETACH:        //当进程卸载dll模块时执行
        MessageBoxW(0, L"ProcessDeTachDll!", L"window2", 0);
        break;
    }
    return TRUE;
}
#include<windows.h>
#include<stdio.h>
 
//调用函数
BOOL GrowPlant(DWORD BaseAddr, DWORD x, DWORD y, DWORD TypePlant) {
    LPVOID PlantFunc = BaseAddr + 0x18D70;
    __asm {
        pushad
        push -1         //-1
        push TypePlant   //植物类型
        mov eax, y       //y
        push x           //x
        mov ecx, BaseAddr
        mov ecx, [ecx+0x355E0C]
        mov ecx, [ecx + 0x868]
        push ecx        //植物种植ebp
        call PlantFunc
        popad
    }
    return TRUE;
}
 
 
BOOL WINAPI DllMain(HMODULE hInstance, DWORD fdwReason, LPVOID lpReserved) {
    DWORD BaseAddr = GetModuleHandle(NULL);
    DWORD pid = GetCurrentProcessId();
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    LPVOID PlantFunc = BaseAddr + 0x18D70;
    DWORD ebpAddr = BaseAddr+0x355E0C,num=0;
    ReadProcessMemory(hProcess, ebpAddr, &ebpAddr, sizeof(DWORD), NULL);
    ebpAddr += 0x868;
    ReadProcessMemory(hProcess, ebpAddr, &ebpAddr, sizeof(DWORD), NULL);//必须使用带hProcess参数的才能正确读取到地址,NULL不可以
    DWORD x = 1, y = 1, TypePlant = 16;
     
    //注意不要写到switch外,否则可能会一次种多株植物,猜测是dll被多个线程加载导致的
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:    //当进程加载dll模块时执行
        //MessageBoxW(0, L"ProcessAttach!", L"window2", 0);
        //1.直接通过使用ReadProcessMemory函数读取内存获取ebp参数
        __asm {
            pushad
            push - 1         //-1
            push TypePlant   //植物类型
            mov eax, y       //y
            push x           //x
            push  ebpAddr    //ebp
            call PlantFunc  
            popad
        }
 
        //2.通过利用寄存器获取ebp(推荐)
        x = 3, y = 2, TypePlant = 18;
        __asm {
            pushad
            push - 1         //-1
            push TypePlant   //植物类型
            mov eax, y       //y
            push x           //x
            mov ecx, BaseAddr
            mov ecx, [ecx+0x355E0C]
            mov ecx, [ecx + 0x868]
            push ecx
            call PlantFunc
            popad
        }
       //3. 通过调用函数(推荐)    
        GrowPlant(BaseAddr,7,3,23);        
                      
        break;
    //case DLL_THREAD_ATTACH:       
    //    printf("ThreadAttach!\n");
    //    break;
    //case DLL_THREAD_DETACH:      
    //  if (lpReserved == NULL)
    //    {
    //        FreeLibrary(hInstance);
    //    }
        break;
    case DLL_PROCESS_DETACH:        //当进程卸载dll模块时执行
        MessageBoxW(0, L"ProcessDeTachDll!", L"window2", 0);
        break;
    }
    return TRUE;
}
__asm {
        pushad
        push - 1         //-1
        push TypePlant   //植物类型
        mov eax, y       //y
        push x           //x
        mov ecx,[BaseAddr+ 0x355E0C]//这样不行,推测是访存过慢
        mov ecx,[ecx+0x868]
        mov num, ecx
        push ecx
        call PlantFunc
        popad
    }
__asm {
        pushad
        push - 1         //-1
        push TypePlant   //植物类型
        mov eax, y       //y
        push x           //x
        mov ecx,[BaseAddr+ 0x355E0C]//这样不行,推测是访存过慢
        mov ecx,[ecx+0x868]
        mov num, ecx
        push ecx
        call PlantFunc
        popad
    }
DWORD WINAPI ThreadProc(
  _In_ LPVOID lpParameter//使用CreateThread函数传递的参数 该参数是一个指向其他数据的指针,当然也可以强转为其他类型直接使用
);
DWORD WINAPI ThreadProc(
  _In_ LPVOID lpParameter//使用CreateThread函数传递的参数 该参数是一个指向其他数据的指针,当然也可以强转为其他类型直接使用
);
//以创建远程线程方式种植植物
BOOL GrowPlantByInjectCode(DWORD dwProcessId,DWORD BaseAddr,DWORD x,DWORD y,DWORD PlantType)
{
    BOOL bSuccess = FALSE;
    //1. 打开进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);   
    if (hProcess != NULL)
    {
        //2. 定义注入代码(函数)
 
        BYTE InjectCode[50] = {                     //汇编指令              //修正点偏移
            0x55,                                   //0 push ebp
            0x89, 0xE5,                             //1 mov ebp,esp
            0x60,                                   //3 pushad               
            0x68, 0xFF, 0xFF, 0xFF, 0xFF,           //4 push -1          
            0x68, 0x00, 0x00, 0x00, 0x00,           //9 push PlantType        //10    
            0xB8, 0x00, 0x00, 0x00, 0x00,           //14 mov eax,y             //15
            0x68, 0x00, 0x00, 0x00, 0x00,           //19 push x                //20
            0xB9, 0x00, 0x00, 0x00, 0x00,           //24 mov ecx,BaseAddr      //25
            0x8B, 0x89, 0x0C, 0x5E, 0x35, 0x00,     //29 mov ecx,[ecx+0x355E0C]
            0x8B, 0x89, 0x68, 0x08, 0x00, 0x00,     //35 mov ecx,[ecx+0x868]
            0x51,                                   //41 push ecx
            0xE8, 0x00, 0x00, 0x00, 0x00,           //42 call PlantFunc        //43     //被调方平栈
            0x61,                                   //47 popad
            0xC9,                                   //48 leave
            0xC3                                    //49 ret
        };
 
        //3. 申请空间用于存储代码
        DWORD  dwCodeSize = 50, desFunc = BaseAddr + 0x18D70;
        LPVOID lpRemoteCodeMem = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
        //4. 修正参数
        *(DWORD*)&InjectCode[10] = PlantType;
        *(DWORD*)&InjectCode[15] = y;
        *(DWORD*)&InjectCode[20] = x;
        *(DWORD*)&InjectCode[25] = BaseAddr;
        *(DWORD*)&InjectCode[43] = desFunc-((DWORD)lpRemoteCodeMem+42+5) ;
        //call指令与jmp类似,相对于当前指令的下一条指令计算偏移,offset=des-(source+5),减去call自身长度5
 
        if (lpRemoteCodeMem != NULL)
        {
            SIZE_T dwBytesWritten = 0;
            //5. 注入代码
            if (WriteProcessMemory(hProcess, lpRemoteCodeMem, InjectCode, dwCodeSize, &dwBytesWritten) &&
                dwBytesWritten == dwCodeSize)
            {
                //6. 创建远程线程执行代码
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteCodeMem,NULL, 0, NULL);
                if (hThread != NULL)
                {
                    //7. 等待线程信号
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    bSuccess = TRUE;
                }
            }
            //8. 执行完后释放空间
            VirtualFreeEx(hProcess, lpRemoteCodeMem, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
     
    return bSuccess;
}
//以创建远程线程方式种植植物
BOOL GrowPlantByInjectCode(DWORD dwProcessId,DWORD BaseAddr,DWORD x,DWORD y,DWORD PlantType)
{
    BOOL bSuccess = FALSE;
    //1. 打开进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);   
    if (hProcess != NULL)
    {
        //2. 定义注入代码(函数)
 
        BYTE InjectCode[50] = {                     //汇编指令              //修正点偏移
            0x55,                                   //0 push ebp
            0x89, 0xE5,                             //1 mov ebp,esp
            0x60,                                   //3 pushad               
            0x68, 0xFF, 0xFF, 0xFF, 0xFF,           //4 push -1          
            0x68, 0x00, 0x00, 0x00, 0x00,           //9 push PlantType        //10    
            0xB8, 0x00, 0x00, 0x00, 0x00,           //14 mov eax,y             //15
            0x68, 0x00, 0x00, 0x00, 0x00,           //19 push x                //20
            0xB9, 0x00, 0x00, 0x00, 0x00,           //24 mov ecx,BaseAddr      //25
            0x8B, 0x89, 0x0C, 0x5E, 0x35, 0x00,     //29 mov ecx,[ecx+0x355E0C]
            0x8B, 0x89, 0x68, 0x08, 0x00, 0x00,     //35 mov ecx,[ecx+0x868]
            0x51,                                   //41 push ecx
            0xE8, 0x00, 0x00, 0x00, 0x00,           //42 call PlantFunc        //43     //被调方平栈
            0x61,                                   //47 popad
            0xC9,                                   //48 leave
            0xC3                                    //49 ret
        };
 
        //3. 申请空间用于存储代码
        DWORD  dwCodeSize = 50, desFunc = BaseAddr + 0x18D70;
        LPVOID lpRemoteCodeMem = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
        //4. 修正参数
        *(DWORD*)&InjectCode[10] = PlantType;
        *(DWORD*)&InjectCode[15] = y;
        *(DWORD*)&InjectCode[20] = x;
        *(DWORD*)&InjectCode[25] = BaseAddr;
        *(DWORD*)&InjectCode[43] = desFunc-((DWORD)lpRemoteCodeMem+42+5) ;
        //call指令与jmp类似,相对于当前指令的下一条指令计算偏移,offset=des-(source+5),减去call自身长度5
 
        if (lpRemoteCodeMem != NULL)
        {
            SIZE_T dwBytesWritten = 0;
            //5. 注入代码
            if (WriteProcessMemory(hProcess, lpRemoteCodeMem, InjectCode, dwCodeSize, &dwBytesWritten) &&
                dwBytesWritten == dwCodeSize)
            {
                //6. 创建远程线程执行代码
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteCodeMem,NULL, 0, NULL);
                if (hThread != NULL)
                {
                    //7. 等待线程信号
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    bSuccess = TRUE;
                }
            }
            //8. 执行完后释放空间
            VirtualFreeEx(hProcess, lpRemoteCodeMem, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
     
    return bSuccess;
}
BOOL GrowZombie(DWORD BaseAddr, DWORD x, DWORD y, DWORD ZombieType) {
    LPVOID PlantZombieFunc = BaseAddr + 0x35390;
    __asm {
        pushad
        push x
        push ZombieType
        mov eax,y
        mov ecx,BaseAddr
        mov ecx,[ecx+0x355E0C]
        mov ecx,[ecx+0x868]
        mov ecx,[ecx+0x178]    //ebp
        call PlantZombieFunc
        popad
    }
    return TRUE;
}
BOOL GrowZombie(DWORD BaseAddr, DWORD x, DWORD y, DWORD ZombieType) {
    LPVOID PlantZombieFunc = BaseAddr + 0x35390;
    __asm {
        pushad
        push x
        push ZombieType
        mov eax,y
        mov ecx,BaseAddr
        mov ecx,[ecx+0x355E0C]
        mov ecx,[ecx+0x868]
        mov ecx,[ecx+0x178]    //ebp
        call PlantZombieFunc
        popad
    }
    return TRUE;
}
//以创建远程线程方式种植僵尸
BOOL GrowZombieByRemoteThread(DWORD dwProcessId,DWORD BaseAddr, DWORD x, DWORD y, DWORD ZombieType) {
 
    BOOL bSuccess = FALSE;
    //1. 打开进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess != NULL)
    {
        //2. 定义注入代码(函数)
 
        BYTE InjectCode[50] = {
            0x55,                                       //0 push ebp
            0x89, 0xE5,                                 //1 mov ebp,esp
            0x60,                                       //3 pushad
            0x68, 0x00, 0x00, 0x00, 0x00,               //4 push x
            0x68, 0x00, 0x00, 0x00, 0x00,               //9 push ZombieType
            0xB8, 0x00, 0x00, 0x00, 0x00,               //14 mov eax,y
            0xB9, 0x00, 0x00, 0x00, 0x00,               //19 mov ecx,BaseAddr
            0x8B, 0x89, 0x0C, 0x5E, 0x35, 0x00,         //24 mov ecx,[ecx+0x355E0C]
            0x8B, 0x89, 0x68, 0x08, 0x00, 0x00,         //30 mov ecx,[ecx+0x868]
            0x8B, 0x89, 0x78, 0x01, 0x00, 0x00,         //36 mov ecx,[ecx+0x178]
            0xE8, 0x00, 0x00, 0x00, 0x00,               //42 call PlantZombieFunc
            0x61,                                       //47 popad
            0xC9,                                       //48 leave
            0xC3                                        //49 ret
        };
 
        //3. 申请空间用于存储代码
        DWORD  dwCodeSize = 50, desFunc = BaseAddr + 0x35390; //种植僵尸函数
        LPVOID lpRemoteCodeMem = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
        //4. 修正参数
        *(DWORD*)&InjectCode[5] = x;
        *(DWORD*)&InjectCode[10] = ZombieType;
        *(DWORD*)&InjectCode[15] = y;
        *(DWORD*)&InjectCode[20] = BaseAddr;
        *(DWORD*)&InjectCode[43] = desFunc - ((DWORD)lpRemoteCodeMem + 42 + 5);//call指令与jmp类似,相对于当前指令的下一条指令计算偏移,要减去call长度5
 
        if (lpRemoteCodeMem != NULL)
        {
            SIZE_T dwBytesWritten = 0;
            //5. 注入代码
            if (WriteProcessMemory(hProcess, lpRemoteCodeMem, InjectCode, dwCodeSize, &dwBytesWritten) &&
                dwBytesWritten == dwCodeSize)
            {
                //6. 创建远程线程执行代码
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteCodeMem, NULL, 0, NULL);
                if (hThread != NULL)
                {
                    //7. 等待线程信号
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    bSuccess = TRUE;
                }
            }
            //8. 执行完后释放空间
            VirtualFreeEx(hProcess, lpRemoteCodeMem, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
 
    return bSuccess;
}
//以创建远程线程方式种植僵尸
BOOL GrowZombieByRemoteThread(DWORD dwProcessId,DWORD BaseAddr, DWORD x, DWORD y, DWORD ZombieType) {
 
    BOOL bSuccess = FALSE;
    //1. 打开进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess != NULL)
    {
        //2. 定义注入代码(函数)
 
        BYTE InjectCode[50] = {
            0x55,                                       //0 push ebp
            0x89, 0xE5,                                 //1 mov ebp,esp
            0x60,                                       //3 pushad
            0x68, 0x00, 0x00, 0x00, 0x00,               //4 push x
            0x68, 0x00, 0x00, 0x00, 0x00,               //9 push ZombieType
            0xB8, 0x00, 0x00, 0x00, 0x00,               //14 mov eax,y
            0xB9, 0x00, 0x00, 0x00, 0x00,               //19 mov ecx,BaseAddr
            0x8B, 0x89, 0x0C, 0x5E, 0x35, 0x00,         //24 mov ecx,[ecx+0x355E0C]
            0x8B, 0x89, 0x68, 0x08, 0x00, 0x00,         //30 mov ecx,[ecx+0x868]
            0x8B, 0x89, 0x78, 0x01, 0x00, 0x00,         //36 mov ecx,[ecx+0x178]
            0xE8, 0x00, 0x00, 0x00, 0x00,               //42 call PlantZombieFunc
            0x61,                                       //47 popad
            0xC9,                                       //48 leave
            0xC3                                        //49 ret
        };
 
        //3. 申请空间用于存储代码
        DWORD  dwCodeSize = 50, desFunc = BaseAddr + 0x35390; //种植僵尸函数
        LPVOID lpRemoteCodeMem = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
        //4. 修正参数
        *(DWORD*)&InjectCode[5] = x;
        *(DWORD*)&InjectCode[10] = ZombieType;
        *(DWORD*)&InjectCode[15] = y;
        *(DWORD*)&InjectCode[20] = BaseAddr;
        *(DWORD*)&InjectCode[43] = desFunc - ((DWORD)lpRemoteCodeMem + 42 + 5);//call指令与jmp类似,相对于当前指令的下一条指令计算偏移,要减去call长度5
 
        if (lpRemoteCodeMem != NULL)
        {
            SIZE_T dwBytesWritten = 0;
            //5. 注入代码
            if (WriteProcessMemory(hProcess, lpRemoteCodeMem, InjectCode, dwCodeSize, &dwBytesWritten) &&
                dwBytesWritten == dwCodeSize)
            {
                //6. 创建远程线程执行代码
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteCodeMem, NULL, 0, NULL);
                if (hThread != NULL)
                {
                    //7. 等待线程信号
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    bSuccess = TRUE;
                }
            }
            //8. 执行完后释放空间
            VirtualFreeEx(hProcess, lpRemoteCodeMem, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
 
    return bSuccess;
}
#include<stdio.h>
#include<windows.h>
#include <tlhelp32.h>
#include <string.h>
#include <shlwapi.h>
#include <psapi.h>
 
enum Type {
    Sunlight, Money, TreeHeight, Chocolate, TreeFood, FlowerFood, Insecticide
};
unsigned int offsetTable[10] = { 0x5578,0x50,0x11c,0x250,0x258,0x220,0x224 };
 
 
// 根据进程名获取进程ID
DWORD GetProcessIdByName(const wchar_t* processName) {
 
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);// 创建一个进程快照
    if (snapshot == INVALID_HANDLE_VALUE) {
        return 0;// 如果创建失败,返回 0
    }
 
    // 定义一个 PROCESSENTRY32 结构体,用于存储进程信息
    PROCESSENTRY32 processEntry = { 0 };
    processEntry.dwSize = sizeof(PROCESSENTRY32);   //必须初始化,否则调用Process32First会失败
    if (!Process32First(snapshot, &processEntry)) {
        CloseHandle(snapshot);
        return 0;// 如果获取第一个进程信息失败,关闭进程快照句柄并返回 0
    }
 
    // 遍历进程列表
    do {
        wchar_t currentProcessName[MAX_PATH];                           // 获取当前进程的名称
        wcscpy_s(currentProcessName, MAX_PATH, processEntry.szExeFile); //szExeFile存储了进程对应可执行文件的名称
        if (wcscmp(currentProcessName, processName) == 0) {
            CloseHandle(snapshot);                                  // 如果当前进程名称和指定的进程名称相同,返回进程 ID
            return processEntry.th32ProcessID;
        }
    } while (Process32Next(snapshot, &processEntry));               //获取快照中下一个进程的信息
 
    // 如果遍历完整个进程列表都没有找到指定进程,关闭进程快照句柄并返回 0
    CloseHandle(snapshot);
    return 0;
}
 
//根据进程模块名获取基址
LPVOID GetModuleBaseAddress(DWORD processId, LPCWSTR moduleName) {
    LPVOID lpBaseAddress = NULL;
 
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); // 打开进程句柄
    if (hProcess != NULL) {
        // 枚举进程中的所有模块
        HMODULE hMods[1024];
        DWORD cbNeeded;
        if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
            DWORD dwModuleCount = cbNeeded / sizeof(HMODULE);// 计算模块数量
            // 获取指定模块的信息
            for (DWORD i = 0; i < dwModuleCount; i++) {
                TCHAR szModName[MAX_PATH];
                //获取指定模块的完整路径名
                if (GetModuleFileNameEx(hProcess, hMods[i], szModName, MAX_PATH)) {//函数成功返回字符串长度,注意第四个参数的单位为字符而非字节
                    if (wcsstr(szModName, moduleName)) {//查找模块名,若成功则返回子串第一次出现的指针
                        MODULEINFO modInfo = { 0 };
                        if (GetModuleInformation(hProcess, hMods[i], &modInfo, sizeof(MODULEINFO))) {//获取模块信息并保存到modInfo中
                            lpBaseAddress = modInfo.lpBaseOfDll;//模块基地址
                            break;
                        }
                    }
                }
            }
        }
        CloseHandle(hProcess); // 关闭进程句柄
    }
 
    return lpBaseAddress;
}
 
 
//修改进程代码区代码 参数: 进程句柄 修改代码起始地址 硬编码指针 代码字节数
BOOL WriteProcessCodeMemory(HANDLE hProcess, LPVOID lpStartAddress, LPCVOID lpBuffer, SIZE_T nSize) {
    DWORD dwOldProtect;
    //取消页保护
    if (!VirtualProtectEx(hProcess, lpStartAddress, nSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        return FALSE;
    }
    BOOL bResult = WriteProcessMemory(hProcess, lpStartAddress, lpBuffer, nSize, NULL);//写入代码
    VirtualProtectEx(hProcess, lpStartAddress, nSize, dwOldProtect, &dwOldProtect);//开启页保护
    return bResult;
}
 
//hook指定地址,申请新空间保存原始代码并写入hookcode,返回申请空间的地址
LPVOID SetHook(HANDLE hProcess, LPVOID desAddr, LPCVOID hookCode, SIZE_T hookCodeSize, SIZE_T origCodeSize) {
    BYTE origCode[10] = { 0 }, jmpCode[5] = { 0xE9,0,0,0,0 };
    //1. 读取并保存原始代码
    if (!ReadProcessMemory(hProcess, desAddr, origCode, origCodeSize, NULL))
        return NULL;
 
    //2. 申请空间用于存储原始代码,hook代码,jmp返回代码
    LPVOID allocAddr = VirtualAllocEx(hProcess, NULL, hookCodeSize + origCodeSize + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!allocAddr)
        return NULL;
 
    //3. 向申请空间写入原始代码,hook代码,jmp返回代码  jmp xxx 偏移为目的地址-jmp下一条指令地址
    *(DWORD*)(jmpCode + 1) = (DWORD)desAddr + 5 - ((DWORD)allocAddr + hookCodeSize + origCodeSize + 5);//hook返回地址的偏移
    if (!WriteProcessCodeMemory(hProcess, allocAddr, origCode, origCodeSize)                      //写入原始代码
        || !WriteProcessCodeMemory(hProcess, (DWORD)allocAddr + origCodeSize, hookCode, hookCodeSize)//写入hook代码
        || !WriteProcessCodeMemory(hProcess, (DWORD)allocAddr + origCodeSize + hookCodeSize, jmpCode, 5))//写入jmpcode
    {
        VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);//写入失败则释放空间
        return NULL;
    }
 
    //4. 修改目的地址处的代码  jmp xxx偏移 原始代码后才是需要执行的hook代码
    *(DWORD*)(jmpCode + 1) = ((DWORD)allocAddr + origCodeSize) - ((DWORD)desAddr + 5);
    WriteProcessCodeMemory(hProcess, desAddr, jmpCode, 5);//在源地址处写入跳转代码
    if (origCodeSize > 5)//原始代码长度大于5时nop多余字节
    {
        BYTE nopCode[5] = { 0x90,0x90,0x90,0x90,0x90 };
        if (!WriteProcessCodeMemory(hProcess, (DWORD)desAddr + 5, nopCode, origCodeSize - 5))
        {
            VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);//写入nopcode失败则释放空间并返回
            return NULL;
        }
    }
 
    //5. hook成功则返回hookCode所在地址
    return allocAddr;
}
 
//取消hook指定地址,写回原始代码并释放申请空间
BOOL UnHook(HANDLE hProcess, LPVOID desAddr, SIZE_T origCodeSize, LPVOID allocAddr) {
    BYTE origCode[10] = { 0 };
    //1. 从申请空间中读出原始代码
    if (!ReadProcessMemory(hProcess, allocAddr, origCode, origCodeSize, NULL))
        return FALSE;
    //2. 将原始代码写回目的地址
    if (!WriteProcessCodeMemory(hProcess, desAddr, origCode, origCodeSize))
        return FALSE;
    //3. 释放申请空间
    if (!VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE))
        return FALSE;
    return TRUE;
}
 
//获取某些项目的值
unsigned int getSomething(HANDLE handle, DWORD BaseAddr, unsigned int type) {
    unsigned int num = 0;
    DWORD addr = BaseAddr + 0x00355E0C;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    if (type == Sunlight)
        addr += 0x868;
    else
        addr += 0x950;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    addr += offsetTable[type];
    ReadProcessMemory(handle, (LPVOID)addr, &num, sizeof(DWORD), 0);
    return num;
}
 
//设置某些项目的值
BOOL setSomething(HANDLE handle, DWORD BaseAddr, unsigned int type, unsigned int num) {
    DWORD addr = BaseAddr + 0x00355E0C;
    ReadProcessMemory(handle, addr, &addr, sizeof(DWORD), NULL);
    if (type == Sunlight)
        addr += 0x868;
    else
        addr += 0x950;
    ReadProcessMemory(handle, (LPVOID)addr, &addr, sizeof(DWORD), NULL);
    addr += offsetTable[type];
    return WriteProcessMemory(handle, (LPVOID)addr, &num, sizeof(DWORD), 0);
}
 
//无限冷却
BOOL Uncooled(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char code[2] = { 0xeb,0x00 };
    return WriteProcessCodeMemory(hProcess, BaseAddr + 0x9ce02, code, 2);//jle 0x18修改为jmp $+2
}
 
//恢复冷却
BOOL RecoveryCooling(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char OriginalCode[2] = { 0x7E ,0x16 };//jmp $+2修改为jle 0x18
    return WriteProcessCodeMemory(hProcess, BaseAddr + 0x9ce02, OriginalCode, 2);
}
 
//无限阳光,锁定阳光为9999
BOOL UnlimitedSun(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char Code[3] = { 0x29,0xdb,0 };//cmp ebx,eax 修改为sub ebx,ebx   and ecx,0x32修改为and ecx,0
    BOOL flag;
    flag = setSomething(hProcess, BaseAddr, Sunlight, 9999);//修改阳光
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x27690, Code, 2);//修改阳光减少代码
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x3C0AB, &Code[2], 1);//修改阳光增加代码
    return flag;
}
 
//恢复阳光消耗
BOOL RecoverySunConsume(HANDLE hProcess, DWORD BaseAddr) {
    unsigned char OriginalCode[3] = { 0x3B,0xD8,0x32 };//sub ebx,ebx恢复为cmp ebx,eax and ecx,0恢复为and ecx,0x32
    BOOL flag = WriteProcessCodeMemory(hProcess, BaseAddr + 0x27690, OriginalCode, 2);//恢复阳光减少代码
    flag &= WriteProcessCodeMemory(hProcess, BaseAddr + 0x3C0AB, &OriginalCode[2], 1);//恢复阳光增加代码
    return flag;
}
 
//除雾
LPVOID DeFogByHook(HANDLE hProcess, LPVOID BaseAddr) {
 
    unsigned char hookCode[9] = {
        0xc7,0x01,0x00,0x00,0x00,0x00,  //mov [ecx],0
        0x83,0xc1,0x04                  //add ecx,0x4
    };
    //写hook代码进行hook
    return SetHook(hProcess, (DWORD)BaseAddr + 0x26173, hookCode, sizeof(hookCode), 5);
}
 
//恢复雾
BOOL RecoveryFogByUnHook(HANDLE hProcess, LPVOID BaseAddr, LPVOID allocAddr) {
    return UnHook(hProcess, (DWORD)BaseAddr + 0x26173, 5, allocAddr);
}
 
//创建远程线程向指定进程注入dll
BOOL InjectDllByRemoteThread(DWORD desProcId,WCHAR* dllPath) {
    //打开进程获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, desProcId);
    if (!hProcess)
        return FALSE;
 
    //申请空间
    DWORD pathSize = (wcslen(dllPath) + 1) * 2;
    LPVOID newMemAddr = VirtualAllocEx(hProcess, 0, pathSize, MEM_COMMIT, PAGE_READWRITE);
    if (!newMemAddr)
        return FALSE;
 
    //写入dll路径
    if (!WriteProcessMemory(hProcess, newMemAddr, dllPath, pathSize, NULL))
    {
        VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
        return FALSE;
    }
        
    //创建远程线程
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, newMemAddr, 0, NULL);
    if (!hThread)
    {
        VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
        return FALSE;
    }
 
    WaitForSingleObject(hThread, INFINITE);//等待线程信号,保证成功注入
 
    //回收资源
    VirtualFreeEx(hProcess, newMemAddr, 0, MEM_RELEASE);
    CloseHandle(hThread);
    CloseHandle(hProcess);
 
    //返回成功
    return TRUE;
}
 
//创建远程线程释放指定进程dll
BOOL UnLoadDllByRemoteThread(DWORD dwProcessId, LPCWSTR lpDllName)
{
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess == NULL)
        return FALSE;
 
    // 在目标进程中申请一块内存,并将需要卸载的DLL模块的名称写入该内存
    LPVOID lpRemoteDllName = VirtualAllocEx(hProcess, NULL, (wcslen(lpDllName) + 1) * sizeof(WCHAR), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (lpRemoteDllName == NULL)
    {
        CloseHandle(hProcess);
        return FALSE;
    }
    if (!WriteProcessMemory(hProcess, lpRemoteDllName, lpDllName, (wcslen(lpDllName) + 1) * sizeof(WCHAR), NULL))
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    //查找dll模块
    HMODULE hModules[1024],DesModule=NULL;
    DWORD dwSize = 0;
    if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &dwSize))
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    // 遍历模块列表,查找需要卸载的DLL模块
    for (DWORD i = 0; i < (dwSize / sizeof(HMODULE)); i++)
    {
        WCHAR szModuleName[MAX_PATH] = { 0 };
        if (GetModuleFileNameExW(hProcess, hModules[i], szModuleName, MAX_PATH) > 0)
        {
            // 获取模块句柄
            if (wcsicmp(szModuleName, lpDllName) == 0)
            {
                DesModule = hModules[i];
            }
        }
    }
    //没有查找到模块
    if (!DesModule) {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    // 在目标进程中创建远程线程,执行FreeLibrary函数
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, DesModule, 0, NULL);
    if (hThread == NULL)
    {
        VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
 
    // 等待线程执行完成
    WaitForSingleObject(hThread, INFINITE);
 
    // 关闭句柄
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, lpRemoteDllName, 0, MEM_RELEASE);
    CloseHandle(hProcess);
 
    return TRUE;
}
 
//以创建远程线程方式种植植物
BOOL GrowPlantByInjectCode(DWORD dwProcessId,DWORD BaseAddr,DWORD x,DWORD y,DWORD PlantType)
{
    BOOL bSuccess = FALSE;
    //1. 打开进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);   
    if (hProcess != NULL)
    {
        //2. 定义注入代码(函数)
 
        BYTE InjectCode[50] = {                     //汇编指令              //修正点偏移
            0x55,                                   //0 push ebp
            0x89, 0xE5,                             //1 mov ebp,esp
            0x60,                                   //3 pushad               
            0x68, 0xFF, 0xFF, 0xFF, 0xFF,           //4 push -1          
            0x68, 0x00, 0x00, 0x00, 0x00,           //9 push PlantType        //10    
            0xB8, 0x00, 0x00, 0x00, 0x00,           //14 mov eax,y             //15
            0x68, 0x00, 0x00, 0x00, 0x00,           //19 push x                //20
            0xB9, 0x00, 0x00, 0x00, 0x00,           //24 mov ecx,BaseAddr      //25
            0x8B, 0x89, 0x0C, 0x5E, 0x35, 0x00,     //29 mov ecx,[ecx+0x355E0C]
            0x8B, 0x89, 0x68, 0x08, 0x00, 0x00,     //35 mov ecx,[ecx+0x868]
            0x51,                                   //41 push ecx
            0xE8, 0x00, 0x00, 0x00, 0x00,           //42 call PlantFunc        //43     //被调方平栈
            0x61,                                   //47 popad
            0xC9,                                   //48 leave
            0xC3                                    //49 ret
        };
 
        //3. 申请空间用于存储代码
        DWORD  dwCodeSize = 50, desFunc = BaseAddr + 0x18D70;
        LPVOID lpRemoteCodeMem = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
        //4. 修正参数
        *(DWORD*)&InjectCode[10] = PlantType;
        *(DWORD*)&InjectCode[15] = y;
        *(DWORD*)&InjectCode[20] = x;
        *(DWORD*)&InjectCode[25] = BaseAddr;
        *(DWORD*)&InjectCode[43] = desFunc-((DWORD)lpRemoteCodeMem+42+5) ;
        //call指令与jmp类似,相对于当前指令的下一条指令计算偏移,offset=des-(source+5),减去call自身长度5
 
        if (lpRemoteCodeMem != NULL)
        {
            SIZE_T dwBytesWritten = 0;
            //5. 注入代码
            if (WriteProcessMemory(hProcess, lpRemoteCodeMem, InjectCode, dwCodeSize, &dwBytesWritten) &&
                dwBytesWritten == dwCodeSize)
            {
                //6. 创建远程线程执行代码
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteCodeMem,NULL, 0, NULL);
                if (hThread != NULL)
                {
                    //7. 等待线程信号
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    bSuccess = TRUE;
                }
            }
            //8. 执行完后释放空间
            VirtualFreeEx(hProcess, lpRemoteCodeMem, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
     
    return bSuccess;
}
 
//以创建远程线程方式种植僵尸
BOOL GrowZombieByInjectCode(DWORD dwProcessId,DWORD BaseAddr, DWORD x, DWORD y, DWORD ZombieType) {
 
    BOOL bSuccess = FALSE;
    //1. 打开进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess != NULL)
    {
        //2. 定义注入代码(函数)
 
        BYTE InjectCode[50] = {
            0x55,                                       //0 push ebp
            0x89, 0xE5,                                 //1 mov ebp,esp
            0x60,                                       //3 pushad
            0x68, 0x00, 0x00, 0x00, 0x00,               //4 push x
            0x68, 0x00, 0x00, 0x00, 0x00,               //9 push ZombieType
            0xB8, 0x00, 0x00, 0x00, 0x00,               //14 mov eax,y
            0xB9, 0x00, 0x00, 0x00, 0x00,               //19 mov ecx,BaseAddr
            0x8B, 0x89, 0x0C, 0x5E, 0x35, 0x00,         //24 mov ecx,[ecx+0x355E0C]
            0x8B, 0x89, 0x68, 0x08, 0x00, 0x00,         //30 mov ecx,[ecx+0x868]
            0x8B, 0x89, 0x78, 0x01, 0x00, 0x00,         //36 mov ecx,[ecx+0x178]
            0xE8, 0x00, 0x00, 0x00, 0x00,               //42 call PlantZombieFunc
            0x61,                                       //47 popad
            0xC9,                                       //48 leave
            0xC3                                        //49 ret
        };
 
        //3. 申请空间用于存储代码
        DWORD  dwCodeSize = 50, desFunc = BaseAddr + 0x35390; //种植僵尸函数
        LPVOID lpRemoteCodeMem = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
        //4. 修正参数
        *(DWORD*)&InjectCode[5] = x;
        *(DWORD*)&InjectCode[10] = ZombieType;
        *(DWORD*)&InjectCode[15] = y;
        *(DWORD*)&InjectCode[20] = BaseAddr;
        *(DWORD*)&InjectCode[43] = desFunc - ((DWORD)lpRemoteCodeMem + 42 + 5);//call指令与jmp类似,相对于当前指令的下一条指令计算偏移,要减去call长度5
 
        if (lpRemoteCodeMem != NULL)
        {
            SIZE_T dwBytesWritten = 0;
            //5. 注入代码
            if (WriteProcessMemory(hProcess, lpRemoteCodeMem, InjectCode, dwCodeSize, &dwBytesWritten) &&
                dwBytesWritten == dwCodeSize)
            {
                //6. 创建远程线程执行代码
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteCodeMem, NULL, 0, NULL);
                if (hThread != NULL)
                {
                    //7. 等待线程信号
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    bSuccess = TRUE;
                }
            }
            //8. 执行完后释放空间
            VirtualFreeEx(hProcess, lpRemoteCodeMem, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
 
    return bSuccess;
}
 
//设置卡槽植物
BOOL SetPlantCard(HANDLE hProcess,DWORD BaseAddr,DWORD nCard,DWORD plantType) {
    DWORD cardAddr = BaseAddr + 0x355E0C;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x868;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x15C;
    ReadProcessMemory(hProcess, cardAddr, &cardAddr, sizeof(DWORD), NULL);
    cardAddr += 0x5C+nCard*0x50;//卡槽偏移
    return WriteProcessMemory(hProcess, cardAddr, &plantType, sizeof(DWORD), NULL);
}
 
//选择菜单
void choiceMenu(HANDLE hProcess,DWORD Pid, LPVOID BaseAddr) {
    DWORD choice = 0;
    unsigned int num = 0;
    DWORD fogAddr = 0;
    unsigned int x, y, Type;
   while(1) {
        system("cls");
        printf("\t\t\t\tWelcome to PVZ Modifier!\n");
        printf("\t\t\t\t\t0.退出\n");
        printf("\t\t\t\t\t1.修改阳光数\n");
        printf("\t\t\t\t\t2.修改金钱数\n");
        printf("\t\t\t\t\t3.修改智慧树高\n");
        printf("\t\t\t\t\t4.修改巧克力数\n");
        printf("\t\t\t\t\t5.修改树肥\n");
        printf("\t\t\t\t\t6.修改花肥\n");
        printf("\t\t\t\t\t7.修改杀虫剂\n");
        printf("\t\t\t\t\t8.无限冷却\n");
        printf("\t\t\t\t\t9.恢复冷却\n");
        printf("\t\t\t\t\t10.无限阳光\n");
        printf("\t\t\t\t\t11.恢复阳光消耗\n");
        printf("\t\t\t\t\t12.除雾\n");
        printf("\t\t\t\t\t13.恢复雾\n");
        printf("\t\t\t\t\t14.种植植物\n");
        printf("\t\t\t\t\t15.生成僵尸\n");
 
        printf("\t\t\t\tPlease choose your option:[ ]\b\b");
        scanf("%d", &choice);
 
        switch(choice){
        case 0:
            return;
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
            printf("\t\t\t\tPlease input Num:");
            scanf("%d", &num);
            setSomething(hProcess, BaseAddr, choice - 1, num);
            break;
        case 8:
            Uncooled(hProcess, BaseAddr);
            break;
        case 9:
            RecoveryCooling(hProcess, BaseAddr);
            break;
        case 10:
            UnlimitedSun(hProcess,BaseAddr);
            break;
        case 11:
            RecoverySunConsume(hProcess, BaseAddr);
            break;
        case 12:
            fogAddr=(DWORD)DeFogByHook(hProcess, BaseAddr);
            break;
        case 13:
            RecoveryFogByUnHook(hProcess, BaseAddr,fogAddr );
            break;
        case 14:
            printf("请输入X Y PlantType: ");
            scanf("%d%d%d", &x, &y, &Type);
            GrowPlantByInjectCode(Pid, BaseAddr,x,y,Type );
            break;
        case 15:
            printf("请输入X Y ZombieType: ");
            scanf("%d%d%d", &x, &y, &Type);
            GrowZombieByInjectCode(Pid, BaseAddr, x, y, Type);
            break;
        }
    }
}
 
 
int main() {
 
    //获取进程pid
    DWORD Pid = GetProcessIdByName(L"PlantsVsZombies.exe");
    //打开进程,获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE,Pid);
    //获取进程基址
    DWORD BaseAddr=GetModuleBaseAddress(Pid, L"PlantsVsZombies.exe");
 
 
    choiceMenu(hProcess, Pid, BaseAddr);
 
 
    //dll注入
    //InjectDllByRemoteThread(Pid, L"E:\\MyProject\\vsProjects\\Project1\\Debug\\DllPlant3.dll");
    //int op = 1;
    //printf("输入0卸载dll:");
    //scanf("%d", &op);
    //if(op==0)
    //    UnLoadDllByRemoteThread(Pid, L"E:\\MyProject\\vsProjects\\Project1\\Debug\\DllPlant3.dll");//加载完dll之后释放掉
 
    CloseHandle(hProcess);
    return 0;
}
#include<stdio.h>
#include<windows.h>
#include <tlhelp32.h>
#include <string.h>
#include <shlwapi.h>
#include <psapi.h>
 
enum Type {
    Sunlight, Money, TreeHeight, Chocolate, TreeFood, FlowerFood, Insecticide
};
unsigned int offsetTable[10] = { 0x5578,0x50,0x11c,0x250,0x258,0x220,0x224 };
 
 
// 根据进程名获取进程ID
DWORD GetProcessIdByName(const wchar_t* processName) {
 
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);// 创建一个进程快照
    if (snapshot == INVALID_HANDLE_VALUE) {
        return 0;// 如果创建失败,返回 0
    }
 
    // 定义一个 PROCESSENTRY32 结构体,用于存储进程信息
    PROCESSENTRY32 processEntry = { 0 };
    processEntry.dwSize = sizeof(PROCESSENTRY32);   //必须初始化,否则调用Process32First会失败
    if (!Process32First(snapshot, &processEntry)) {
        CloseHandle(snapshot);
        return 0;// 如果获取第一个进程信息失败,关闭进程快照句柄并返回 0
    }
 
    // 遍历进程列表
    do {
        wchar_t currentProcessName[MAX_PATH];                           // 获取当前进程的名称
        wcscpy_s(currentProcessName, MAX_PATH, processEntry.szExeFile); //szExeFile存储了进程对应可执行文件的名称
        if (wcscmp(currentProcessName, processName) == 0) {
            CloseHandle(snapshot);                                  // 如果当前进程名称和指定的进程名称相同,返回进程 ID
            return processEntry.th32ProcessID;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 21
支持
分享
最新回复 (18)
雪    币: 914
活跃值: (2448)
能力值: ( LV5,RANK:68 )
在线值:
发帖
回帖
粉丝
2

2023-8-3 15:30
1
雪    币: 154
活跃值: (213)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
好文章
2023-8-3 16:16
0
雪    币: 4037
活跃值: (4777)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
为干货文章点赞
2023-8-3 21:03
0
雪    币: 6186
活跃值: (4196)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2023-8-3 23:22
0
雪    币: 3369
活跃值: (2688)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
分析很透彻!
2023-8-4 08:36
0
雪    币: 9978
活跃值: (4381)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享。研究得很透啊
2023-8-4 11:15
0
雪    币: 2948
活跃值: (30846)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2023-8-4 11:16
1
雪    币: 210
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
真详细,又学到了
2023-8-4 12:20
0
雪    币: 5768
活跃值: (3839)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
整个目录都看懂了,感谢
2023-8-4 13:17
0
雪    币: 14960
活跃值: (4090)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
老表,请把植物大战僵尸原程序或下载链接提供一下,以便对照学习,谢谢
2023-8-4 15:47
0
雪    币: 46
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
大佬 可以将这个版本的游戏链接分享一下吗  找了好久也没找到  呜呜~~~
2023-8-4 16:03
0
雪    币: 1899
活跃值: (2938)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
13
示例PVZ年度中文加强版链接:https://pan.baidu.com/s/1Yh4tSpy0wyMhmjmQJlFCEQ?pwd=j1sa 
提取码:j1sa
2023-8-4 16:10
0
雪    币: 1899
活跃值: (2938)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
小菜阿龙 大佬 可以将这个版本的游戏链接分享一下吗 找了好久也没找到 呜呜~~~
评论区自取
2023-8-4 16:11
0
雪    币: 56
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
梦开始的地方
2023-8-4 17:02
0
雪    币: 6076
活跃值: (5480)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
16
写的不错,排版也好,顶一下!
2023-8-10 11:25
0
雪    币: 51
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
看起来不错,插眼到时候学习下
2023-8-13 02:36
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
没有GUI
2023-8-16 10:26
0
雪    币: 2277
活跃值: (5005)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
666
2023-8-22 10:33
0
游客
登录 | 注册 方可回帖
返回
//