1. 程式人生 > >入門級 PDF 檔案格式分析

入門級 PDF 檔案格式分析

一、概述:
    結構化的文件格式PDF(Portable Document Format)是由美國排版與影象處理軟體公司Adobe於1993年首次提出的。Adobe Reader這款pdf閱讀器軟體相信大家並不陌生,人們熟知它的原因是因為它的應用相當普及,可能接觸過計算機的人中沒有幾個會不知道它,但是相信也有一部分人注意到Adobe這款軟體是因為它頻頻爆出漏洞的緣故,號稱漏洞之王的Adobe似乎有報不完的漏洞,時不時就會給人以驚喜,其潛力真是不容置疑!這樣說來,如果想對Adobe的漏洞原理進行分析。瞭解PDF檔案的格式就變得尤為重要了!
二、PDF檔案結構:
    PDF的結構可以從檔案結構和邏輯結構兩個方面來理解。PDF的檔案結構指的是其檔案物理組織方式,邏輯結構則指的是其內容的邏輯組織方式[1]。
1、資料物件型別:
    PDF檔案的基本元素是PDF物件(PDF Object),PDF物件包括直接物件(Direct Object)和間接物件(Indirect Object);其中直接物件如下幾種基本型別:布林型(Boolean)、數值型(Number)、字串型(String)、名字型(Name)、陣列型(Array)、字典型(Dictionary)、流物件(Stream)以及空物件(Null);間接物件是一種標識了的PDF物件,這個標識叫作間接物件的ID。標識的目的是為了讓別的PDF物件引用。任何PDF物件標識後都變成了間接物件。
2、PDF檔案結構:
    PDF的檔案結構(即物理結構)包括四個部分:檔案頭(Header)、檔案體(Body)、交叉引用表(Cross-reference Table)和檔案尾(Trailer),如圖-1所示:

     
                    圖-1 PDF檔案結構
    檔案頭(Header)指明瞭該檔案所遵從PDF規範的版本號,它出現在PDF檔案的第一行。如%PDF-1.6表示該檔案格式符合PDF1.6規範。
    檔案體(Body)由一系列的PDF間接物件組成。這些間接物件構成了PDF檔案的具體內容如字型、頁面、影象等等。
    交叉引用表(Cross-reference Table)則是為了能對間接物件進行隨機存取而設立的一個間接物件地址索引表。
    檔案尾(Trailer)聲明瞭交叉引用表的地址,指明檔案體的根物件(Catalog),還儲存了加密等安全資訊。根據檔案尾提供的資訊,PDF的應用程式可以找到交叉引用表和整個PDF檔案的根物件,從而控制整個PDF檔案。
3、PDF文件結構:
PDF的文件結構反映了檔案體中間接物件間的等級層次關係。PDF的文件結構是一種樹型結構如圖-2所示。樹的根節點就是PDF檔案的目錄物件(Catalog)。這個目錄物件是PDF文件的根物件,包含PDF文件的大綱(Outlines)和頁面組物件(Pages)。根節點下有四個子樹:頁面樹(Pages Tree)、書籤樹(Outline Tree)、線索樹(Article Threads)、名字樹(Named Destination)。

     
                             圖-2 PDF文件結構

4、PDF中的資源:
    PDF檔案中的內容(如文字、圖形、影象)都儲存在頁面物件的Contents關鍵字對應的流物件(Stream)中。內容流(Content Stream)中用到了很多基本物件如數字、字串,這些都是用直接物件(Direct Object)表示的。但還有其他一些物件如字型(Font),本身就是用字典物件(Dictionary)或流物件(Stream)來表示的,無法用直接物件表示,而內容流中又不能出現任何間接物件,於是就將這些物件命名,並在內容流中用相應的名字來表示它們。這些用名字來表示的物件就稱作命名資源(Named Resources)。   
    在頁面物件中有一個資源項(Resources Key),該項列出了內容流中用到的所有資源,並建立了一個資源名字與資源物件本身的對映表。   
    PDF中的命名資源有:指令集(ProcSet)、字型(Font)、色彩空間(Color space)、外部物件(XObject)、擴充套件的圖形狀態(Extended graphics state)、底紋(Pattern)、使用者擴充套件標記列表(Property list)。非命名資源有:Encoding、Font descriptor、Halftone、Function、CMap。由於非命名資源都是被隱含引用的,因此沒有命名的需要。
5、PDF頁面描述命令:
    PDF共有60個頁面描述指令。這60個頁面描述指令描述了頁面上的一系列圖形物件。這些圖形物件可分為四類:路徑物件(Path Object),文字物件(Text Object),影象物件(Image   Object),外部物件(XObject)。
三、PDF檔案分析:
    PDF檔案是一種文字和二進位制混排的格式,但是Adobe更願意讓人把它當成二進位制的檔案,所以在裡面建議當檔案裡面的文字太多的時候,可以加一些二進位制的註釋,好讓現有的一些編譯器把它當成二進位制檔案。裡面的文字主要是對檔案結構的一種描述,二進位制的內容來自於三個方面:1、圖片;2、字型;3、壓縮後的Post Script[2]。
     下面使用只有一句話的一個PDF檔案進行分析,使用UltraEdit開啟PDF檔案,然後選擇以十六進位制編輯就能看到類似下面的資訊,我將著重挑選部分資訊進行介紹,並使用#進行註釋並在後面做相關解釋。

%PDF-1.6        #檔案頭,說明符合PDF1.6規範
%懺嫌    #下面就是很多的Object物件
2 0 obj    #Object物件,其中2是Obj順序號,0是Obj的版本號
<<     # <<>>之間為Object物件的內容
[/ICCBased 3 0 R]
>>
Endobj    #Object結束關鍵字

7 0 obj
<<
/Filter
/FlateDecode   #流物件的壓縮方式為zip的壓縮演算法
/Length 148   #流物件的長度
>>
Stream    #流物件
PDF檔案格式分析 Author:Cryin' #檔案內容資訊,注:此處為直觀從而手動填寫的
Endstream   #流物件結束標誌
Endobj

8 0 obj
<<
/Contents 7 0 R    #頁面內容物件的物件號為7
/MediaBox [0 0 595.2 841.68] #頁面顯示大小,以畫素為單位
/PageIndex 1 
/Parent 1 0 R   #其父物件號為1以及Pages物件 
/Resources    #該頁包含的資源
<</Font <</F4 4 0 R >>   #字型的型別
/Shading <<>>
/XObject <<>>     #外部物件
/ColorSpace <</CS1 2 0 R>> >>    #色彩空間
/Type /Page 
>>
Endobj

1 0 obj
<<
/Count 1     #頁碼數量為1
/Kids [8 0 R ]   #kids物件說明它的子頁物件為8 
/Type /Pages 
>>
Endobj

13 0 obj
<<
/Author (? Cryin') 
/CreationDate (D:20100926145832+08'00') 
/Title (? PDF檔案格式分析) 
>>
endobj

Xref     #表示交叉引用表開始
0 14     #0表明引用表描述的物件從0開始,8說明共有8個物件
0000000000 65536 f #一般pdf都是以這行開始交叉引用表的,起始地址0和產生號
0000003195 00000 n #表示物件1,就是catalog,3195為偏移地址n表示物件在使用
0000000018 00000 n
0000000051 00000 n
0000003464 00000 n
0000000000 00000 f
0000004282 00000 n
0000002728 00000 n
0000002992 00000 n
0000003256 00000 n
0000003892 00000 n
0000003620 00000 n
0000008660 00000 n
0000008712 00000 n
Trailer    #說明檔案尾物件開始
<</Size 14    #14說明PDF檔案物件數目
/Root 12 0 R    #說明跟物件號為12
/Info 13 0 R>>  
startxref
8980    #8980為交叉引用表的偏移地址,此處為十進位制表示
%%EOF    #檔案結束標誌

四、結束語:
    PDF檔案基本的格式就分析到這裡了,當然這裡並沒有談到對PDF漏洞檔案的分析,本例分析的PDF並沒有巢狀JavaScrpit語句,但PDF漏洞分析的著手點就在於檔案巢狀的JavaScrpit或者是flash檔案。PDF檔案漏洞一般是利用JavaScript來實現堆噴射完成溢位[3]。這裡就必然會在PDF檔案中巢狀JavaScript語句了,PDF中巢狀的JavaScript可以通過Obj物件裡面的/OpenAction這項定位其具體位置,不過一般都是經過FlateDecode編碼過的, 總之在分析PDF漏洞時先找出JS語句就可以找到其中的shellcode,也可以自己修改JavaScript。這樣對漏洞的分析就能更順利的開展,當然具體分析還牽扯一些除錯的過程,這方面本人也正在學習階段,難免表述有所錯誤,還請見諒。總之,知識就是不斷的總結和積累,也希望這篇簡短的文章能給大家帶來些許幫助!