植物大战僵尸简单外挂原理及实现

单机游戏外挂的基本原理
游戏一旦运行,其中的数据就会进入到内存中,比如一些攻击力,血量等等。
以植物大战僵尸为例,一个比较重要的数据就是阳光值,这个值就一定存在与内存中,如果我们能够获得阳光值在内存中的地址,然后修改这个地址的内容,就可以轻松的修改游戏中的阳光值了。

如何找到要修改数据的地址
绝大多数单机游戏的数据虽然每次运行时所在地址不一样,但都是以一个基址为基础,加上一定的偏移量后得到这个数据的地址。

寻找地址的过程
通过ce找到阳光值的地址是179c6f98
然后得到add [eax+00005560], ecx
让eax寄存器中存放的地址加上00005560后的地址的内容加上ecx寄存器中的内容,并放回eax+00005560地址中。
因为ecx的内容是25(也就是一个阳光的值),所以可以大体上判断ecx就是阳光值,而存储阳光值的地址是由eax+00005560得到的。
得到eax 地址为179C1A38。即eax(179C1A38) + 00005560 = 179C6F98

同理edi(0255A010) + 00000768 = esi(179C1A38)

综上:edi(0255A010)先偏移 00000768 ,在偏移 00005560后得到179C6F98即阳光的地址。
最后验证一样,得到的结论是正确的, 到这里分析完毕,剩下的就是代码实现了。

代码实现

import win32gui
import win32process
import win32api
import ctypes
import tkinter
from tkinter import ttk


def operate(sun_count):
    # 获取窗口句柄
    window_handle = win32gui.FindWindow(None, "植物大战僵尸中文版")

    # 获取进程id
    process_id = win32process.GetWindowThreadProcessId(window_handle)[1]

    # 获取进程句柄
    process_handle = win32api.OpenProcess(0x1F0FFF, False, process_id)
    # print(process_handle)

    # 利用kernel32.dll来读取数据和把数据写入内存
    kernel32 = ctypes.windll.LoadLibrary(r"C:\Windows\System32\kernel32.dll")

    # 声明一个c语言中int类型的变量
    data1 = ctypes.c_int()
    # 读取0x006A9EC0地址的内容
    kernel32.ReadProcessMemory(int(process_handle), 0x006A9EC0, ctypes.byref(data1), 4, None)
    # print(data1.value)

    data2 = ctypes.c_int()
    kernel32.ReadProcessMemory(int(process_handle), data1.value+0x768, ctypes.byref(data2), 4, None)
    # print(data2.value)

    data3 = ctypes.c_int()
    kernel32.ReadProcessMemory(int(process_handle), data2.value+0x5560, ctypes.byref(data3), 4, None)
    # print(data3.value)

    # sun = input("输入阳光值:")
    # 通过sun_count.get()将读取的IntVar类型转变成int类型
    kernel32.WriteProcessMemory(int(process_handle), data2.value+0x5560, ctypes.byref(ctypes.c_int(sun_count.get())), 4, None)


def main():
    # 创建GUI界面
    window = tkinter.Tk()
    window.title("title")
    window.maxsize(300, 200)
    window.minsize(300, 200)

    lable = tkinter.Label(window, text="输入阳光值", font=("", 20))
    lable.place(x=0, y=0)

    sun_count = tkinter.IntVar()
    entry = tkinter.Entry(window, textvariable=sun_count)
    entry.place(x=0, y=30)

    button = ttk.Button(window, text="修改", command=lambda: operate(sun_count))
    button.place(x=180, y=0, width=100, height=50)

    window.mainloop()


if __name__ == "__main__":
    main()

你可能感兴趣的:(课程设计/实践)