最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

pvzclass是如何實(shí)現(xiàn)的?pvzclass源代碼初步分析(4)Memory類 & AsmFuntions.h

2021-06-21 22:30 作者:__W1thoutD0ubt  | 我要投稿

本篇將分析PVZ.h中的Memory類,以及AsmFuntions.h & AsmFunctions.cpp) 。

文中會(huì)涉及到一些Windows API函數(shù),不過(guò)本文不會(huì)對(duì)它們深層次的實(shí)現(xiàn)作深入探討,請(qǐng)放心。

本文中的“PVZ本體”和“修改器本體”指的是運(yùn)行中的程序,而不是存在存儲(chǔ)器中的文件。

Memory類概覽

PVZ.h中的Memory類

如上圖所示,Memory類中的所有成員都帶有static關(guān)鍵字,即它們都是靜態(tài)的。

不過(guò)為了使用它們,你仍然需要實(shí)例化PVZ對(duì)象。

除了InjectDll()(.dll文件的注入)的定義在PVZ.cpp中完成,其他方法的定義都在Classes文件夾的Memory.cpp中。

Memory類中的成員可以分為三類:PVZ的屬性、讀寫(xiě)PVZ內(nèi)存的方法,以及其他內(nèi)存相關(guān)方法。

不過(guò),因?yàn)镻VZ屬性相關(guān)的變量的賦值依賴于Memory類的方法,這些變量的分析放到最后。

讀寫(xiě)PVZ內(nèi)存的方法

ReadMemory、WriteMemory、ReadArray和WriteArray都用到了C++中的template,定義也是直接在PVZ.h中完成。

使用template,意味著我們?cè)趯?shí)際調(diào)用時(shí)完全不用擔(dān)心各種變量類型的轉(zhuǎn)換問(wèn)題。這種問(wèn)題放手交給pvzclass就行。

ReadMemory和ReadArray都使用了ReadProcessMemory,它的聲明類似于如下的代碼:

其中l(wèi)pBaseAddr表示讀取的起始地址,nSize表示讀取的內(nèi)存大小。

雖然返回值是Bool類型,但是實(shí)際上它只表示讀取是否成功,實(shí)際的讀取結(jié)果存儲(chǔ)到修改器本體從lpBuffer開(kāi)始的內(nèi)存。

WriteMemory和WriteArray類似,它們使用了WriteProcessMemory,其聲明類似于如下的代碼:

與ReadProcessMemory類似,lpBaseAddr表示寫(xiě)入的起始地址,nSize表示讀取的內(nèi)存大小。

寫(xiě)入的數(shù)據(jù)源則是修改器本體從lpBuffer開(kāi)始的內(nèi)存。

雖然返回值是Bool類型,但是實(shí)際上它只表示寫(xiě)入是否成功。

某種意義上講,ReadProcessMemory和WriteProcessMemory像是跨程序的memcpy。

ReadPointer的定義是在Memory.cpp中完成的:

套娃函數(shù)

要讀取指針指向的變量,如果不用ReadPointer,需要多次使用ReadMemory。

ReadPointer可以減少代碼量,用起來(lái)也非常方便。

實(shí)際上PVZ.cpp中GetAll類的方法,大都使用了ReadPointer來(lái)代替ReadMemory。

其他方法

剩余的方法也都用到了Windows API函數(shù)。

AllAccess使用VirtualProtectEx,可以將PVZ本體中的一段內(nèi)存轉(zhuǎn)變?yōu)榭勺x、可寫(xiě)、可執(zhí)行的狀態(tài)。

AllocMemory使用VirtualAllocEx,可以在PVZ本體中申請(qǐng)一段未使用的內(nèi)存,用來(lái)存放數(shù)據(jù)等內(nèi)容。

AllocMemory的返回值為申請(qǐng)的內(nèi)存的起始地址。

CreateThread使用CreateRemoteThread,可以從PVZ本體的某個(gè)位置直接開(kāi)始一段線程的運(yùn)行。

FreeMemory與AllocMemory相對(duì),使用VirtualFreeEx,可以釋放在PVZ本體中申請(qǐng)的內(nèi)存。

Execute的代碼如下:

像是單純地封裝了之前的方法

Execute的作用是在PVZ本體中運(yùn)行一段在PVZ外寫(xiě)成的程序。

從上面的代碼中,我們可以看出Execute的運(yùn)行步驟:

申請(qǐng)內(nèi)存、注入代碼、運(yùn)行線程、釋放內(nèi)存、取走返回值。

其中兩個(gè)WriteMemory的作用,第一個(gè)是暫停PVZ本體其他線程的運(yùn)行,第二個(gè)則是恢復(fù)其他線程的運(yùn)行。

InjectDll的代碼如下:

與Execute的結(jié)構(gòu)高度相似。

不同的是,InjectDll執(zhí)行的代碼大部分是固定的,匯編代碼(即__asm__InjectDll)主要存儲(chǔ)在Asmfuntions.h中。

PVZ屬性相關(guān)

在Memory.cpp中,我們可以看到四個(gè)變量的初值……嗎?

4個(gè)“空”

這顯然不能看出它們的作用。

實(shí)際上對(duì)它們賦值的主要代碼在PVZ類的構(gòu)造函數(shù)中:

(位于PVZ.cpp中)

這樣這四個(gè)變量的作用就比較明晰了:

processId存儲(chǔ)PVZ本體的進(jìn)程ID,通過(guò)Open或其他方法獲??;

hProcess存儲(chǔ)PVZ本體的句柄,由OpnProcess獲?。?/p>

mainwindowhandle存儲(chǔ)PVZ窗口的句柄,從PVZ本體的內(nèi)存中讀取;

Variable則存儲(chǔ)pvzclass申請(qǐng)的一段內(nèi)存。

hProcess和mainwindowhandle可以作為某些Windows API函數(shù)的參數(shù)。

pvzclass中也有不少功能是用機(jī)器碼實(shí)現(xiàn)的,這些功能臨時(shí)占用的空間、部分參數(shù)的存儲(chǔ)位置、返回值的暫存位置,全都在Variable對(duì)應(yīng)的內(nèi)存之中。

AsmFunctions

這里吐個(gè)槽,AsmFunction.h的拼寫(xiě)一直是錯(cuò)誤的"AsmFuntion.h"("Function"沒(méi)有"c")。下文采用"AsmFunction.h"。

這里的"Asm"指的是"Assembly Language",即“匯編語(yǔ)言”。

AsmFunctions(.h/.cpp)包含的,正是為pvzclass擴(kuò)充匯編語(yǔ)言的支持的代碼。

如果沒(méi)有匯編語(yǔ)言基礎(chǔ)的話,看這一節(jié)之前還是先去了解一下相關(guān)的內(nèi)容吧。

當(dāng)然,這不影響你使用pvzclass的其他絕大部分內(nèi)容。

AsmFunctions.h包括三部分:定義匯編代碼和INVOKE宏、定義封裝用宏、聲明匯編代碼。

我們依次分析。

asm define部分中有一個(gè)INUMBER宏,它看上去很奇怪:

如果你熟悉位運(yùn)算的話,應(yīng)該能看出來(lái),這是將一個(gè)32位整數(shù)8位8位地分割,然后將四部分的順序顛倒過(guò)來(lái)而已。

這么做是針對(duì)機(jī)器碼處理32位整數(shù)的方法。

即使是熟悉匯編語(yǔ)言的人,可能也會(huì)對(duì)代碼名的后綴感到頭皮發(fā)麻。

這里大概解釋一下命名風(fēng)格:

每個(gè)宏的命名由“代碼名”和“后綴”兩部分構(gòu)成。

“代碼名”對(duì)應(yīng)的是某條指令在匯編語(yǔ)言中的名稱。

“后綴”則表示該條指令的參數(shù)、參數(shù)類型、格式等。

如"DWORD"表示相關(guān)參數(shù)占4字節(jié)(而非默認(rèn)的1字節(jié)),"_EAX"表示參數(shù)中含有寄存器eax,等等等等。

這里不詳細(xì)展開(kāi)。讀者可以利用Cheat Engine等軟件自己摸索。

接下來(lái)介紹一個(gè)比較重要的宏:INVOKE宏。

在匯編語(yǔ)言中,call指令使用相對(duì)引用。

也就是說(shuō),機(jī)器碼都為"0xE8 0x64 0x00 0x00 0x00"的代碼,在0xE38000時(shí)是"call 0xE38007",但在其他位置則是另外的"call"了。

但對(duì)于常用匯編語(yǔ)言的創(chuàng)作者而言,絕對(duì)引用的call是非常有必要的,因?yàn)镻VZ的代碼不會(huì)自己跑到內(nèi)存的其他地方。

在這種情況下,INVOKE宏應(yīng)運(yùn)而生。

INVOKE宏可以視為一個(gè)替代CALL的解決方案。它可以作為一個(gè)絕對(duì)引用的CALL而不會(huì)產(chǎn)生其他副作用,避免了計(jì)算相對(duì)引用的繁雜過(guò)程。

在pvzclass中,INVOKE宏也相當(dāng)常用。

讀者也可以嘗試在自己的pvzclass自用匯編代碼中使用INVOKE宏。

在初始的INVOKE宏下方,還有多個(gè)INVOKE宏的變種,但它們都只是在INVOKE宏的基礎(chǔ)上添加了參數(shù)而已。

定義封裝用宏

這里定義的是pvzclass自用的匯編代碼中使用的宏。

可以看到,這些宏只是在具體地應(yīng)用INVOKE宏而已。

這里聲明的是pvzclass自用的匯編代碼。

在pvzclass中,機(jī)器碼(包括自匯編代碼轉(zhuǎn)化而來(lái)的)用byte數(shù)組的形式存儲(chǔ)。

這些的實(shí)裝主要在AsmFunctions.cpp中完成。

pvzclass是針對(duì)PVZ的項(xiàng)目。

PVZ, PVZ, 怎么能沒(méi)有P(植物)和Z(僵尸)呢?

下一篇開(kāi)始分析pvzclass中,有關(guān)植物和僵尸的代碼。

pvzclass是如何實(shí)現(xiàn)的?pvzclass源代碼初步分析(4)Memory類 & AsmFuntions.h的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
黄陵县| 哈巴河县| 平陆县| 贵州省| 永寿县| 海原县| 齐河县| 安丘市| 莲花县| 武乡县| 浦北县| 临邑县| 灌云县| 河西区| 化德县| 乐平市| 堆龙德庆县| 丰都县| 邵阳县| 七台河市| 奎屯市| 大城县| 青浦区| 麦盖提县| 洪洞县| 新巴尔虎右旗| 华蓥市| 黄山市| 祁阳县| 辛集市| 清涧县| 新竹县| 墨脱县| 德化县| 邻水| 南岸区| 保定市| 开远市| 天镇县| 绿春县| 阜平县|