羅文華
(中國刑事警察學院 網絡犯罪偵查系,遼寧 沈陽110854)
Windows操作系統環境下,每個進程都被賦予自己的虛擬地址空間。以32位操作系統為例,每個進程的虛擬地址空間為4GB,因此32位指針可以尋址從0x00000000至0xFFFFFFFF之間的任意地址。雖然每一個32位進程可使用4GB的地址空間,但并不意味著每一個進程實際擁有4GB的物理地址空間。4GB僅僅是一個虛擬地址空間,進程實際可以得到的物理內存要遠小于其虛擬地址空間。并且,進程的虛擬地址空間是為每個進程所私有的,在進程內運行的線程對內存空間的訪問都被限制在調用進程之內,而不能訪問屬于其他進程的內存空間。這樣,在不同的進程中可以使用相同地址的指針來指向屬于各自調用進程的內容而不會由此引起混亂。
為進一步保證操作系統安全,進程的虛擬地址空間被設計者人為地分為兩個部分——用戶空間與內核空間。32位操作系統中,用戶最大可以使用3GB的空間,主要存儲程序執行所需的管理結構(如進程環境塊、線程環境塊等)與數據;內核則可占據從3GB到4GB的這段地址,管理諸如進程塊(包括執行體進程塊、核心進程塊)、線程塊(包括執行體線程塊、核心線程塊)、句柄表(包含所有已被進程打開對象的指針)一類的系統結構(見圖1)。用戶進程通常情況下只能訪問用戶空間的虛擬地址,需要進行系統調用(代表用戶進程在內核態執行)時才可以訪問內核空間。用戶空間對應進程,每當進程切換,用戶空間就會隨之變化;而內核空間則由內核負責映射,并不隨進程改變,是固定的[1]。

圖1 特定進程的用戶空間與系統空間內容信息
以往的內存電子數據取證研究往往重點關注系統空間中的管理結構分析,相對忽視了用戶空間中與特定進程直接關聯的數據內容剖析,無法全面深刻揭示應用程序的細節。然而,實踐發現系統空間中存儲的一般性進程信息證據價值并不高,很難與特定的用戶行為進行關聯。因此,研究進程用戶空間中典型數據結構的證據屬性,挖掘應用程序行為秘密,業已成為內存電子數據取證領域新的關注熱點。
本節重點以32位Windows 7操作系統為背景,結合用戶空間中最重要的進程環境塊、線程環境塊、虛擬地址描述符等數據結構,描述其取證特性與分析方法。
每一個Windows進程都有一個執行體進程塊(EPROCESS),負責描述進程的基本信息(如進程ID、父進程ID、程序名、進程優先級、內存管理信息、設備映像等),并指向其他與進程控制相關的數據結構。EPROCESS結構的首部是核心進程塊(KPROCESS,也成PCB),主要包含CPU調度時需要的信息,如進程狀態、時間片大小等。需要指出的是,EPROCESS與KPROCESS均位于系統空間中,然而另一描述進程的重要結構——進程環境塊(PEB)則處于用戶空間。PEB位于EPROCESS頭部偏移0x1a8處(見圖2),重點存放進程運行所需的環境信息,因為其中的數據經常需要用戶進行修改,放在系統空間中會導致系統隱患和頻繁的操作模式切換,因此該結構位于用戶空間中。

圖2 EPROCESS頭部偏移0x1a8處含有指向PEB結構的指針
PEB結構中(見圖3),有如下域值信息值得取證調查人員特別關注。ImageBaseAddress(偏移0x008處)域可以用來找尋映像(即可執行文件)的基地址;Ldr(偏移0x008處)列舉所有被加載的模塊(利用下文所述VAD結構也可實現此目的);基于ProcessParameters(偏移0x010處)則可以抽取進程傳遞的參數;Process Heap(偏移0x018處)指向堆指針列表,NumberOfHeaps(偏移0x088處)給出了堆列表的大小,ProcessHeaps(偏移0x090處)則直接指向了堆列表中的第一個堆(即缺省堆),綜合上述三種域值信息能夠實現歸屬于特定進程的堆結構分析;AnsiCodePageData(偏移0x058處)、OemCodePageData(偏移 0x05C 處)、UnicodeCase TableData(偏移0x060處)分別指向了代碼頁中特定編碼格式的數據,可在其指定的頁面空間中實現已知關鍵字的搜索。

圖3 PEB結構體具體信息(部分)
每個進程都有一個或多個線程,這些線程由執行體線程塊(ETHREAD)(主要包含有線程創建時間、結束時間、當前狀態、優先級別等信息)進行描述。ETHREAD的首部為核心線程塊(KTHREAD),其內存儲有分發器(內核中負責調度的例程集合)頭部、總用戶時間、總內核時間、棧結構等。ETHREAD和它所指向的結構通常都位于系統地址空間中,唯一的例外是線程環境塊(TEB)。由于操作系統要在TEB中保存頻繁使用的線程相關數據,因此它位于用戶地址空間中。KTHREAD結構偏移0x088處即為指向TEB結構體的指針(見圖4),它存放在比PEB所在地址低的地方。進程中的每個線程都有自己的一個TEB,并主要以棧的方式進行存儲[1]。

圖4 KTHREAD頭部偏移0x088處含有指向TEB結構的指針
TEB的首部為NT_TIB結構格式的NtTib域,基于其內含的StackBase與StackLimit可實現棧信息的深度挖掘;偏移0x030處的ProcessEnvironmentBlock指向PEB結構,用于線程與所屬進程的關聯;偏移0x040處的Win32ThreadInfo則含有32位進程的描述信息;ActivationContextStackPointer(偏移 0x1a8 處)負責指向棧的上下文數據;StaticUnicodeString(偏移0xbf8 處)、StaticUnicodeBuffer(偏移 0xc00 處)、Thread PoolData(偏移0xf90)指向了非二進制信息的存儲區域,可用于關鍵字搜索;0xf6c處的WinSockData則描述了網絡通訊數據(如果存在的話)。具體信息如圖5所示。

圖5 TEB結構體具體信息(部分)
Windosws系統使用虛擬地址描述符VAD描述進程的虛擬地址空間。對于每一個進程,內存管理器都需要為其分配一組VAD節點,用來描述該進程地址空間的狀態。這些VAD節點被組織成一棵自平衡的二叉樹,以便使查找過程迅速高效。當一個進程提出內存空間請求時,內存管理器就創建一個VAD節點來保存此次內存請求所提供的相關信息,比如被保留的地址范圍、共享或是私有、是否可被繼承,以及應用頁面的保留屬性等。EPROCESS頭部偏移0x278處的VadRoot域使用MMVAD結構描述VAD二叉樹節點,內含該VAD節點的左右孩子節點、所屬進程等信息(見圖6),因此利用該結構可以實現特定進程涉及的所有VAD節點的遍歷。另外,依靠VAD二叉樹能夠確定地址空間類型,私有(private)或是已映射(mapped)。所謂私有是指該區域只存在于特定進程的地址空間中,而已映射區域卻可以存在于多個進程的地址空間中[2]。

圖6 MMVAD結構體具體信息
基于圖6還可發現該結構體中包含有一指向MSUBSECTION結構的指針MappedSubsection(偏移0x024處),MSUBSECTION結構首部為指向控制區域CONTROL_AREA的指針,如果該指針為空,則表示該區域屬性為私有,否則為已映射。已映射區域可細分為FILE_OBJECT和SECTION_OBJECT兩種類型,FILE_OBJECT表示磁盤文件在內存中的映射,SECTION_OBJECT則表示多個進程間的共享內存區域(如果CONTROL_AREA結構體中的FilePointer指針為空,即表示該區域類型為 SECTION_OBJECT)。CONTROAL_AREA結構首部就是指向SEGMENT結構的指針,而在SEGMENT結構中同樣含有一指針指向CONTROAL_AREA結構。在使用Rootkit技術修改EPROCESS結構體中的雙向鏈表指針ActiveProcessLinks,使進程從鏈表中脫離的情況下,可通過掃描SEGMENT結構體,逆向發現被隱藏的進程[3]。利用VAD二叉樹可以發現進程間的共享區域,直至挖掘出對象句柄表(Object Handle Table)的細節信息,具體流程如圖7所示。

圖7 基于VAD發現共享的內存區域
本節利用Windbg(Windows平臺下的用戶態和內核態調試工具)工具,重點基于第2節所述管理結構說明針對進程用戶空間的電子數據取證方法具體應用。Windbg能夠用于調試在線系統和鏡像文件 (擴展名為DMP),利用工具自帶的“process”命令可獲得特定進程的EPROCESS結構的內存地址信息,利用該地址可以追溯用戶空間中其他重要的管理結構。實例中“win32dd.exe”的EPROCESS結構首地址為0x87ccb030,其結構頭部偏移0x1a8處出現有“Peb:0x7ffdd000_PEB”,可知該進程環境塊的起始地址為0x7ffdd000。圖8所示為基于0x7ffdd000地址解析出的PEB內容。

圖8 起始地址為0x7ffdd000的PEB具體信息(部分)
以Ldr域為例,該域當前值為 0x77df7880,指向PEB_LDR_DATA結構。深入分析該結構發現,其內含有名為 InLoadOrderModuleList(0x221990-0x245648)和 InMemoryOrderModuleList(0x221998-0x245650)的鏈表(LIST_ENTRY)(見圖9)。依據鏈表存儲的地址,即可實現加載模塊的挖掘。

圖9 起始地址為0x77df7880的PEB_LDR_DATA具體信息
按照 EPROCESS→KPROCESS→ThreadListHead→ETHREAD→KTHREAD→TEB的次序,找尋到該進程的第一個線程的地址為0x87e7e298,其具體內容如圖10所示。該結構體中最重要的就是首部NtTib域,其中含有StackBase、StackLimit等歸屬于特定線程的棧屬性,利用這些信息可以抽取出被調用函數的地址及參數。

圖10 起始地址為0x87e7e298的TEB具體信息(部分)
EPROCESS頭部偏移0x278處的VadRoot值為0x875c9780,其左右孩子節點地址分別為0x87dd3 b00、0x87ff0ac8,Subsection 結構與 MappedSubsection結構的指針同為0x88518a70(見圖11)。需要指出的是,每個VAD二叉樹節點均為MMVAD結構,因此基于根節點可以獲知整個二叉樹的信息。

圖11 VAD二叉樹根節點信息
vad命令后接二叉樹根節點地址可以顯示該樹全部節點信息(見圖12),其中包括每個樹節點的虛擬地址、所在層級、提交類型、讀寫權限等。以DLL文件為例,通常就包含在提交類型為“Mapped”、讀寫權限為“EXECUTE_WRITECOPY”的VAD空間中。如果要對DLL文件進行調查,便可重點針對此類VAD空間進行挖掘。

圖12 獲取VAD二叉樹信息
選取0x87a7bef8節點描述的虛擬地址區域進行解析,其 MappedSubsection域值為 0x87afc428;MappedSubsection域中ControlArea指針值為0x87 afc3d8;ControlArea域中包含有指向Segment的指針0x8ac56c50;而Segment域中包含有指向ControlArea的指針0x87afc3d8(見圖13)。利用互逆的這兩個指針可實現進程結構體與對象句柄的追蹤。另外,ControlArea域中還包含有一名為FilePointer的指針,負責指向具體的FILE_OBJECT對象;在該對象的FileName域中會出現有被調用的動態鏈接庫文件的完整路徑與文件名稱。

圖13 基于內存數據結構獲取DLL文件信息
文中重點分析對象是Windows操作系統內存轉儲(DMP)文件,同時 ProDiscover IR、Mandiant Memoryze、Moonsols DumpIt等工具也可生成該格式文件。而對于由DD(已升級到Windows和Linux環境下均可使用)、Mantech mdd等工具生成的內存映像文件,則無法使用WinDbg進行信息獲取,但可使用Winhex一類的十六進制編輯器完成取證分析。另外,本文應用實例基于特定進程,在需要針對整個鏡像中的進程用戶空間進行深度分析時,可借助開源工具Volatility予以實現[4]。進程用戶空間中還有一些用于實現特定功能或傳遞關鍵信息的子結構,進一步挖掘這些結構的電子數據取證特性,從而全面深刻揭示用戶程序操作行為,將是課題組下一步的重點工作。
參考文獻:
[1]Russinovich MR,Solomon DA.Microsoft windows Internals:Windows Server 2008 and Window Vista[M].5th ed.USA:Microsoft Press,2012:146-253.
[2]Okolica J,Peterson GL.Windows operating systems agnostic memory analysis[J].Digital Investigation 2010,(7)::48-56.
[3]Hejazi SM,Talhi C,Debbabi M.Extraction of forensically sensitive information from windows physical memory[J].Digital Investigation,2009,6(S1):121-131.
[4]羅文華,湯艷君.基于Volatility的內存信息調查方法研究[J].中國司法鑒定,2012,(4):90-93.