import pymem
import pymem.process
import tkinter as tk
from tkinter import ttk, messagebox
import psutil
import threading
import time
class PVZHybridCheater:
def __init__(self, root):
self.root = root
self.root.title("PVZ 植物大战僵尸杂交版修改器 (指针链版)")
self.root.geometry("450×480")
self.root.resizable(False, False)
self.pm = None
self.process_id = None
# 指针链常量,来自 ZJamss/PVZ_Cheating 项目
self.POINTER_CHAINS = {
"阳光": (0x006A9F38, [0x768, 0x5560]),
"银币": (0x006A9EC0, [0x82C, 0x208]),
"金币": (0x006A9EC0, [0x82C, 0x20C]),
"钻石": (0x006A9EC0, [0x82C, 0x210]),
}
# 冷却功能涉及修改代码,纯读写内存无法实现,这里暂不包含。
self.create_widgets()
def create_widgets(self):
ttk.Label(self.root, text="植物大战僵尸 杂交版修改器", font=("SimHei", 12, "bold")).pack(pady=10)
# 进程连接
conn_frame = ttk.LabelFrame(self.root, text="游戏进程")
conn_frame.pack(fill="x", padx=15, pady=5)
self.status_var = tk.StringVar(value="未连接")
ttk.Label(conn_frame, textvariable=self.status_var).pack(side="left", padx=5)
ttk.Button(conn_frame, text="连接游戏", command=self.connect_process).pack(side="right", padx=5)
# 修改区域
for item in ["阳光", "银币", "金币", "钻石"]:
self._create_modify_widget(item)
def _create_modify_widget(self, item_name):
frame = ttk.LabelFrame(self.root, text=item_name)
frame.pack(fill="x", padx=15, pady=5)
value_var = tk.StringVar()
# 动态创建组件并保存引用
setattr(self, f"{item_name}_entry", ttk.Entry(frame, textvariable=value_var, width=15))
getattr(self, f"{item_name}_entry").pack(side="left", padx=5)
ttk.Button(frame, text="读取", command=lambda n=item_name: self.read_value(n)).pack(side="left", padx=2)
ttk.Button(frame, text="修改", command=lambda n=item_name: self.write_value(n)).pack(side="left", padx=2)
ttk.Button(frame, text="锁定", command=lambda n=item_name: self.start_lock_thread(n)).pack(side="left", padx=2)
setattr(self, f"{item_name}_var", value_var)
def connect_process(self):
try:
# 杂交版进程名可能是 popcapgame1.exe 或 plantsvszombies.exe
target_names = ["popcapgame1.exe", "plantsvszombies.exe"]
pid = None
for proc in psutil.process_iter(['pid', 'name']):
if proc.info['name'] and proc.info['name'].lower() in [n.lower() for n in target_names]:
pid = proc.info['pid']
break
if not pid:
messagebox.showerror("错误", "未找到游戏进程,请先启动植物大战僵尸杂交版")
return
self.pm = pymem.Pymem(pid)
self.process_id = pid
self.status_var.set(f"已连接: {pid}")
messagebox.showinfo("成功", f"已连接到进程 PID: {pid}")
except Exception as e:
messagebox.showerror("连接失败", str(e))
def get_address(self, item_name):
"""解析指针链获取最终数据地址"""
if not self.pm:
messagebox.showwarning("警告", "请先连接游戏进程")
return None
base, offsets = self.POINTER_CHAINS[item_name]
try:
# 读取基址指向的值
addr = self.pm.read_int(base)
# 逐级解析偏移
for offset in offsets[:-1]:
addr = self.pm.read_int(addr + offset)
# 最后一个偏移直接加到地址上
final_addr = addr + offsets[-1]
return final_addr
except Exception as e:
print(f"解析 {item_name} 地址失败: {e}")
return None
def read_value(self, item_name):
addr = self.get_address(item_name)
if addr:
try:
value = self.pm.read_int(addr)
getattr(self, f"{item_name}_var").set(str(value))
except Exception as e:
messagebox.showerror("读取失败", str(e))
def write_value(self, item_name):
addr = self.get_address(item_name)
if not addr:
return
try:
entry_var = getattr(self, f"{item_name}_var")
value = int(entry_var.get())
self.pm.write_int(addr, value)
messagebox.showinfo("成功", f"{item_name} 已修改为 {value}")
except ValueError:
messagebox.showerror("错误", "请输入有效的整数")
except Exception as e:
messagebox.showerror("修改失败", str(e))
def start_lock_thread(self, item_name):
"""启动锁定线程,持续写入数值"""
if not self.pm:
messagebox.showwarning("警告", "请先连接游戏进程")
return
try:
target_value = int(getattr(self, f"{item_name}_var").get())
except ValueError:
messagebox.showerror("错误", "请先读取或输入一个有效的数值")
return
def lock_loop():
addr = self.get_address(item_name)
if not addr:
return
while True:
try:
self.pm.write_int(addr, target_value)
time.sleep(0.1) # 每0.1秒写入一次
except Exception:
# 如果地址失效(游戏关闭或换关),退出循环
break
# 使用守护线程,避免程序无法退出
thread = threading.Thread(target=lock_loop, daemon=True)
thread.start()
messagebox.showinfo("锁定中", f"{item_name} 已开始锁定为 {target_value}\\n再次点击可重新锁定。")
if __name__ == "__main__":
root = tk.Tk()
app = PVZHybridCheater(root)
root.mainloop()




