使用Python學(xué)習(xí)win32庫進(jìn)行內(nèi)存讀寫2

根據(jù)上一篇 使用Python讀寫游戲1 中,使用Python win32庫,對(duì)一款游戲進(jìn)行了讀內(nèi)存 操作。

今天來寫一下對(duì)內(nèi)存進(jìn)行寫的操作

正文

要進(jìn)行32位的讀寫,首先了解一下要用到的幾個(gè)函數(shù),通過百度找到的,大多都是C/C++的資料。

更詳細(xì)的分析看上一篇。

寫入函數(shù) 是 WriteProcessMemory

此函數(shù)能寫入某一進(jìn)程的內(nèi)存區(qū)域(直接寫入會(huì)出Access Violation錯(cuò)誤,故需此函數(shù))。

VC++聲明

BOOL WriteProcessMemory(
HANDLE hProcess,//要修改的進(jìn)程內(nèi)存的句柄。句柄必須具有對(duì)進(jìn)程的進(jìn)程_vm_寫和進(jìn)程_vm_操作的訪問權(quán)限
LPVOID lpBaseAddress,//指向?qū)懭霐?shù)據(jù)的指定進(jìn)程中的基地址的指針。在進(jìn)行數(shù)據(jù)傳輸之前,系統(tǒng)將驗(yàn)證指定大小的基址和內(nèi)存中的所有數(shù)據(jù)都可用于寫訪問,如果無法訪問,則函數(shù)將失敗。
LPVOID lpBuffer,//指向緩沖區(qū)的指針,其中包含要在指定進(jìn)程的地址空間中寫入的數(shù)據(jù)
DWORD nSize,//要寫入指定進(jìn)程的字節(jié)數(shù)。
LPDWORD lpNumberOfBytesWritten//指向接收傳輸?shù)街付ㄟM(jìn)程的字節(jié)數(shù)的變量的指針。此參數(shù)是可選的。如果lpNumberOfBytesWritten是零,則忽略該參數(shù)。
);

返回值

如果函數(shù)成功,則返回值為非零

如果函數(shù)失敗,則返回值為0(零)。若要獲取擴(kuò)展錯(cuò)誤信息,請(qǐng)調(diào)用GetLastError,如果請(qǐng)求的寫操作跨入進(jìn)程中無法訪問的區(qū)域,則函數(shù)將失敗。

對(duì)單機(jī)植物大戰(zhàn)僵尸進(jìn)行讀取與寫入操作

對(duì)植物大戰(zhàn)僵尸分析,請(qǐng)看

植物大戰(zhàn)僵尸(1)

植物大戰(zhàn)僵尸(2)

植物大戰(zhàn)僵尸(3)

首先是對(duì)陽光數(shù)量的讀取

陽光的基址偏移是:

陽光:PlantsVsZombies.exe+2A9EC0+768+5560   

不能直接讀PlantsVsZombies.exe+2A9EC0,所以把該值添加到CE中,查看地址欄中的十六進(jìn)制值 006A9EC0
image

讀寫操作,與上一篇文章寫法相似

# -*- coding: utf-8 -*-
import win32process#進(jìn)程模塊
from win32con import PROCESS_ALL_ACCESS #Opencress 權(quán)限
import win32api#調(diào)用系統(tǒng)模塊
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"植物大戰(zhàn)僵尸中文版")
    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 ("陽光的數(shù)量:%d" % sun)

if __name__ == '__main__':
    main()

sun 分解寫法:

def main():
    ret  = GetProcssID(0x006A9EC0,4)
    ret2 = GetProcssID(ret+0x768,4)
    sun = GetProcssID(ret2+0x5560,4)
    print ("陽光的數(shù)量:%d" % sun)
    #sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
    
image

根據(jù)之前的分析,植物大戰(zhàn)僵尸可以開啟自動(dòng)收集功能。具體的地址是

自動(dòng)收集:PlantsVsZombies.exe+3158B   初始值:5274496  修改后:22051712
        十六進(jìn)制:0043158B

聲明一個(gè)函數(shù)

def WriteMemeryInt(_address,Data):
    hGameHandle = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
    WriteProcessInt = kernel32.WriteProcessMemory // 從kernel32動(dòng)態(tài)鏈接庫中調(diào)用這個(gè)函數(shù)
    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)),  //要寫入的數(shù)據(jù)
4,    //要寫入指定進(jìn)程的字節(jié)數(shù)。
None  //指向接收傳輸?shù)街付ㄟM(jìn)程的字節(jié)數(shù)的變量的指針。此參數(shù)是可選的。如果lpNumberOfBytesWritten是零,則忽略該參數(shù)。
);

修改植物大戰(zhàn)僵尸陽光數(shù)量

def _modifySunshine():
    sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
    sun_write = WriteMemeryInt(GetProcssID( GetProcssID( 0x006A9EC0, 4) + 0x768,4) + 0x5560, 100)
    print("修改前陽光的數(shù)量:" , sun)
    if sun_write:
        print("###################修改陽光數(shù)量成功##############################")
        sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
        print("修改后陽光的數(shù)量:" , sun)
    else:
        print("###################修改陽光數(shù)量失敗,錯(cuò)誤信息:##################",GetLastError)

sun_write 分解寫法

def _modifySunshine():
    ret = GetProcssID(0x006A9EC0, 4)
    ret2 = GetProcssID(ret + 0x768, 4)
    sun_write = WriteMemeryInt(ret2+0x5560,100) 
    #ret2+0x5560 要寫入的地址,不能在GetProcessID讀取,不然寫入的地址就不正確
    #100 為修改的數(shù)量。
    if sun_write:
        print("###################修改陽光數(shù)量成功##############################")
    else:
        print("###################修改陽光數(shù)量失敗,錯(cuò)誤信息:##################",GetLastError)

運(yùn)行代碼

image
# -*- coding: utf-8 -*-
import win32process#進(jìn)程模塊
from win32con import PROCESS_ALL_ACCESS #Opencress 權(quán)限
import win32api#調(diào)用系統(tǒng)模塊
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"植物大戰(zhàn)僵尸中文版")
    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動(dòng)態(tài)鏈接庫中調(diào)用這個(gè)函數(shù)
    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("修改前陽光的數(shù)量:" , sun)
    if sun_write:
        print("###################修改陽光數(shù)量成功##############################")
        sun = GetProcssID(GetProcssID(GetProcssID(0x006A9EC0, 4)+0x768, 4)+0x5560, 4)
        print("修改后陽光的數(shù)量:" , sun)
    else:
        print("###################修改陽光數(shù)量失敗,錯(cuò)誤信息:##################",GetLastError)

def main():
    _modifySunshine()

if __name__ == '__main__':
    main()

基本代碼就這些了,接下來按照我寫C的格式,把代碼格式改一下,因?yàn)榭雌饋碚娴耐y的

先把FindWindow 等基礎(chǔ)操作用函數(shù)給封裝

# -*- coding: utf-8 -*-
import win32process#進(jìn)程模塊
from win32con import PROCESS_ALL_ACCESS #Opencress 權(quán)限
import win32api#調(diào)用系統(tǒng)模塊
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"植物大戰(zhàn)僵尸中文版")

    _hGameHandle = _GetPorcessHandle(ProcessId)

    win32api.CloseHandle(_hGameHandle)
   
if __name__ == '__main__':
    main()

在開始寫功能,先是讀取陽光數(shù)量和修改陽光數(shù)量:

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("修改前陽光的數(shù)量:" , sun)
    if sun_write:
        print("###################修改陽光數(shù)量成功##############################")
        sun = _ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle, _ReadMemeryInt(hGameHandle, 0x006A9EC0, 4) + 0x768,4) + 0x5560, 4)
        print("修改后的陽光數(shù)量:", sun)
    else:
        print("###################修改陽光數(shù)量失敗,錯(cuò)誤信息:##################",GetLastError)

接著,根據(jù)分析,有自動(dòng)收集陽光功能,基址是:

自動(dòng)收集:PlantsVsZombies.exe+3158B   初始值:5274496  修改后:22051712
        十六進(jìn)制:0043158B
def _collectSunshine(hGameHandle):
    collect = WriteMemeryInt(hGameHandle,0x0043158B,22051712)
    if collect:
        print("###################啟動(dòng)自動(dòng)收集功能成功#########################")
    else:
        print("###################修改自動(dòng)收集功能失敗,錯(cuò)誤信息:##################",GetLastError)

接下來是秒殺功能,因?yàn)椴灰欢看味际氐米?/p>

普通僵尸秒殺基址:

秒殺普通僵尸: PlantsVsZombies.exe+13178A   初始值:1284214911 修改后:1284214928  
            十六進(jìn)制:0053178A
def _Seckill(hGameHandle):
    seckill = WriteMemeryInt(hGameHandle,0x0053178A,1284214928)
    if seckill:
        print("###################啟動(dòng)秒殺普通僵尸功能成功#########################")
    else:
        print("###################修改秒殺功能失敗,錯(cuò)誤信息:#########################",GetLastError)

除了普通僵尸,還有頭盔僵尸:

頭盔僵尸基址:

秒殺帶護(hù)甲:   PlantsVsZombies.exe+13186D   初始值:1347618942  修改后:1347653776  
            十六進(jìn)制:0053186D
def _SecKillHelmet(hGameHandle):
    seckillHelemet = WriteMemeryInt(hGameHandle,0x53186D ,1347653776)
    if seckillHelemet:
        print("###################啟動(dòng)秒殺頭盔僵尸功能成功#########################")
    else:
        print("###################修改頭盔僵尸秒殺功能失敗,錯(cuò)誤信息:#################",GetLastError)

完整代碼:

# -*- coding: utf-8 -*-
import win32process#進(jìn)程模塊
from win32con import PROCESS_ALL_ACCESS #Opencress 權(quán)限
import win32api#調(diào)用系統(tǒng)模塊
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("修改前陽光的數(shù)量:" , sun)
    if sun_write:
        print("###################修改陽光數(shù)量成功##############################")
        sun = _ReadMemeryInt(hGameHandle,_ReadMemeryInt(hGameHandle, _ReadMemeryInt(hGameHandle, 0x006A9EC0, 4) + 0x768,4) + 0x5560, 4)
        print("修改后的陽光數(shù)量:", sun)
    else:
        print("###################修改陽光數(shù)量失敗,錯(cuò)誤信息:##################",GetLastError)

def _collectSunshine(hGameHandle):
    collect = WriteMemeryInt(hGameHandle,0x0043158B,22051712)
    if collect:
        print("###################啟動(dòng)自動(dòng)收集功能成功#########################")
    else:
        print("###################修改自動(dòng)收集功能失敗,錯(cuò)誤信息:##################",GetLastError)

def _Seckill(hGameHandle):
    seckill = WriteMemeryInt(hGameHandle,0x0053178A,1284214928)
    if seckill:
        print("###################啟動(dòng)秒殺普通僵尸功能成功#########################")
    else:
        print("###################修改秒殺功能失敗,錯(cuò)誤信息:#########################",GetLastError)

def _SecKillHelmet(hGameHandle):
    seckillHelemet = WriteMemeryInt(hGameHandle,0x53186D ,1347653776)
    if seckillHelemet:
        print("###################啟動(dòng)秒殺頭盔僵尸功能成功#########################")
    else:
        print("###################修改頭盔僵尸秒殺功能失敗,錯(cuò)誤信息:#################",GetLastError)

def main():
    ProcessId = _GetProcessId(None,u"植物大戰(zhàn)僵尸中文版")

    _hGameHandle = _GetPorcessHandle(ProcessId)

    _modifySunshine(_hGameHandle)

    _collectSunshine(_hGameHandle)

    _Seckill(_hGameHandle)

    _SecKillHelmet(_hGameHandle)

    win32api.CloseHandle(_hGameHandle)

if __name__ == '__main__':
    main()

運(yùn)行代碼:

image

結(jié)尾

借用一句看到很不錯(cuò)的話:

技術(shù)不分對(duì)錯(cuò).人性才分善惡.

學(xué)習(xí)逆向的人必須身心放正.

身心放正之人手握屠龍刀,也是保家衛(wèi)民.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容