PE檔案解析-異常處理表與數字簽名
一、異常處理表
1.位置及概述
PE檔案頭可選映像頭中資料目錄表的第4成員IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]指向異常處理表,它儲存在PE檔案中,通常在".pdata"區段。
x86系統採用動態的方式構建SEH結構,相比而言x64系統下采用靜態的方式處理SEH結構。
2.異常處理表結構
資料目錄表的第四個元素指向異常表,RVA指向的是一個IMAGE_IA64_RUNTIME_FUNCTION_ENTRY的結構體,其結構如下:
typedef struct _IMAGE_IA64_RUNTIME_FUNCTION_ENTRY {
DWORD BeginAddress; //與SEH相關程式碼的起始偏移地址
DWORD EndAddress; //與SEH相關程式碼的末尾偏移地址
DWORD UnwindInfoAddress; //指向描述上面兩個欄位之間程式碼異常資訊的UNWIND_INFO
} IMAGE_IA64_RUNTIME_FUNCTION_ENTRY, *PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY;
BeginAddress與EndAddress之間,是異常處理函式的內容。UnwindInfoAddress指向的位置是用來描述BeginAddress與EndAddress之間的程式碼異常屬性資訊的UNWIND_INFO。UNWIND_INFO也叫作異常展開資訊,此結構用來描述堆疊指標的記錄屬性與暫存器中儲存的地址屬性,它的結構體如下:
struct _UNWIND_INFO { UBYTE Version:3; UBYTE Flags:5; UBYTE SizeOfProlog; UBYTE CountOfCodes; UBYTE FrameRegister:4; UBYTE FrameOffset:4; UNWIND_CODE UnwindCode[1]; union { // If (Flags & UNW_FLAG_EHANDLER) OPTIONAL ULONG ExceptionHandler;//異常/終止函式的映像相對地址指標 // Else if (Flags & UNW_FLAG_CHAININFO) OPTIONAL ULONG FunctionEntry;//展開資訊鏈的映像相對地址指標 }; // If (Flags & UNW_FLAG_EHANDLER) ULONG ExceptionData[1];//異常處理程式的資料 } UNWIND_INFO, *PUNWIND_INFO;
Version:異常展開資訊的版本號,一般為0x001
Flags:共有四種標誌:
1.當它為0x0的時候表示UNW_FLAG_NHANDLER,沒有異常處理函式。
2.當它為0x1的時候表示UNW_FLAG_EHANDLER,有異常處理函式。
3.當它為0x2的時候表示UNW_FLAG_UHANDLER,有系統預設的處理函式。
4.當它為0x4的時候表示UNW_FLAG_CHAININFO,表示FunctionEntry指向的是前一個RUNTIME_FUNCTION的RAV。
SizeOfProlog:函式起始部分位元組的長度
CountOfCodes:UNWIND_INFO結構包含的UNWIND_CODE結構數
FrameRegister:暫存器幀指標,為0則指定函式不使用框架
FrameOffset:若上面欄位不為0,表示函式偏移
UnwindCode:指定永久性暫存器與RSP的陣列專案數
ExceptionHandler:異常控制代碼
FunctionEntry:展開資訊鏈(函式)的映像相對地址指標(如果設定了UNW_FLAG_CHAININFO標識)
ExceptionData:異常處理程式的資料
異常處理相關內容參考自:https://blog.csdn.net/tutucoo/article/details/83828700
二、數字簽名
1.位置描述
數字簽名有時又叫做安全表,用於儲存Authenticode格式的數字簽名。如果一個PE檔案有數字簽名,資料目錄表的第5成員IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]就指向數字簽名,判斷方法是該資料目錄的VirtualAddress成員不為0。該VirtualAddress不同於其他資料,在這裡代表了檔案偏移地址,而不是RVA地址。通常該結構儲存在檔案末尾。
Authenticode®是一種數字簽名格式,它是用來驗證二進位制軟體的來源和完整性。Authenticode是基於公開密匙加密標準(PKCS) #7 來簽名資料,並使用X.509證書來繫結經過數字簽發的二進位制程式與其軟體釋出者的身份的聯絡。這份文件包含Authenticode簽名的結構和技術細節。
這份文件不討論如何簽發/處理X.509證書,如何使用Windows SDK工具來簽署二進位制程式,如何部署程式碼簽名基礎設施,或者相關的Windows® API函式。這方面的相關資訊可以檢視在本文件最後的“資源”章節。
本資料應用於下列作業系統:
Windows Server® 2008
Windows Vista®
Windows Server 2003
Windows® XP
Windows 2000
這裡引用和討論的相關資源列於這份文件的結尾。
在PE檔案中的可信程式碼數字簽名是PKCS #7 簽名塊結構。該簽名可以保證:
· 這份軟體源於某個確定的軟體釋出者。
· 這份軟體自從簽署以來沒有經過修改。
一份PKCS #7 簽名塊結構包含該PE檔案的雜湊值、通過軟體釋出者私匙建立的簽名以及將軟體釋出者的簽名密匙繫結到一個合法實體的X.509 v3證書。一份PKCS #7簽名塊可以包含以下可選資訊:
· 關於軟體釋出者的描述
· 軟體釋出者的連結
· 可信程式碼簽名的時間戳
簽名時間戳由時間戳權威機構(TSA)生成,並且保證軟體釋出者所做的簽名在這個時間戳之前已經存在。這個時間戳可以延長了這個簽名的生命期,即便相關的簽名證書已經過期或者後來被廢除。
可信程式碼簽名可以被嵌入到Windows的PE檔案中,位於PE檔案的Optional Header Data Directories結構中Certificate Table所指向的位置。當可信程式碼簽名被用於簽署一個Windows PE檔案時,計算檔案數字簽名雜湊值的演算法略過PE檔案結構中的特定欄位。當把數字簽名嵌入檔案時,簽名過程可以修改這些欄位,而不致於影響檔案的雜湊值。
圖1顯示了一幅簡單的PE檔案全域性圖,它描述了數字簽名是如何包含在PE檔案中的。它包含了嵌入的可信程式碼數字簽名和指出那些被略過計算PE檔案雜湊值的PE結構欄位。
關於PE檔案結構的細節,請參閱“Microsoft Portable Executable and Common Object File Format Specification”(PE/COFF specification)。
關於可信程式碼數字簽名中PKCS #7部分的細節,請參閱本文件後面的Abstract Syntax Notation version 1 (ASN.1) 結構定義。
關於可信程式碼數字簽名如何計算PE檔案雜湊值的細節,參閱本文件後面的“Calculating the PE Image Hash”。
2.數字簽名結構
資料目錄表的第5成員指向數字簽名,該成員的VirtualAddress是數字簽名的物理偏移地址,Size是簽名檔案的長度。該地址指向的是一個WIN_CERTIFICATE結構體。f
typedef struct _WIN_CERTIFICATE {
DWORD dwLength;
WORD wRevision;
WORD wCertificateType; // WIN_CERT_TYPE_xxx
BYTE bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
dwLength:此結構體的長度。
wRevision:在bCertificate裡面保護的證書的版本號,版本號有兩種,如下表,一般為0x0200。
值 | 資訊 | Win32 SDK中的巨集定義名 |
0x0100 | Win_Certificate的老版本 | WIN_CERT_REVISION_1_0 |
0x0200 | Win_Certificate的當前版本 | WIN_CERT_REVISION_2_0 |
wCertificateType:證書型別,有如下表格中的型別:
值 | 資訊 | Win32 SDK中的巨集定義名 |
0x0001 | X.509證書 | WIN_CERT_TYPE_X509 |
0x0002 | 包含PKCS#7的SignedData的結構 | WIN_CERT_TYPE_PKCS_SIGNED_DATA |
0x0003 | 保留 | WIN_CERT_TYPE_RESERVED_1 |
0x0004 | 終端伺服器協議堆疊證書籤名 | WIN_CERT_TYPE_TS_STACK_SIGNED |
bCertificate:包含一個或多個證書,一般來說這個證書的內容一直到安全表的末尾。