import threading import time import tkinter as tk from tkinter import messagebox import win32gui import win32process import win32api import ctypes kernel32 = ctypes.windll.kernel32 PROCESS_ALL_ACCESS = (0x000F0000 | 0x00100000 | 0xFFF) running = False # 定义修改阳光和冷却的函数 def change_sun(Phand, sun_num): sun_date = ctypes.c_long() # kernel32.ReadProcessMemory(int(Phand), 0x03F8A9C0, ctypes.byref(sun_date), 4, None) kernel32.ReadProcessMemory(int(Phand), 0x6A9EC0, ctypes.byref(sun_date), 4, None) """ 0x03F8A9C0 是基础地址,假设这里存储了一个指向阳光数值的指针。 ctypes.byref(sun_date) 是一个指向sun_date变量的引用,用于接收从内存中读取的数据。 4 表示读取数据的大小,这里是4字节,即一个整数。 None 是一个可选参数,用来接收实际读取的字节数,但在这里我们不关心这个值。 """ kernel32.ReadProcessMemory(int(Phand), sun_date.value + 0x768, ctypes.byref(sun_date), 4, None) # 写入新的数值 new_sun_date = ctypes.c_long(sun_num) print(sun_date) print(new_sun_date) return kernel32.WriteProcessMemory(int(Phand), sun_date.value + 0x5560, ctypes.byref(new_sun_date), 4, None) def change_cooling(Phand, cooling): """ 修改冷却 :param Phand: :param cooling: 0 冷却 1 无冷却 :return: """ time.sleep(0.5) cooling_data = ctypes.c_long() kernel32.ReadProcessMemory(int(Phand), 0x6A9EC0, ctypes.byref(cooling_data), 4, None) kernel32.ReadProcessMemory(int(Phand), cooling_data.value + 0x768, ctypes.byref(cooling_data), 4, None) kernel32.ReadProcessMemory(int(Phand), cooling_data.value + 0x144, ctypes.byref(cooling_data), 4, None) # kernel32.ReadProcessMemory(int(Phand),cooling_data.value,ctypes.byref(cooling_data),4,None) new_cooling_date = ctypes.c_long(cooling) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x70, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0xC0, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x110, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x160, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x1B0, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x200, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x250, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x2A0, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x2F0, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x340, ctypes.byref(new_cooling_date), 4, None) # 可以看出,从第二个地址开始,每个地址与其前一个地址之间的差值是固定的,为0x50(80)。这种模式表明,每个卡槽的冷却时间数据在内存中是以固定间隔排列的。 # # 推测剩余卡槽的冷却时间地址 # 既然已知前十个卡槽的冷却时间地址遵循0x50的增量规律,那么我们可以轻易地推测出后五个卡槽的冷却时间地址: # # 第11个卡槽:0x340 + 0x50 = 0x390 (944) # 第12个卡槽:0x390 + 0x50 = 0x3E0 (992) # 第13个卡槽:0x3E0 + 0x50 = 0x430 (1072) # 第14个卡槽:0x430 + 0x50 = 0x480 (1168) # 第15个卡槽:0x480 + 0x50 = 0x4D0 (1232) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x390, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x3E0, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x430, ctypes.byref(new_cooling_date), 4, None) kernel32.WriteProcessMemory(int(Phand), cooling_data.value + 0x480, ctypes.byref(new_cooling_date), 4, None) # 定义检测游戏是否运行的函数 def find_game_window(): global running hwnd = win32gui.FindWindow(None, game_title_entry.get()) if hwnd == 0: messagebox.showinfo("提示", "植物大战僵尸没有运行,请先启动游戏!") # 将启动按钮设置为禁用状态 # start_button.config(state=tk.DISABLED) # 如果正在进行修改,则停止 if running: running = False start_button.config(text="启动") return None else: running = True _, pid = win32process.GetWindowThreadProcessId(hwnd) Phand = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid) # 如果游戏开始运行,重新激活启动按钮 start_button.config(state=tk.NORMAL) return Phand # 定义修改阳光值的函数 def modify_sunlight(): sunlight_value = int(sunlight_entry.get()) Phand = find_game_window() if Phand: change_sun(Phand, sunlight_value) # 定义修改冷却时间的函数 def modify_cooling(): cooling_enabled = cooling_var.get() Phand = find_game_window() if Phand: change_cooling(Phand, cooling_enabled) # 定义开始/停止修改的函数 def start_stop_modification(): global running if running: running = False start_button.config(text="启动") else: running = True start_button.config(text="启动中") modification_thread = threading.Thread(target=modification_loop) modification_thread.start() def modification_loop(): while running: modify_sunlight() if cooling_var.get(): modify_cooling() time.sleep(0.1) # 防止CPU占用过高 def get_visible_windows(): """获取所有可见窗口的标题和PID""" results = [] def foreach_window(hwnd, _): if win32gui.IsWindowVisible(hwnd): title = win32gui.GetWindowText(hwnd) if title: _, pid = win32process.GetWindowThreadProcessId(hwnd) results.append((title, pid)) return True win32gui.EnumWindows(foreach_window, None) return results def auto_fill_title(window_list, game_title): """尝试自动识别游戏窗口标题并填充""" for title, _ in get_visible_windows(): if "植物大战僵尸" in title and "修改器" not in title: game_title.set(title) break def update_window_list(window_list, game_title): """更新窗口列表并自动填充游戏窗口标题""" window_list.delete(0, tk.END) # 清空列表 for title, pid in get_visible_windows(): window_list.insert(tk.END, f"{title} (PID: {pid})") # 插入新条目 auto_fill_title(window_list, game_title) # 尝试自动填充游戏标题 def enable_start_button(start_button, game_title): """当游戏标题非空时启用启动按钮""" if game_title.get(): start_button.config(state=tk.NORMAL) else: start_button.config(state=tk.DISABLED) if __name__ == '__main__': running = False # 创建主窗口 root = tk.Tk() root.title("植物大战僵尸修改器") root.resizable(False, False) # 创建阳光值输入框 sunlight_label = tk.Label(root, text="阳光值:") sunlight_label.grid(row=0, column=0, padx=(10, 5), pady=10) sunlight_entry = tk.Entry(root) sunlight_entry.insert(0, "9000") sunlight_entry.grid(row=0, column=1, padx=(5, 10), pady=10) # 创建冷却时间复选框 cooling_label = tk.Label(root, text="无冷却:") cooling_label.grid(row=1, column=0, padx=(10, 5), pady=10) cooling_var = tk.IntVar() cooling_checkbutton = tk.Checkbutton(root, variable=cooling_var) cooling_checkbutton.grid(row=1, column=1, padx=(5, 10), pady=10) # 创建开始/停止按钮 start_button = tk.Button(root, text="启动", command=start_stop_modification) start_button.grid(row=2, columnspan=2, padx=10, pady=10) # 添加窗口列表框 window_list = tk.Listbox(root, height=5) window_list.grid(row=0, column=2, rowspan=3, padx=(10, 10), pady=10) # 添加更新窗口列表的按钮 update_button = tk.Button(root, text="刷新窗口列表", command=lambda: update_window_list(window_list, game_title)) update_button.grid(row=3, column=2, padx=10, pady=10) # 创建游戏标题输入框 game_title_label = tk.Label(root, text="游戏窗口标题:") game_title_label.grid(row=3, column=0, padx=(10, 5), pady=10) game_title = tk.StringVar() game_title_entry = tk.Entry(root, textvariable=game_title) game_title_entry.grid(row=3, column=1, padx=(5, 10), pady=10) game_title.trace("w", lambda *args: enable_start_button(start_button, game_title)) # 监听变化 # 确保开始按钮初始状态为禁用 start_button.config(state=tk.DISABLED) root.mainloop()