色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Windows2000下用戶(hù)模式的內(nèi)存掃描

瀏覽:110日期:2023-08-27 11:11:07

簡(jiǎn)述:

本文簡(jiǎn)要介紹了在Windows2000下實(shí)現(xiàn)內(nèi)存掃描的基本理論和實(shí)現(xiàn)的辦

法。內(nèi)存掃描是一項(xiàng)重要的技術(shù),有相當(dāng)廣泛的應(yīng)用范圍:如病毒掃描、

游戲修改等。Windows2000是一個(gè)完全保護(hù)的系統(tǒng),且具有兩種工作模式,

即用戶(hù)態(tài)和核心態(tài)(User Model and Kernel Model)。內(nèi)存掃描也可分為

用戶(hù)態(tài)的內(nèi)存掃描與核心態(tài)的內(nèi)存掃描。本文主要講述的是工作于用戶(hù)態(tài)

的內(nèi)存掃描。

一.相關(guān)理論

早期在Dos壞境下進(jìn)行內(nèi)存掃描是一件相對(duì)簡(jiǎn)單的事情。因?yàn)镈OS工作在

CPU的實(shí)模式下,沒(méi)有采用虛存技術(shù)也沒(méi)有提供內(nèi)存的保護(hù)機(jī)制,只要實(shí)實(shí)

在在的掃描完所有的物理內(nèi)存,一切工作也就完成了,早期有一些防毒軟

件就是用了這樣的辦法。當(dāng)然為了提高效率,我們并不用掃描所有的內(nèi)存

區(qū)域,因?yàn)橛行┛臻g是沒(méi)有被用到的,掃描這些地方也是只浪費(fèi)時(shí)間。這

可以通過(guò)遍歷DOS系統(tǒng)的MCB(Memory Control Block)鏈,來(lái)得到實(shí)際內(nèi)

存的使用區(qū)域,從而使掃描的效率大大提高。相似的思路在Windows2000下

的內(nèi)存掃描也是適用的。

Windows2000則是一個(gè)完全保護(hù)的系統(tǒng),工作于CPU的保護(hù)模式下,引入

了虛存技術(shù)。每個(gè)進(jìn)程擁有獨(dú)立的4GB的地址空間,其中低的2GB為進(jìn)程的私有空間,高的2GB為系統(tǒng)空間的映射(如果在Boot.ini文件中使用

“/3GB”的開(kāi)關(guān)可以使進(jìn)程的私有空間增大到3GB,系統(tǒng)空間1GB)。對(duì)于

每個(gè)進(jìn)程來(lái)講其虛擬的地址空間是連續(xù)的,實(shí)際上它們是以頁(yè)面為單位

離 散的存在于物理內(nèi)存中,一些可能被交換到硬盤(pán)上的頁(yè)面文件中,而

且還有大部分的空間是未提交(Uncommitted)的。因此在Windows2000

中對(duì)進(jìn)程的用戶(hù)空間進(jìn)行掃描必須依次對(duì)每個(gè)進(jìn)程的空間進(jìn)行掃描。一

個(gè)進(jìn)程的低2GB有空間的分布如下表:

范圍

大小

作用

0x0~~ 0xFFFF

64 KB

不可訪(fǎng)問(wèn)區(qū)域,只是用來(lái)防止非法的指針訪(fǎng)問(wèn),訪(fǎng)問(wèn)該范圍的地址會(huì)導(dǎo)致訪(fǎng)問(wèn)違例。

0x10000~~

0x7FFEFFFF

2 GB 減去至少 192 KB

進(jìn)程的私有地址空間

0x7FFDE000~~

0x7FFDEFFF

4 KB

進(jìn)程中第一個(gè)線(xiàn)程的線(xiàn)程環(huán)境塊,即 TEB ( Thread environment block )

0x7FFDF000~~ 0x7FFDFFFF

4 KB

進(jìn)程的進(jìn)程環(huán)境塊,即 PEB ( Process environment block )

0x7FFE0000~~

0x7FFE0FFF

4 KB

一個(gè)共享的只讀用戶(hù)數(shù)據(jù)塊,該塊映射到到系

統(tǒng)空間的一個(gè)數(shù)據(jù)塊,其中存放的是一些系統(tǒng)

信息如系統(tǒng)時(shí)間、時(shí)鐘的滴答數(shù)、系統(tǒng)版本號(hào)

等。這樣訪(fǎng)問(wèn)這些信息的時(shí)候系統(tǒng)就不用切換

到核心模式。

0x7FFE1000~~

0x7FFEFFFF

60 KB

不可訪(fǎng)問(wèn)

0x7FFF0000~~ 0x7FFFFFFF

64 KB

不可訪(fǎng)問(wèn),用于防止線(xiàn)程的緩沖跨越兩種模式

空間的邊界

表 1

二.實(shí)現(xiàn) 從上表可以看出,我們要掃描范圍的起點(diǎn)和終點(diǎn)不是從 0~~2GB,而只是其中的一 部分。要得到這個(gè)起點(diǎn)和終點(diǎn)可以使用API函數(shù)GetSystemInfo,函數(shù)的原型如下: VOID GetSystemInfo( LPSYSTEM_INFO lpSystemInfo // system information ); 而在結(jié)構(gòu)SYSTEM_INFO中有兩個(gè)域: lpMinimumApplicationAddress 和 lpMaximumApplicationAddress (類(lèi)型都是 LPVOID) 中 ,我們就可以得到一個(gè)應(yīng)用程序可用的最小和最大的地址空間。這樣我們就得到了要掃描的地址的起點(diǎn)和終點(diǎn)。那么是不是這起點(diǎn)和終點(diǎn)間所有的地址都要掃描呢?并不是這樣的,因?yàn)橐话闱闆r下一個(gè)進(jìn)程是用不著這么大(接近2GB)的地址空間的。因此一個(gè)進(jìn)程的大部分地址空間都是未用(Free)或是保留(Reserved)的,真正用到的只是那些已提交(Committed)的內(nèi)存而已。

內(nèi)存頁(yè)面可以有三種狀態(tài): 未用( Free)、保留(Reserved)和提交

(Committed)。一個(gè)未用的頁(yè)面是指該頁(yè)面未被保留或是提交,對(duì)一個(gè)進(jìn)

程來(lái)講一個(gè)未用的頁(yè)面是不可訪(fǎng)問(wèn)的,訪(fǎng)問(wèn)這樣的頁(yè)面將導(dǎo)致訪(fǎng)問(wèn)違例。

進(jìn)程可以要求系統(tǒng)保留一些頁(yè)面以備后用,系統(tǒng)返回一段保留的地址給進(jìn)

程,但是這些地址同樣是不可訪(fǎng)問(wèn)的,進(jìn)程若想使用這段地址空間,使用

必須先提交。只有一個(gè)提交的頁(yè)面才是一個(gè)真正可以訪(fǎng)問(wèn)的頁(yè)面。不過(guò)你

提交了一個(gè)頁(yè)面,系統(tǒng)并不會(huì)馬上分配物理頁(yè)面,只有在該頁(yè)面第一次被

訪(fǎng)問(wèn)到時(shí),系統(tǒng)才會(huì)分配頁(yè)面并初始化。另外,這三個(gè)狀態(tài)的兩兩之間都

是可以相互轉(zhuǎn)化的。相關(guān)的API函數(shù)有 VirtualAlloc VirtualAllocEx 、

VirtualFree 、 VirtualFreeEx 等 .

這樣我們的工作已大大減少了,只需要掃描那些提交的頁(yè)面就好了。接下來(lái)要做的就

是得到一個(gè)進(jìn)程的已提交的頁(yè)面范圍。這就要用到另外兩個(gè) API函數(shù)VirtualQuery和

VirtualQueryEx。兩個(gè)函數(shù)的功能相似,不同就是VirtualQuery只是查詢(xún)本進(jìn)程而

VirtualQueryEx可以查詢(xún)指定進(jìn)程的內(nèi)存空間信息,后者正是我們所需要的,函數(shù)原

型如下:

DWord VirtualQueryEx(

HANDLE hProcess , // handle to process LPCVOID lpAddress , // address of region PMEMORY_BASIC_INFORMATION lpBuffer , // information buffer SIZE_T dwLength // size of buffer ); 第一個(gè)參數(shù)是進(jìn)程的句柄;第二個(gè)參數(shù)是內(nèi)存地址指針;第三個(gè)參數(shù)是指向 MEMORY_BASIC_INFORMATION 結(jié)構(gòu)的指針,用于返回內(nèi)存空間的信息;第四個(gè)參數(shù)是 lpBuffer 的長(zhǎng)度。再來(lái)看一下結(jié)構(gòu) MEMORY_BASIC_INFORMATION 的聲明: typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress ; PVOID AllocationBase ; DWORD AllocationProtect ; SIZE_T RegionSize ; DWORD State ; DWORD Protect ; DWORD Type ; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; 第一個(gè)參數(shù)是查詢(xún)內(nèi)存塊的基地址;第二個(gè)參數(shù)指的是用VirtualAlloc分配該內(nèi)存時(shí)實(shí)際分配的基地址, 可以小于 BaseAddress ,也就是說(shuō) BaseAddress 一定包含在 AllocationBase 分配的范圍內(nèi);第三個(gè)參數(shù)指的是分 配該頁(yè)面時(shí),頁(yè)面的一些屬性,如 PAGE_READWRITE、PAGE_EXECUTE 等(其它屬性 可參考 Platform SDK );第四 個(gè)參數(shù)指的是從 BaseAddress 開(kāi)始,具有相同屬性的頁(yè)面的大小。第五參數(shù)指的是頁(yè)面的狀態(tài),有三種可能值: MEM_COMMIT、MEM_FREE 和 MEM_RESERVE ,這個(gè)參數(shù)對(duì)我們來(lái)說(shuō)是最重要的了,從中我們便可知指定內(nèi)存頁(yè)面的狀態(tài)了; 第六個(gè)參數(shù)指的是頁(yè)面的屬性,其可能的取值與 AllocationProtect 相同;最后一個(gè)參數(shù)指明了該內(nèi)存塊的類(lèi)型,有三種可能值: MEM_IMAGE 、 MEM_MAPPED 和 MEM_PRIVATE 。 這樣我們就可得到進(jìn)程中需要掃描的地址范圍了。到這里剩下的問(wèn)題就是要讀取指定的進(jìn)程的指定的地地址空間的內(nèi)容了。這里要用到的是用于調(diào)試程序和錯(cuò)誤處理( Debugging and Error Handling )的 API函數(shù)。在“ Platform SDK: Debugging and Error Handling” 章節(jié)中,介紹了一部分與程序調(diào)試和錯(cuò)誤處理相關(guān)的 API函數(shù),有許多是很有用,例如我們下面用到的 ReadProcessMemory 和 WriteProcessMemory, 它們?cè)腿缦拢?BOOL ReadProcessMemory( HANDLE hProcess , // handle to the process LPCVOID lpBaseAddress , // base of memory area LPVOID lpBuffer , // data buffer SIZE_T nSize , // number of bytes to read SIZE_T * lpNumberOfBytesRead // number of bytes read ); BOOL WriteProcessMemory( HANDLE hProcess , // handle to process LPVOID lpBaseAddress , // base of memory area LPCVOID lpBuffer , // data buffer SIZE_T nSize , // count of bytes to write SIZE_T * lpNumberOfBytesWritten // count of bytes written ); 參數(shù)很簡(jiǎn)單從它們的名字都可以猜出其意義了,這里就不多做說(shuō)明了。要說(shuō)明的是 要對(duì)一個(gè)進(jìn)程進(jìn)行 ReadProcessMemory操作,當(dāng)前進(jìn)程對(duì)要讀的進(jìn)程必須有PROCESS_VM_READ訪(fǎng)問(wèn)權(quán)。要對(duì)一個(gè)進(jìn)程進(jìn)行WriteProcessMemory操作,當(dāng)前進(jìn)程對(duì)要寫(xiě)的進(jìn)程必須有PROCESS_VM_WRITE 和PROCESS_VM_OPERATION訪(fǎng)問(wèn)權(quán)。要獲得一個(gè)進(jìn)程的句柄和對(duì)這個(gè)進(jìn)程的一些控制權(quán)可以使用API函數(shù)OpenProcess得到,其使用不做詳細(xì)說(shuō)明了,只給出其原型: HANDLE OpenProcess( DWORD dwDesiredAccess , // access flag BOOL bInheritHandle , // handle inheritance option DWORD dwProcessId // process identifIEr );

這樣對(duì)一個(gè)進(jìn)程的用戶(hù)地址空間內(nèi)存掃描的流程基本就闡述清楚了。

三 相關(guān)的問(wèn)題:

在實(shí)際操作中會(huì)遇到一些問(wèn)題。如果我們指定了寫(xiě)相關(guān)的訪(fǎng)問(wèn)權(quán)(如

PROCESS_VM_WRITE 、 PROCESS_SET_INFORMATION 、 PROCESS_ALL_ACCESS 等 ),用

OpenProcess打開(kāi)一些普通進(jìn)程是沒(méi)什么問(wèn)題,但要是打開(kāi)的是系統(tǒng)安全進(jìn)程

(如Sy stem、Winlogon、smss、csRSS、services、lsass等)或是一些注冊(cè)為

服務(wù)的進(jìn)程時(shí),就會(huì)遇到“訪(fǎng)問(wèn)拒絕”的錯(cuò)誤,這是為了系統(tǒng)的安全而采取的保

護(hù)手段。說(shuō)明了當(dāng)前的進(jìn)程沒(méi)有足夠的權(quán)限來(lái)進(jìn)行此操作。在進(jìn)程控制結(jié)構(gòu)中

有一個(gè)“訪(fǎng)問(wèn)令牌”(Access tokens),里面包含有本進(jìn)程的權(quán)限信息。一些常

用的權(quán)限如表1所示(摘自Inside Windows2000,Third Edition)。

權(quán)限名

權(quán)限含義

SeBackup

在備份的時(shí)候繞過(guò)安全檢查

SeDebug

可對(duì)一個(gè)進(jìn)程進(jìn)行調(diào)試

SeShutdown

可關(guān)閉本地系統(tǒng)

SeTakeOwnerShip

在沒(méi)有得到自由訪(fǎng)問(wèn)權(quán)的情況下得到一個(gè)對(duì)象的所有權(quán)

表 2

要對(duì)一個(gè)任意進(jìn)程(包括系統(tǒng)安全進(jìn)程和服務(wù)進(jìn)程)進(jìn)行 指定了寫(xiě)相 關(guān)的訪(fǎng)問(wèn)權(quán)的 OpenProcess操作,只要當(dāng)前進(jìn)程具有SeDeDebug權(quán)限就 可 以了。要是一個(gè)用戶(hù)是Administrator或是被給予了相應(yīng)的權(quán)限, 就可以具 有該權(quán)限。可是,就算我們用Administrator帳號(hào)對(duì)一個(gè)系統(tǒng)安全進(jìn)程執(zhí)行 OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)還是會(huì)遇到 “訪(fǎng) 問(wèn)拒絕”的錯(cuò)誤。什么原因呢?原來(lái)在默認(rèn)的情況下進(jìn)程的一些訪(fǎng)問(wèn)權(quán)限 是沒(méi)有被使能( Enabled)的,所以我們要做的首先是使能這些權(quán)限。與此 相關(guān)的一些API函數(shù)有OpenProcessToken、 LookupPrivilegeValue 、 AdjustTokenPrivileges 。我們要修改一個(gè)進(jìn)程的訪(fǎng)問(wèn)令牌,首先要獲得進(jìn) 程訪(fǎng)問(wèn)令牌的句柄,這可以通過(guò) OpenProcessToken得到,函數(shù)的原型如:

BOOL OpenProcessToken( HANDLE ProcessHandle , DWORD DesiredAccess , PHANDLE TokenHandle ); 第一參數(shù)是要修改訪(fǎng)問(wèn)權(quán)限的進(jìn)程句柄;第三個(gè)參數(shù)就是返回的訪(fǎng)問(wèn)令牌指針;第二個(gè)參數(shù)指定你要進(jìn)行的操作類(lèi)型,如要修改令牌我們要指定第二個(gè)參數(shù)為 TOKEN_ADJUST_PRIVILEGES( 其它一些參數(shù)可參考 Platform SDK )。通過(guò)這個(gè)函數(shù)我們就可以得到當(dāng)前進(jìn)程的訪(fǎng)問(wèn)令牌的句柄(指定函數(shù)的第一個(gè)參數(shù)為 GetCurrentProcess()就可以了)。接著我們可以調(diào)用AdjustTokenPrivileges對(duì)這個(gè)訪(fǎng)問(wèn)令牌進(jìn)行修改。AdjustTokenPrivileges的原型如下: BOOL AdjustTokenPrivileges( HANDLE TokenHandle , // handle to token BOOL DisableAllPrivileges , // disabling option PTOKEN_PRIVILEGES NewState , // privilege information DWORD BufferLength , // size of buffer PTOKEN_PRIVILEGES PreviousState , // original state buffer PDWORD ReturnLength // required buffer size );

第一個(gè)參數(shù)是訪(fǎng)問(wèn)令牌的句柄;第二個(gè)參數(shù)決定是進(jìn)行權(quán)限修改還是除能( Disable)所有權(quán)限;第三個(gè)參數(shù)指明要修改的權(quán)限,是一個(gè)指向 TOKEN_PRIVILEGES 結(jié)構(gòu)的指針,該結(jié)構(gòu)包含一個(gè)數(shù)組,數(shù)據(jù)組的每個(gè)項(xiàng)指明了權(quán)限的類(lèi)型和要進(jìn)行的操作 ; 第四個(gè)參數(shù)是結(jié)構(gòu) PreviousState 的長(zhǎng)度,如果 PreviousState 為空,該參數(shù)應(yīng)為 NULL ;第五個(gè)參數(shù)也是一個(gè) 指向 TOKEN_PRIVILEGES 結(jié)構(gòu)的指針,存放修改前的訪(fǎng)問(wèn)權(quán)限的信息,可空;最后一個(gè)參數(shù)為實(shí)際 PreviousState 結(jié)構(gòu)返回的大小。在使用這個(gè)函數(shù)前再看一下 TOKEN_PRIVILEGES 這個(gè)結(jié)構(gòu),其聲明如下:

typedef struct _TOKEN_PRIVILEGES { DWORD PrivilegeCount ; LUID_AND_ATTRIBUTES Privileges []; } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;

PrivilegeCount 指的數(shù)組原素的個(gè)數(shù),接著是一個(gè) LUID_AND_ATTRIBUTES 類(lèi)型的數(shù)組,再來(lái)看一下 LUID_AND_ATTRIBUTES 這個(gè)結(jié)構(gòu)的內(nèi)容,聲明如下:

typedef struct _LUID_AND_ATTRIBUTES { LUID Luid ; DWORD Attributes ;

} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES

第二個(gè)參數(shù)就指明了我們要進(jìn)行的操作類(lèi)型,有三個(gè)可選項(xiàng):

SE_PRIVILEGE_ENABLED 、 SE_PRIVILEGE_ENABLED_BY_DEFAULT 、

SE_PRIVILEGE_USED_FOR_ACCESS 。要使能一個(gè)權(quán)限就指定 Attributes 為

SE_PRIVILEGE_ENABLED 。第一個(gè)參數(shù)就是指權(quán)限的類(lèi)型,是一個(gè) LUID 的

值, LUID 就是指 locally unique identifier ,我想 GUID 大家是比較熟

悉的,和 GUID 的要求保證全局唯一不同, LUID 只要保證局部唯一,就是

指在系統(tǒng)的每一次運(yùn)行期間保證是唯一的就可以了。另外和 GUID 相同的

一點(diǎn), LUID 也是一個(gè) 64 位的值,相信大家都看過(guò) GUID 那一大串的值,我

們要怎么樣才能知道一個(gè)權(quán)限對(duì)應(yīng)的 LUID 值是多少呢?這就要用到另外

一個(gè) API 函數(shù) LookupPrivilegeValue ,其原形如下:

BOOL LookupPrivilegeValue( LPCTSTR lpSystemName , // system name LPCTSTR lpName , // privilege name PLUID lpLuid // locally unique identifier );

第一個(gè)參數(shù)是系統(tǒng)的名稱(chēng),如果是本地系統(tǒng)只要指明為 NULL 就可以了,

第三個(gè)參數(shù)就是返回 LUID 的指針,第二個(gè)參數(shù)就是指明了權(quán)限的名稱(chēng),

如“ SeDebugPrivilege ”。在 Winnt.h 中還定義了一些權(quán)限名稱(chēng)的宏,

如:

#define SE_BACKUP_NAME TEXT('SeBackupPrivilege')

#define SE_RESTORE_NAME TEXT('SeRestorePrivilege')

#define SE_SHUTDOWN_NAME TEXT('SeShutdownPrivilege')

#define SE_DEBUG_NAME TEXT('SeDebugPrivilege')

這樣通過(guò)這三個(gè)函數(shù)的調(diào)用,我們就可以用 OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)來(lái)打獲得任意進(jìn)程的句柄,并

且指定了所有的訪(fǎng)問(wèn)權(quán)。

四 總結(jié)

用戶(hù)模式的內(nèi)存掃描還是具有想當(dāng)?shù)木窒扌?,它不能完全掃?/p>

Windows2000的全部?jī)?nèi)存空間。要對(duì)系統(tǒng)空間進(jìn)行掃描,在Windows2000下,用戶(hù)模式的應(yīng)用程序是不能實(shí)現(xiàn)的。要實(shí)現(xiàn)對(duì)系統(tǒng)空間的掃描,必須

通過(guò)工作于核心模式的程序—驅(qū)動(dòng)程序來(lái)實(shí)現(xiàn)。

標(biāo)簽: Windows系統(tǒng)
主站蜘蛛池模板: 亚洲片在线观看 | 国产a级高清版毛片 | 精品一久久香蕉国产线看播放 | 国产精品国产国产aⅴ | 丰满寡妇一级毛片 | 成人深夜福利在线播放不卡 | 欧美亚洲不卡 | 亚洲精品综合一区二区三区 | 黄色网址进入 | 欧美黑人性xxx猛交 欧美很黄视频在线观看 | 久久99国产一区二区三区 | 巴西一级毛片 | 久久综合综合久久 | 伊在人香蕉99久久 | 中文字幕一区中文亚洲 | 日韩免费视频播播 | 成人网18免费软件 | 精品国产午夜久久久久九九 | 久久久久久久久久久视频国内精品视频 | 成人毛片全部免费观看 | 中文字幕亚洲综合久久 | 日韩美女大全视频在线 | 国产视频二 | 免费看一级做a爰片久久 | 国产午夜精品久久久久九九 | 91久久国产成人免费观看资源 | 国产美女啪 | 国产精品久久成人影院 | 最新中文字幕乱码在线 | 一级毛片免费视频网站 | 亚洲区精品久久一区二区三区 | 福利视频99 | 国产精品免费看久久久香蕉 | 私人午夜影院 | 亚洲国产成人久久综合一区 | 亚洲精品国产一区二区在线 | 欧美另类视频一区二区三区 | 日本一道免费一区二区三区 | 欧美黄网站 | 亚洲综合色吧 | 99久久久久国产 |