使用Python對植物大戰殭屍學習研究
阿新 • • 發佈:2020-10-15
根據上一篇 使用Python讀寫遊戲1 中,使用Python win32庫,對一款遊戲進行了讀記憶體 操作。
今天來寫一下對記憶體進行寫的操作
正文
要進行32位的讀寫,首先了解一下要用到的幾個函式,通過百度找到的,大多都是C/C++的資料。
更詳細的分析看上一篇。
寫入函式 是 WriteProcessMemory
此函式能寫入某一程序的記憶體區域(直接寫入會出Access Violation錯誤,故需此函式)。
VC++宣告
BOOL WriteProcessMemory( HANDLE hProcess,//要修改的程序記憶體的控制代碼。控制代碼必須具有對程序的程序_vm_寫和程序_vm_操作的訪問許可權 LPVOID lpBaseAddress,//指向寫入資料的指定程序中的基地址的指標。在進行資料傳輸之前,系統將驗證指定大小的基址和記憶體中的所有資料都可用於寫訪問,如果無法訪問,則函式將失敗。 LPVOID lpBuffer,//指向緩衝區的指標,其中包含要在指定程序的地址空間中寫入的資料 DWORD nSize,//要寫入指定程序的位元組數。 LPDWORD lpNumberOfBytesWritten//指向接收傳輸到指定程序的位元組數的變數的指標。此引數是可選的。如果lpNumberOfBytesWritten是零,則忽略該引數。 );
返回值
如果函式成功,則返回值為非零
如果函式失敗,則返回值為0(零)。若要獲取擴充套件錯誤資訊,請呼叫GetLastError,如果請求的寫操作跨入程序中無法訪問的區域,則函式將失敗。
對單機植物大戰殭屍進行讀取與寫入操作
對植物大戰殭屍分析,請看
首先是對陽光數量的讀取
陽光的基址偏移是:
陽光:PlantsVsZombies.exe+2A9EC0+768+5560
不能直接讀PlantsVsZombies.exe+2A9EC0,所以把該值新增到CE中,檢視位址列中的十六進位制值 006A9EC0
讀寫操作,與上一篇文章寫法相似
# -*- coding: utf-8 -*- import win32process#程序模組 from win32con import PROCESS_ALL_ACCESS #Opencress 許可權 import win32api#呼叫系統模組 import ctypes#C語言型別 from win32gui import FindWindow#介面 def GetProcssID(address,bufflength): pid = ctypes.c_ulong() kernel32 = ctypes.windll.LoadLibrary("kernel32.dll") hwnd = FindWindow(None,u"植物大戰殭屍中文版") ReadProcessMemory = kernel32.ReadProcessMemory hpid, pid = win32process.GetWindowThreadProcessId(hwnd) hProcess = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid) addr = ctypes.c_ulong() ReadProcessMemory(int(hProcess), address, ctypes.byref(addr), bufflength, None) win32api.CloseHandle(hProcess) return addr.value def main(): sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4) print ("陽光的數量:%d" % sun) if __name__ == '__main__': main()
sun 分解寫法:
def main():
ret = GetProcssID(0x006A9EC0,4)
ret2 = GetProcssID(ret+0x768,4)
sun = GetProcssID(ret2+0x5560,4)
print ("陽光的數量:%d" % sun)
#sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
寫
根據之前的分析,植物大戰殭屍可以開啟自動收集功能。具體的地址是
自動收集:PlantsVsZombies.exe+3158B 初始值:5274496 修改後:22051712 十六進位制:0043158B
宣告一個函式
def WriteMemeryInt(_address,Data):
hGameHandle = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
WriteProcessInt = kernel32.WriteProcessMemory // 從kernel32動態連結庫中呼叫這個函式
WriteProcessInt(int(hGameHandle),_address,ctypes.byref(ctypes.c_ulong(Data)),4,None)
return Data
程式碼分析:
WriteProcessInt(int(hGameHandle),_address,ctypes.byref(ctypes.c_ulong(Data)),4,None)
BOOL WriteProcessInt(
int(hGameHandle), //傳入的控制代碼
_address, //要寫入的地址
ctypes.byref(ctypes.c_ulong(Data)), //要寫入的資料
4, //要寫入指定程序的位元組數。
None //指向接收傳輸到指定程序的位元組數的變數的指標。此引數是可選的。如果lpNumberOfBytesWritten是零,則忽略該引數。
);
修改植物大戰殭屍陽光數量
def _modifySunshine():
sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
sun_write = WriteMemeryInt(GetProcssID( GetProcssID( 0x006A9EC0, 4) + 0x768,4) + 0x5560, 100)
print("修改前陽光的數量:" , sun)
if sun_write:
print("###################修改陽光數量成功##############################")
sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
print("修改後陽光的數量:" , sun)
else:
print("###################修改陽光數量失敗,錯誤資訊:##################",GetLastError)
sun_write 分解寫法:
def _modifySunshine():
ret = GetProcssID(0x006A9EC0, 4)
ret2 = GetProcssID(ret + 0x768, 4)
sun_write = WriteMemeryInt(ret2+0x5560,100)
#ret2+0x5560 要寫入的地址,不能在GetProcessID讀取,不然寫入的地址就不正確
#100 為修改的數量。
if sun_write:
print("###################修改陽光數量成功##############################")
else:
print("###################修改陽光數量失敗,錯誤資訊:##################",GetLastError)
執行程式碼
# -*- coding: utf-8 -*-
import win32process#程序模組
from win32con import PROCESS_ALL_ACCESS #Opencress 許可權
import win32api#呼叫系統模組
import ctypes#C語言型別
from win32gui import FindWindow#介面
def GetProcssID(address,bufflength):
pid = ctypes.c_ulong()
kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")
hwnd = FindWindow(None,u"植物大戰殭屍中文版")
ReadProcessMemory = kernel32.ReadProcessMemory
hpid, pid = win32process.GetWindowThreadProcessId(hwnd)
hProcess = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
addr = ctypes.c_ulong()
ReadProcessMemory(int(hProcess), address, ctypes.byref(addr), bufflength, None)
win32api.CloseHandle(hProcess)
return addr.value
def WriteMemeryInt(_address,Data):
hGameHandle = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
WriteProcessInt = kernel32.WriteProcessMemory // 從kernel32動態連結庫中呼叫這個函式
WriteProcessInt(int(hGameHandle),_address,ctypes.byref(ctypes.c_ulong(Data)),4,None)
return Data
def _modifySunshine():
sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
sun_write = WriteMemeryInt(GetProcssID(GetProcssID( 0x006A9EC0, 4) + 0x768,4) + 0x5560, 100)
print("修改前陽光的數量:" , sun)
if sun_write:
print("###################修改陽光數量成功##############################")
sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
print("修改後陽光的數量:" , sun)
else:
print("###################修改陽光數量失敗,錯誤資訊:##################",GetLastError)
def main():
_modifySunshine()
if __name__ == '__main__':
main()
基本程式碼就這些了,接下來按照我寫C的格式,把程式碼格式改一下,因為看起來真的挺亂的
先把FindWindow 等基礎操作用函式給封裝
# -*- coding: utf-8 -*-
import win32process#程序模組
from win32con import PROCESS_ALL_ACCESS #Opencress 許可權
import win32api#呼叫系統模組
import ctypes#C語言型別
from win32gui import FindWindow#介面
kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")
GetLastError = kernel32.GetLastError
def _GetProcessId(className,windowName):
hGameWindow = FindWindow(className, windowName)
pid = win32process.GetWindowThreadProcessId(hGameWindow)[1]
return pid
def _GetPorcessHandle(pid):
hGameHandle = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
return hGameHandle
def _ReadMemeryInt(hGameHandle,_address,bufflength):
addr = ctypes.c_ulong()
ReadProcessInt = kernel32.ReadProcessMemory
ReadProcessInt(int(hGameHandle), _address, ctypes.byref(addr), bufflength, None)
return addr.value
def WriteMemeryInt(hGameHandle,_address,Data):
WriteProcessInt = kernel32.WriteProcessMemory
WriteProcessInt(int(hGameHandle),_address,ctypes.byref(ctypes.c_ulong(Data)),4,None)
return Data
def main():
ProcessId = _GetProcessId(None,u"植物大戰殭屍中文版")
_hGameHandle = _GetPorcessHandle(ProcessId)
win32api.CloseHandle(_hGameHandle)
if __name__ == '__main__':
main()
在開始寫功能,先是讀取陽光數量和修改陽光數量:
def _modifySunshine(hGameHandle):
sun = _ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle,0x006A9EC0, 4) + 0x768, 4) + 0x5560, 4)
sun_write = WriteMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle, _ReadMemeryInt(hGameHandle, 0x006A9EC0, 4) + 0x768,4) + 0x5560, 100)
print("修改前陽光的數量:" , sun)
if sun_write:
print("###################修改陽光數量成功##############################")
sun = _ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle, _ReadMemeryInt(hGameHandle, 0x006A9EC0, 4) + 0x768,4) + 0x5560, 4)
print("修改後的陽光數量:", sun)
else:
print("###################修改陽光數量失敗,錯誤資訊:##################",GetLastError)
接著,根據分析,有自動收集陽光功能,基址是:
自動收集:PlantsVsZombies.exe+3158B 初始值:5274496 修改後:22051712
十六進位制:0043158B
def _collectSunshine(hGameHandle):
collect = WriteMemeryInt(hGameHandle,0x0043158B,22051712)
if collect:
print("###################啟動自動收集功能成功#########################")
else:
print("###################修改自動收集功能失敗,錯誤資訊:##################",GetLastError)
接下來是秒殺功能,因為不一定每次都守得住
普通殭屍秒殺基址:
秒殺普通殭屍: PlantsVsZombies.exe+13178A 初始值:1284214911 修改後:1284214928
十六進位制:0053178A
def _Seckill(hGameHandle):
seckill = WriteMemeryInt(hGameHandle,0x0053178A,1284214928)
if seckill:
print("###################啟動秒殺普通殭屍功能成功#########################")
else:
print("###################修改秒殺功能失敗,錯誤資訊:#########################",GetLastError)
除了普通殭屍,還有頭盔殭屍:
頭盔殭屍基址:
秒殺帶護甲: PlantsVsZombies.exe+13186D 初始值:1347618942 修改後:1347653776
十六進位制:0053186D
def _SecKillHelmet(hGameHandle):
seckillHelemet = WriteMemeryInt(hGameHandle,0x53186D ,1347653776)
if seckillHelemet:
print("###################啟動秒殺頭盔殭屍功能成功#########################")
else:
print("###################修改頭盔殭屍秒殺功能失敗,錯誤資訊:#################",GetLastError)
完整程式碼:
# -*- coding: utf-8 -*-
import win32process#程序模組
from win32con import PROCESS_ALL_ACCESS #Opencress 許可權
import win32api#呼叫系統模組
import ctypes#C語言型別
from win32gui import FindWindow#介面
kernel32 = ctypes.windll.LoadLibrary("kernel32.dll")
GetLastError = kernel32.GetLastError
def _GetProcessId(className,windowName):
hGameWindow = FindWindow(className, windowName)
pid = win32process.GetWindowThreadProcessId(hGameWindow)[1]
return pid
def _GetPorcessHandle(pid):
hGameHandle = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
return hGameHandle
def _ReadMemeryInt(hGameHandle,_address,bufflength):
addr = ctypes.c_ulong()
ReadProcessInt = kernel32.ReadProcessMemory
ReadProcessInt(int(hGameHandle), _address, ctypes.byref(addr), bufflength, None)
return addr.value
def WriteMemeryInt(hGameHandle,_address,Data):
WriteProcessInt = kernel32.WriteProcessMemory
WriteProcessInt(int(hGameHandle),_address,ctypes.byref(ctypes.c_ulong(Data)),4,None)
return Data
def _modifySunshine(hGameHandle):
sun = _ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle,0x006A9EC0, 4) + 0x768, 4) + 0x5560, 4)
sun_write = WriteMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle, _ReadMemeryInt(hGameHandle, 0x006A9EC0, 4) + 0x768,4) + 0x5560, 100)
print("修改前陽光的數量:" , sun)
if sun_write:
print("###################修改陽光數量成功##############################")
sun = _ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle, _ReadMemeryInt(hGameHandle, 0x006A9EC0, 4) + 0x768,4) + 0x5560, 4)
print("修改後的陽光數量:", sun)
else:
print("###################修改陽光數量失敗,錯誤資訊:##################",GetLastError)
def _collectSunshine(hGameHandle):
collect = WriteMemeryInt(hGameHandle,0x0043158B,22051712)
if collect:
print("###################啟動自動收集功能成功#########################")
else:
print("###################修改自動收集功能失敗,錯誤資訊:##################",GetLastError)
def _Seckill(hGameHandle):
seckill = WriteMemeryInt(hGameHandle,0x0053178A,1284214928)
if seckill:
print("###################啟動秒殺普通殭屍功能成功#########################")
else:
print("###################修改秒殺功能失敗,錯誤資訊:#########################",GetLastError)
def _SecKillHelmet(hGameHandle):
seckillHelemet = WriteMemeryInt(hGameHandle,0x53186D ,1347653776)
if seckillHelemet:
print("###################啟動秒殺頭盔殭屍功能成功#########################")
else:
print("###################修改頭盔殭屍秒殺功能失敗,錯誤資訊:#################",GetLastError)
def main():
ProcessId = _GetProcessId(None,u"植物大戰殭屍中文版")
_hGameHandle = _GetPorcessHandle(ProcessId)
_modifySunshine(_hGameHandle)
_collectSunshine(_hGameHandle)
_Seckill(_hGameHandle)
_SecKillHelmet(_hGameHandle)
win32api.CloseHandle(_hGameHandle)
if __name__ == '__main__':
main()
執行程式碼:
結尾
借用一句看到很不錯的話:
技術不分對錯.人性才分善惡.
學習逆向的人必須身心放正.
身心放正之人手握屠龍刀,也是保家衛民.