<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    [系統安全] 三十四.惡意代碼檢測(4)編寫代碼自動提取IAT表、字符串及時間戳溯源地區

    VSole2021-12-29 09:30:29

    一.PE文件格式

    什么是PE文件?

    PE文件的全稱是Portable Executable,意為可移植的可執行的文件,常見的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微軟Windows操作系統上的程序文件(可能是間接被執行,如DLL)。

    EXE文件格式:

    • DOS:MZ格式
    • WIndows 3.0/3.1:NE(New Executable)、16位Windows可執行文件格式

    為什么要重點學習這種文件格式呢?

    PE文件是可移植、可執行、跨Win32平臺的文件格式

    • 所有Win32執行體(exe、dll、kernel mode drivers)
    • 知道PE文件本質后,能更好進行惡意樣本分析、APT攻擊分析、勒索病毒分析
    • 了解軟件加密和加殼的思想,能夠PJ相關的PE文件
    • 它是您熟悉Windows操作系統的第一步,包括EXE程序怎么映射到內存,DLL怎么導入等
    • 軟件逆向工程的基本思想與PE文件格式息息相關
    • 如果您想成為一名黑客、系統安全工程師,那么精通PE文件是非常必要的


    可執行程序是具有不同的形態的,比如用戶眼中的QQ如下圖所示。


    本質上,QQ如下圖所示。

    PE文件格式總體結構

    接著讓我們來欣賞下PE文件格式總體結構圖,包括:MZ頭部、DOS stub、PE文件頭、可選文件頭、節表、節等。

    本文的第二部分我們將對PE文件格式進行詳細解析。比如,MZ頭文件是定位PE文件頭開始位置,用于PE文件合法性檢測。DOS下運行該程序時,會提示用戶“This Program cannot be run in DOS mode”。

    PE文件格式與惡意軟件的關系

    • 何為文件感染或控制權獲取?
    • 使目標PE文件具備或啟動病毒功能(或目標程序)
    • 不破壞目標PE文件原有功能和外在形態(如圖標)等
    • 病毒代碼如何與目標PE文件融為一體呢?
    • 代碼植入
    • 控制權獲取
    • 圖標更改
    • Hook

    PE文件解析常用工具包括:

    • PEView:可按照PE文件格式對目標文件的各字段進行詳細解析。
    • Stud_PE:可按照PE文件格式對目標文件的各字段進行詳細解析。
    • Ollydbg:可跟蹤目標程序的執行過程,屬于用戶態調試工具。
    • UltraEdit \ 010Editor:可對目標文件進行16進制查看和修改。

    二.PE文件格式解析

    該部分實驗內容:

    • 使用010Editor觀察PE文件例子程序hello-2.5.exe的16進制數據
    • 使用Ollydbg對該程序進行初步調試,了解該程序功能結構,在內存中觀察該程序的完整結構
    • 使用010Editor修改該程序,使得該程序僅彈出第二個對話框

    1.010Editor解析PE文件

    PE文件結構如下圖所示,我推薦大家使用010Editor工具及其模板來進行PE文件分析。

    MZ頭部+DOS stub+PE文件頭+可選文件頭+節表+節

    (1) 使用010Editor工具打開PE文件,并運行模板。

    該PE文件可分為若干結構,如下圖所示。

    (2) MZ文件頭(000h-03fh)。

    下圖為hello-2.5.exe的MZ文件頭,該部分固定大小為40H個字節。偏移3cH處字段Offset to New EXE Header,指示“NT映象頭的偏移地址”,其中000000B0是NT映象頭的文件偏移地址,定位PE文件頭開始位置,用于PE文件合法性檢驗。

    000000B0指向PE文件頭開始位置。

    (3) DOS插樁程序(040h-0afh)

    DOS Stub部分大小不固定,位于MZ文件頭和NT映象頭之間,可由MZ文件頭中的Offset to New EXE Header字段確定。下圖為hello-2.5.exe中的該部分內容。

    (4) PE文件頭(0b0h-1a7h)

    該部分包括PE標識、映像文件頭、可選文件頭。

    • Signature:字串“PE\0\0”,4個字節(0b0H~0b4H)
    • 映象文件頭File Header:14H個字節(0b5H~0c7H)
    • 偏移2H處,字段Number of Section 給出節的個數(2個字節):0003
    • 偏移10H處,字段Size of Optional Header 給出可選映象頭的大小(2個字節):00E0
    • 可選映象頭Optional Header:0c8H~1a7H

    對應解析如下圖所示,包括PE標識、X86架構、3個節、文件生成時間、COFF便宜、可選頭大小、文件信息標記等。

    010Editor使用模板定位PE文件各節點信息。

    PE文件可選文件頭224字節,其對應的字段信息如下所示:

    typedef struct _IMAGE_OPTIONAL_HEADER {
        WORD    Magic;                  /*機器型號,判斷是PE是32位還是64位*/
        BYTE    MajorLinkerVersion;          /*連接器版本號高版本*/
        BYTE    MinorLinkerVersion;          /*連接器版本號低版本,組合起來就是 5.12 其中5是高版本,C是低版本*/
        DWORD   SizeOfCode;               /*代碼節的總大小(512為一個磁盤扇區)*/
        DWORD   SizeOfInitializedData;        /*初始化數據的節的總大小,也就是.data*/
        DWORD   SizeOfUninitializedData;       /*未初始化數據的節的大小,也就是 .data ? */
        DWORD   AddressOfEntryPoint;          /*程序執行入口(OEP) RVA(相對偏移)*/
        DWORD   BaseOfCode;               /*代碼的節的起始RVA(相對偏移)也就是代碼區的偏移,偏移+模塊首地址定位代碼區*/
        DWORD   BaseOfData;               /*數據結的起始偏移(RVA),同上*/
        DWORD   ImageBase;               /*程序的建議模塊基址(意思就是說作參考用的,模塊地址在哪里)*/
        DWORD   SectionAlignment;           /*內存中的節對齊*/
        DWORD   FileAlignment;             /*文件中的節對齊*/
        WORD    MajorOperatingSystemVersion;    /*操作系統版本號高位*/
        WORD    MinorOperatingSystemVersion;    /*操作系統版本號低位*/
        WORD    MajorImageVersion;          /*PE版本號高位*/
        WORD    MinorImageVersion;          /*PE版本號低位*/
        WORD    MajorSubsystemVersion;        /*子系統版本號高位*/
        WORD    MinorSubsystemVersion;        /*子系統版本號低位*/
        DWORD   Win32VersionValue;          /*32位系統版本號值,注意只能修改為4 5 6表示操作系統支持nt4.0 以上,5的話依次類推*/
        DWORD   SizeOfImage;               /*整個程序在內存中占用的空間(PE映尺寸)*/
        DWORD   SizeOfHeaders;            /*所有頭(頭的結構體大小)+節表的大小*/
        DWORD   CheckSum;               /*校驗和,對于驅動程序,可能會使用*/
        WORD    Subsystem;              /*文件的子系統 :重要*/
        WORD    DllCharacteristics;         /*DLL文件屬性,也可以成為特性,可能DLL文件可以當做驅動程序使用*/
        DWORD   SizeOfStackReserve;         /*預留的棧的大小*/
        DWORD   SizeOfStackCommit;          /*立即申請的棧的大小(分頁為單位)*/
        DWORD   SizeOfHeapReserve;          /*預留的堆空間大小*/
        DWORD   SizeOfHeapCommit;           /*立即申請的堆的空間的大小*/
        DWORD   LoaderFlags;             /*與調試有關*/
        DWORD   NumberOfRvaAndSizes;         /*下面的成員,數據目錄結構的項目數量*/
        IMAGE_DATA_DIRECTORY DataDirectory[16];  /*數據目錄,默認16個,16是宏,這里方便直接寫成16*/
    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
    

    (5) 節表(1a8h-21fh)

    • 表項大小固定,28H個字節;表項個數由映象文件頭的字段Number of Section 給出。
    • 每個表項的起始位置起(8個字節),字段Name給出對應節的名稱。
    • 每個表項的偏移14H處(4個字節),字段Offset to Raw Data給出對應節的起始文件偏移。

    該結構包括3個節,對應上圖的3個struct IMAGE_SECTION_HEADER,即“.test”、“.rdata”、“.data”節,其偏移地址對應下圖紫色區域,分別是400、600、800的位置。

    (6) 3個節

    • 400H-5ffH:代碼節
    • 600H-7ffH:引入函數節
    • 800H-9ffH:數據節

    注意,代碼節“.text”前46H為數據,后面全是0位填充值,為了實現文件的200H對齊,所以代碼節是400H到5ffH。

    (7) 引入函數節

    ?來從其他DLL中引?函數,引入了kernel32.dll和user32.dll,這個節一般名為“.rdata”。引入函數是被某模塊調用的但又不在調用者模塊中的函數,用來從其他(系統或第三方寫的)DLL中引入函數,例如kernel32.dll、gdi32.dll等。

    010Editor打開如下圖所示:

    詳細標注信息如下圖所示:(圖引自HYQ同學,再此感謝)

    (8) 數據節

    數據節實際大小58h,對齊后大小200h,地址為800h-9ffh,包括對話框彈出的具體內容。


    2.Ollydbg動態調試程序

    使用Ollydbg對該程序進行初步調試,了解該程序功能結構,在內存中觀察該程序的完整結構。注意,內存對齊單位和文件對齊單位的不同,內容和文件中IAT表內容的不同。

    第一步,打開OD加載PE文件。

    OD是一款PE文件動態調試器,此時程序斷點自動停止在程序入口點00401000H位置。

    在010Editor中,我們可以看到,該PE程序基地址是400000h,程序入口地址是1000h,兩個相加為加載至內存中的地址,即401000h。

    第二步,動態調試程序。

    當我們雙擊地址位置,則可以下斷點且變紅,比如0040100Fh。

    接著查看對應調試快捷鍵,F7是單步步入,F8是單步步過。

    我們直接按F8單步步過,此時的位置會CALL一個MessageBoxA函數。

    直接單步步過,此時會彈出第一個對話框,點擊“確定”按鈕。

    第三步,動態調試程序之數據跟隨。

    接著我們看左下角部分的內存數據,在該區域按下“Ctrl+G”在數據窗口中跟隨,輸入基地址400000。

    此時可以看到加載到內存中的數據,可以看到該數據與010Editor打開的PE文件數據一致的。

    接著繼續按F8單步步過彈出第二個窗口。

    右上角是它寄存器的值,包括各個寄存器中的數據,我們實驗中主要使用的寄存器包括EAX、ECX、EDX、EBX等。

    接著步過0040102E,它是退出進程ExitProcess的位置,此時進程已經終止,如下圖所示。

    實驗講到這里,使用OD動態調試的PE文件的基礎流程就講解完畢,后續隨著實驗深入,我們還會使用該工具。


    三.Python獲取時間戳

    接著我們嘗試通過Python來獲取時間戳,python的PE庫是pefile,它是用來專門解析PE文件的,可靜態分析PE文件。pefile能完成的任務包括:

    • 檢查頭
    • 分析部分數據
    • 檢索嵌入式數據
    • 從資源中讀取字符串
    • 警告值可疑和格式錯誤
    • PE的基本分析,喜歡寫一些領域和其他部分的PE的
    • 帶有PEiD簽名的打包程序檢測
    • PEiD簽名 生成

    推薦大家學習官方資料和github文檔。

    • https://github.com/erocarrera/pefile
    • https://pypi.org/project/pefile/
    • https://github.com/erocarrera/pefile/releases

    安裝擴展包的方法如下:

    • pip install pefile

    假設安裝成功之后,我們需要對下圖所示的軟件進行分析,該軟件是我在博客中生成的,大家直接使用即可(文章開頭的github鏈接能下載)。

    • Windows黑客編程之注入技術詳解(全局鉤子、遠線程鉤子、突破Session 0注入、APC注入)

    第一步,我們通過010Editor分析PE文件。

    其時間戳的輸出結果如下:

    • 06/19/2020 10:46:21

    我們希望通過Python寫代碼實現自動化提取,為后續自動化溯源提供幫助。

    第二步,撰寫Python代碼實現簡單分析。

    import pefile
    import os,string,shutil,re
    PEfile_Path = "MFCApplication.exe"
     
    pe = pefile.PE(PEfile_Path)
    print(type(pe))
    print(pe)
    

    輸出如下圖所示結果,這是Python包自定義的PE結構。

    squeezed text表示python的一種編程規范要求,簡稱pep8,你只需要將鼠標放到Squeezed上,右鍵Copy即可查看內容,顯示的是該PE文件的基本結構,如下所示:

    ----------Parsing Warnings----------
    Byte 0xcc makes up 17.8750% of the file's contents. This may indicate truncation / malformation.
    Suspicious flags set for section 0. Both IMAGE_SCN_MEM_WRITE and IMAGE_SCN_MEM_EXECUTE are set. This might indicate a packed executable.
    ----------DOS_HEADER----------
    [IMAGE_DOS_HEADER]
    0x0        0x0   e_magic:                       0x5A4D    
    0x2        0x2   e_cblp:                        0x90      
    0x4        0x4   e_cp:                          0x3       
    0x6        0x6   e_crlc:                        0x0       
    0x8        0x8   e_cparhdr:                     0x4       
    0xA        0xA   e_minalloc:                    0x0       
    0xC        0xC   e_maxalloc:                    0xFFFF    
    0xE        0xE   e_ss:                          0x0       
    0x10       0x10  e_sp:                          0xB8      
    0x12       0x12  e_csum:                        0x0       
    0x14       0x14  e_ip:                          0x0       
    0x16       0x16  e_cs:                          0x0       
    0x18       0x18  e_lfarlc:                      0x40      
    0x1A       0x1A  e_ovno:                        0x0       
    0x1C       0x1C  e_res:                         
    0x24       0x24  e_oemid:                       0x0       
    0x26       0x26  e_oeminfo:                     0x0       
    0x28       0x28  e_res2:                        
    0x3C       0x3C  e_lfanew:                      0x108     
    ----------NT_HEADERS----------
    [IMAGE_NT_HEADERS]
    0x108      0x0   Signature:                     0x4550    
    ----------FILE_HEADER----------
    [IMAGE_FILE_HEADER]
    0x10C      0x0   Machine:                       0x14C     
    0x10E      0x2   NumberOfSections:              0xA       
    0x110      0x4   TimeDateStamp:                 0x5EEC977D [Fri Jun 19 10:46:21 2020 UTC]
    0x114      0x8   PointerToSymbolTable:          0x0       
    0x118      0xC   NumberOfSymbols:               0x0       
    0x11C      0x10  SizeOfOptionalHeader:          0xE0      
    0x11E      0x12  Characteristics:               0x102     
    Flags: IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_EXECUTABLE_IMAGE
    ----------OPTIONAL_HEADER----------
    [IMAGE_OPTIONAL_HEADER]
    0x120      0x0   Magic:                         0x10B     
    0x122      0x2   MajorLinkerVersion:            0xE       
    0x123      0x3   MinorLinkerVersion:            0x1A      
    0x124      0x4   SizeOfCode:                    0x700C00  
    0x128      0x8   SizeOfInitializedData:         0x2F1E00  
    0x12C      0xC   SizeOfUninitializedData:       0x0       
    0x130      0x10  AddressOfEntryPoint:           0x36CE65  
    0x134      0x14  BaseOfCode:                    0x1000    
    0x138      0x18  BaseOfData:                    0x1000    
    0x13C      0x1C  ImageBase:                     0x400000  
    0x140      0x20  SectionAlignment:              0x1000    
    0x144      0x24  FileAlignment:                 0x200     
    0x148      0x28  MajorOperatingSystemVersion:   0x6       
    0x14A      0x2A  MinorOperatingSystemVersion:   0x0       
    0x14C      0x2C  MajorImageVersion:             0x0       
    0x14E      0x2E  MinorImageVersion:             0x0       
    0x150      0x30  MajorSubsystemVersion:         0x6       
    0x152      0x32  MinorSubsystemVersion:         0x0       
    0x154      0x34  Reserved1:                     0x0       
    0x158      0x38  SizeOfImage:                   0xD54000  
    0x15C      0x3C  SizeOfHeaders:                 0x400     
    0x160      0x40  CheckSum:                      0x0       
    0x164      0x44  Subsystem:                     0x2       
    0x166      0x46  DllCharacteristics:            0x8140    
    0x168      0x48  SizeOfStackReserve:            0x100000  
    0x16C      0x4C  SizeOfStackCommit:             0x1000    
    0x170      0x50  SizeOfHeapReserve:             0x100000  
    0x174      0x54  SizeOfHeapCommit:              0x1000    
    0x178      0x58  LoaderFlags:                   0x0       
    0x17C      0x5C  NumberOfRvaAndSizes:           0x10      
    DllCharacteristics: IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLLCHARACTERISTICS_NX_COMPAT, IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
    ----------PE Sections----------
    [IMAGE_SECTION_HEADER]
    0x200      0x0   Name:                          .textbss
    0x208      0x8   Misc:                          0x35B30B  
    0x208      0x8   Misc_PhysicalAddress:          0x35B30B  
    0x208      0x8   Misc_VirtualSize:              0x35B30B  
    0x20C      0xC   VirtualAddress:                0x1000    
    0x210      0x10  SizeOfRawData:                 0x0       
    0x214      0x14  PointerToRawData:              0x0       
    0x218      0x18  PointerToRelocations:          0x0       
    0x21C      0x1C  PointerToLinenumbers:          0x0       
    0x220      0x20  NumberOfRelocations:           0x0       
    0x222      0x22  NumberOfLinenumbers:           0x0       
    0x224      0x24  Characteristics:               0xE00000A0
    Flags: IMAGE_SCN_CNT_CODE, IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE
    Entropy: 0.000000 (Min=0.0, Max=8.0)
    MD5     hash: d41d8cd98f00b204e9800998ecf8427e
    SHA-1   hash: da39a3ee5e6b4b0d3255bfef95601890afd80709
    SHA-256 hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    SHA-512 hash: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
    ....
    

    對應于010Editor分析的結果,前后是一致的。

    同時,我們可以輸入help(pefile.PE) 查看幫助信息,它定義了pefile包的一些函數和屬性。

    Help on class PE in module pefile:
    class PE(builtins.object)
     |  PE(name=None, data=None, fast_load=None)
     |  
     |  A Portable Executable representation.
     |  
     |  This class provides access to most of the information in a PE file.
     |  
     |  It expects to be supplied the name of the file to load or PE data
     |  to process and an optional argument 'fast_load' (False by default)
     |  which controls whether to load all the directories information,
     |  which can be quite time consuming.
     |  
     |  pe = pefile.PE('module.dll')
     |  pe = pefile.PE(name='module.dll')
     |  
     |  would load 'module.dll' and process it. If the data is already
     |  available in a buffer the same can be achieved with:
     |  
     |  pe = pefile.PE(data=module_dll_data)
     |  
     |  The "fast_load" can be set to a default by setting its value in the
     |  module itself by means, for instance, of a "pefile.fast_load = True".
     |  That will make all the subsequent instances not to load the
     |  whole PE structure. The "full_load" method can be used to parse
     |  the missing data at a later stage.
     |  
     |  Basic headers information will be available in the attributes:
     |  
     |  DOS_HEADER
     |  NT_HEADERS
     |  FILE_HEADER
     |  OPTIONAL_HEADER
     |  
     |  All of them will contain among their attributes the members of the
     |  corresponding structures as defined in WINNT.H
     |  
     |  The raw data corresponding to the header (from the beginning of the
     |  file up to the start of the first section) will be available in the
     |  instance's attribute 'header' as a string.
     |  
     |  The sections will be available as a list in the 'sections' attribute.
     |  Each entry will contain as attributes all the structure's members.
     |  
     |  Directory entries will be available as attributes (if they exist):
     |  (no other entries are processed at this point)
     |  
     |  DIRECTORY_ENTRY_IMPORT (list of ImportDescData instances)
     |  DIRECTORY_ENTRY_EXPORT (ExportDirData instance)
     |  DIRECTORY_ENTRY_RESOURCE (ResourceDirData instance)
     |  DIRECTORY_ENTRY_DEBUG (list of DebugData instances)
     |  DIRECTORY_ENTRY_BASERELOC (list of BaseRelocationData instances)
     |  DIRECTORY_ENTRY_TLS
     |  DIRECTORY_ENTRY_BOUND_IMPORT (list of BoundImportData instances)
     |  
     |  The following dictionary attributes provide ways of mapping different
     |  constants. They will accept the numeric value and return the string
     |  representation and the opposite, feed in the string and get the
     |  numeric constant:
     |  
     |  DIRECTORY_ENTRY
     |  IMAGE_CHARACTERISTICS
     |  SECTION_CHARACTERISTICS
     |  DEBUG_TYPE
     |  SUBSYSTEM_TYPE
     |  MACHINE_TYPE
     |  RELOCATION_TYPE
     |  RESOURCE_TYPE
     |  LANG
     |  SUBLANG
    ......
    

    第三步,撰寫代碼獲取PE文件的方法和屬性,比如section。

    import pefile
    import os,string,shutil,re
    PEfile_Path = "MFCApplication.exe"
    #解析PE文件
    pe = pefile.PE(PEfile_Path)
    print(type(pe))
    print(pe)
    #查看方法和屬性
    print(dir(pefile.PE))
    for section in pe.sections:
        print(section)
    

    輸出如下結果:

    獲取導入表信息代碼如下:

    import pefile
    import os,string,shutil,re
    PEfile_Path = "MFCApplication.exe"
    #解析PE文件
    pe = pefile.PE(PEfile_Path)
    print(type(pe))
    print(pe)
    #獲取導入表信息
    for item in pe.DIRECTORY_ENTRY_IMPORT:
        print(item.dll)
        for con in item.imports:
            print(con.name)
        print("") #換行
    

    輸出如下所示的結果,包括KERNEL32.dll、USER32.dll等。

    b'KERNEL32.dll'
    b'RtlUnwind'
    b'GetModuleHandleExW'
    b'GetCommandLineA'
    b'GetSystemInfo'
    b'CreateThread'
    ...
    b'USER32.dll'
    b'DlgDirSelectExA'
    b'FindWindowExA'
    b'FindWindowA'
    b'SetParent'
    b'ChildWindowFromPointEx'
    ...
    b'GDI32.dll'
    b'CreateEllipticRgn'
    b'CreateFontIndirectA'
    b'CreateHatchBrush'
    b'CreateICA'
    b'CreatePalette'
    b'CreatePen'
    ...
    b'MSIMG32.dll'
    b'AlphaBlend'
    b'GradientFill'
    b'TransparentBlt'
    b'ADVAPI32.dll'
    b'RegCloseKey'
    b'RegQueryValueExA'
    b'RegCreateKeyExA'
    b'RegDeleteKeyA'
    ...
    b'SHELL32.dll'
    b'SHGetPathFromIDListA'
    b'SHGetSpecialFolderLocation'
    b'SHBrowseForFolderA'
    b'SHGetDesktopFolder'
    b'DragAcceptFiles'
    ...
    b'COMCTL32.dll'
    b'InitCommonControlsEx'
    ...
    

    對應010editor的PE軟件分析結果如下:

    第四步,分析文件結構及時間戳位置。

    同樣,我們可以使用stud_PE查看文件屬性,該軟件用于顯示頭部、DOs、區段、函數等信息,包括導入表、導出表等,顯示該EXE程序加載的DLL文件及函數。

    這里我們最關心的內容是“TimeDateStamp”,接下來想辦法獲取它即可。

    typedef     struct _IMAGE_FILE_HEADER 
    {
    	+04h    WORD        Machine;              // 運行平臺
    	+06h    WORD        NumberOfSections;     // 文件的區塊數目
    	+08h    DWORD       TimeDateStamp;        // 文件創建日期和時間
    	+0Ch    DWORD       PointerToSymbolTable; // 指向符號表(主要用于調試)
    	+10h    DWORD       NumberOfSymbols;      // 符號表中符號個數(同上)
    	+14h    WORD        SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 結構大小
    	+16h    WORD        Characteristics;      // 文件屬性
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
    

    對應的Python包返回的值如下所示:

    第五步,接著我們通過pe.DOS_HEADER、pe.FILE_HEADER等方法獲取對應的內容。

    import pefile
    import os,string,shutil,re
    PEfile_Path = "MFCApplication.exe"
    #解析PE文件
    pe = pefile.PE(PEfile_Path, fast_load=True)
    print(type(pe))
    print(pe)
    #顯示DOS_HEADER
    print(pe.DOS_HEADER,"")
    #顯示NT_HEADERS
    print(pe.NT_HEADERS,"")
    #顯示FILE_HEADER
    print(pe.FILE_HEADER,"")
    #顯示OPTIONAL_HEADER
    print(pe.OPTIONAL_HEADER,"")
    

    輸出如下圖所示的結構,其中時間戳也在其中。

    作者本想通過它指定的方法提取對應的值,但一直失敗,但作為長期從事NLP和數據挖掘的程序員,這都不是事,我們通過正則表達式即可提取所需知識。

    import pefile
    import os,string,shutil,re
    PEfile_Path = "MFCApplication.exe"
    #解析PE文件
    pe = pefile.PE(PEfile_Path, fast_load=True)
    print(type(pe))
    print(pe)
    print(pe.get_imphash())
    #顯示DOS_HEADER
    dh = pe.DOS_HEADER
    #顯示NT_HEADERS
    nh = pe.NT_HEADERS
    #顯示FILE_HEADER
    fh = pe.FILE_HEADER
    #顯示OPTIONAL_HEADER
    oh = pe.OPTIONAL_HEADER
    print(type(fh)) #
    print(str(fh))
    #通過正則表達式獲取時間
    p = re.compile(r'[[](.*?)[]]', re.I|re.S|re.M)   #最小匹配
    res = re.findall(p, str(fh))
    print(res[1])                                    #第一個值是IMAGE_FILE_HEADER
    # Fri Jun 19 10:46:21 2020 UTC
    

    最終輸出結果如下所示,這樣我們就完成了Python自動化提取PE軟件的時間戳過程。任何一個PE軟件都能進行提取,該時間戳也記錄了軟件的編譯時間。

    <class 'pefile.PE'>
    Squeezed text(347 lines).
    <class 'pefile.Structure'>
    [IMAGE_FILE_HEADER]
    0x10C      0x0   Machine:                       0x14C     
    0x10E      0x2   NumberOfSections:              0xA       
    0x110      0x4   TimeDateStamp:                 0x5EEC977D [Fri Jun 19 10:46:21 2020 UTC]
    0x114      0x8   PointerToSymbolTable:          0x0       
    0x118      0xC   NumberOfSymbols:               0x0       
    0x11C      0x10  SizeOfOptionalHeader:          0xE0      
    0x11E      0x12  Characteristics:               0x102     
    Fri Jun 19 10:46:21 2020 UTC
    

    四.時間戳判斷來源地區

    1.UTC時間轉換

    協調世界時,又稱世界統一時間、世界標準時間、國際協調時間。由于英文(CUT)和法文(TUC)的縮寫不同,作為妥協,簡稱UTC。協調世界時是以原子時秒長為基礎,在時刻上盡量接近于世界時的一種時間計量系統。Python時間解析代碼如下:

    import pefile
    import time
    import datetime
    import os,string,shutil,re
    PEfile_Path = "MFCApplication.exe"
    #----------------------------------第一步 解析PE文件-------------------------------
    pe = pefile.PE(PEfile_Path, fast_load=True)
    print(type(pe))
    print(pe)
    print(pe.get_imphash())
    #顯示DOS_HEADER
    dh = pe.DOS_HEADER
    #顯示NT_HEADERS
    nh = pe.NT_HEADERS
    #顯示FILE_HEADER
    fh = pe.FILE_HEADER
    #顯示OPTIONAL_HEADER
    oh = pe.OPTIONAL_HEADER
    print(type(fh)) #
    print(str(fh))
    #----------------------------------第二步 獲取UTC時間-------------------------------
    #通過正則表達式獲取時間
    p = re.compile(r'[[](.*?)[]]', re.I|re.S|re.M)   #最小匹配
    res = re.findall(p, str(fh))
    print(res[1])                                    #第一個值是IMAGE_FILE_HEADER
    res_time = res[1].replace(" UTC","")
    # Fri Jun 19 10:46:21 2020 UTC
    #獲取當前時間
    t = time.ctime()
    print(t)                                         # Thu Jul 16 20:42:18 2020
    final_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y')
    print(final_time)
    # 2020-06-19 10:46:21
    

    輸出結果如下,可以看到該EXE的創建時間。如果想轉換成時間戳可以進一步處理。

    • Fri Jun 19 10:46:21 2020 UTC
    • 2020-06-19 10:46:21

    接下來我們需要進一步分析,根據時間戳判斷所在區域。


    2.時區APT溯源案例(白象)

    作者在“七十四.APT攻擊檢測溯源與常見APT組織的攻擊案例”文章中普及過,安天公司通過時區溯源白象APT來自南亞地區,這里再進行回顧下。

    在過去的四年中,安天的工程師們關注到了中國的機構和用戶反復遭遇來自“西南方向”的網絡入侵嘗試。這些攻擊雖進行了一些掩蓋和偽裝,我們依然可以將其推理回原點——來自南亞次大陸的某個國家。
    - 參考文章:白象的舞步——來自南亞次大陸的網絡攻擊

    安天在2014年4月相關文章中披露的針對中國兩所大學被攻擊的事件,涉及以下六個樣本。其中五個樣本投放至同一個目標,這些樣本間呈現出模塊組合作業的特點。

    • 4號樣本是初始投放樣本,其具有下載其他樣本功能
    • 3號樣本提取主機相關信息生成日志文件
    • 5號樣本負責上傳
    • 6號樣本采集相關文檔文件信息
    • 2號樣本則是一個鍵盤記錄器

    那么,如何溯源該組織所來自的區域呢?

    安天通過對樣本集的時間戳、時區分析進行分析,發現其來自南亞。樣本時間戳是一個十六進制的數據,存儲在PE文件頭里,該值一般由編譯器在開發者創建可執行文件時自動生成,時間單位細化到秒,通常可以認為該值為樣本生成時間(GMT時間)。

    時間戳的分析需要收集所有可用的可執行文件時間戳,并剔除過早的和明顯人為修改的時間,再將其根據特定標準分組統計,如每周的天或小時,并以圖形的形式體現,下圖是通過小時分組統計結果:

    從上圖的統計結果來看,如果假設攻擊者的工作時間是早上八九點至下午五六點的話,那么將工作時間匹配到一個來自UTC+4或UTC+5時區的攻擊者的工作時間。根據我們匹配的攻擊者所在時區(UTC+4 或UTC+5),再對照世界時區分布圖,就可以來推斷攻擊者所在的區域或國家。

    接著對該攻擊組織進行更深入的分析。對這一攻擊組織繼續綜合線索,基于互聯網公開信息,進行了畫像分析,認為這是一個由10~16人的組成的攻擊小組。其中六人的用戶ID是cr01nk 、neeru rana、andrew、Yash、Ita nagar、Naga。

    在安天的跟蹤分析中,發現該組織的部分C&C地址是一些正常的網站,經過分析我們認為,有可能該組織入侵了這些網站,將自己的C&C服務控制代碼放到它們的服務器上,以此來隱藏自己的IP信息。同時這種方式還會使安全軟件認為連接的是正常的網站,而不會觸發安全警報。

    基于現有資源可以分析出,“白象二代”組織一名開發人員的ID為“Kanishk”,通過維基百科查詢到一個類似單詞“Kanishka”,這是一個是梵文譯音,中文翻譯為“迦膩色迦”,迦膩色伽是貴霜帝國(Kushan Empire)的君主,貴霜帝國主要控制范圍在印度河流域。至此推測該APT組織來自南亞某國。

    通過這個案例,我們可以通過時區、公開信息、黑客ID、C&C域名進行溯源,并一步步遞進。


    3.時間戳分析

    比如當前北京時間是2020年7月16日晚上9點3分,而UTC時間是13點3分。

    但這里存在一個問題,當有很多惡意樣本的時候,我們基于多個樣本時間戳并結合正常作息時間進行分析,才能判斷其來源。但是,如果僅從一個樣本進行分析,其準確率還是會有影響,有的惡意軟件是深夜發布,也影響了該方法的準確性,同時混淆、加殼、對抗樣本也能影響我們的實驗效果,但作者僅是提供了一種方法,更深入的研究還在繼續,如果您有好的方法也歡迎和我討論。

    這里我們PE軟件獲取的時間是“2020-06-19 10:46:21”,對應北京時間是19點46分。因為作者習慣晚上寫代碼,但如果是軟件或惡意樣本,大公司通常會有正常的作息,從而可以結合海量數據分析來確定最終的軟件來源地區或國家。

    • Fri Jun 19 10:46:21 2020 UTC
    • 2020-06-19 10:46:21

    此時的Python代碼如下:

    import pefile
    import time
    import warnings
    import datetime
    import os,string,shutil,re
    #忽略警告
    warnings.filterwarnings("ignore")
    PEfile_Path = "MFCApplication.exe"
    #----------------------------------第一步 解析PE文件-------------------------------
    pe = pefile.PE(PEfile_Path, fast_load=True)
    print(type(pe))
    print(pe)
    print(pe.get_imphash())
    #顯示DOS_HEADER
    dh = pe.DOS_HEADER
    #顯示NT_HEADERS
    nh = pe.NT_HEADERS
    #顯示FILE_HEADER
    fh = pe.FILE_HEADER
    #顯示OPTIONAL_HEADER
    oh = pe.OPTIONAL_HEADER
    print(type(fh)) #
    print(str(fh))
    #----------------------------------第二步 獲取UTC時間-------------------------------
    #通過正則表達式獲取時間
    p = re.compile(r'[[](.*?)[]]', re.I|re.S|re.M)   #最小匹配
    res = re.findall(p, str(fh))
    print(res[1])                                    #第一個值是IMAGE_FILE_HEADER
    res_time = res[1].replace(" UTC","")
    # Fri Jun 19 10:46:21 2020 UTC
    #獲取當前時間
    t = time.ctime()
    print(t,"")                                    # Thu Jul 16 20:42:18 2020
    utc_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y')
    print("UTC Time:", utc_time)
    # 2020-06-19 10:46:21
    #----------------------------------第三步 全球時區轉換-------------------------------
    #http://zh.thetimenow.com/india
    #UTC時間比北京時間晚八個小時 故用timedelta方法加上八個小時
    china_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=8)
    print("China Time:",china_time)
    #美國 UTC-5
    america_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') - datetime.timedelta(hours=5)
    print("America Time:",america_time)
    #印度 UTC+5
    india_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=5)
    print("India Time:",india_time)
    #澳大利亞 UTC+10
    australia_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=10)
    print("Australia Time",australia_time)
    #俄羅斯 UTC+3
    russia_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=3)
    print("Russia Time",russia_time)
    #英國 UTC+0
    england_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y')
    print("England Time",england_time)
    #日本 UTC+9
    japan_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=9)
    print("Japan Time",england_time)
    #德國 UTC+1
    germany_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=1)
    print("Germany Time",germany_time)
    #法國 UTC+1
    france_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=1)
    print("France Time",france_time)
    #加拿大 UTC-5
    canada_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') - datetime.timedelta(hours=5)
    print("Canada Time:",canada_time)
    #越南 UTC+7 
    vietnam_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=7)
    print("Vietnam Time:",vietnam_time)
    

    輸出結果如下圖所示,不同地區有對應的時間分布,如果正常作息是早上9點到12點、下午2點到5點,從結果看更像是來自India、England、Japan等地區。當然,只有惡意樣本很多的時候,我們才能進行更好的溯源,哈哈~


    五.總結

    寫到這里,這篇文章就介紹完畢,希望對您有所幫助,最后進行簡單的總結下作者的猜想。

    • 通過PE文件分析抓取創建文件時間戳,然后UTC定位國家地區,但受樣本數量較少,活動規律不穩定影響很大
    • 通過靜態分析獲取非英文字符串,軟件中一般有供該國使用的文字,然后進行編碼比對溯源地區
    • 某些APP或軟件存在流量反饋或IP定位,嘗試進行流量抓取分析
    • 利用深度學習進行分類,然后提取不同國家的特征完成溯源


    本文嘗試的是最簡單的方法,所以也存在很多問題,比如當有很多惡意樣本的時候,我們才能基于多個樣本時間戳并結合正常作息時間進行分析,才能判斷其來源。如果僅從一個樣本進行分析,其準確率還是會有影響,有的惡意軟件是深夜發布,也影響了該方法的準確性,同時混淆、加殼、對抗樣本也能影響我們的實驗效果,但作者僅是提供了一種方法,更深入的研究還在繼續,如果您有好的方法也歡迎和我討論。

    最后歡迎大家討論如何判斷PE軟件或APP來源哪個國家或地區呢?印度又是如何確保一鍵正確卸載中國APP呢?哈哈,未知攻,焉知防。加油~

    學安全一年,認識了很多安全大佬和朋友,希望大家一起進步。這篇文章中如果存在一些不足,還請海涵。作者作為網絡安全初學者的慢慢成長路吧!希望未來能更透徹撰寫相關文章。同時非常感謝參考文獻中的安全大佬們的文章分享,深知自己很菜,得努力前行。

    《珈國情》

    明月千里兩相思,

    清風縷縷寄離愁。

    燕歸珞珈花已謝,

    情滿景逸映深秋。

    最感恩的永遠是家人的支持,知道為啥而來,知道要做啥,知道努力才能回去。夜已深,雖然笨,但還得奮斗。

    歡迎大家討論,是否覺得這系列文章幫助到您!任何建議都可以評論告知讀者,共勉。

    (By:Eastmount 2021-12-29 夜于武漢 )

    pe文件時間戳
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    起底GoldenJackal APT組織
    2023-06-05 09:42:08
    GoldenJackal是一家APT組織,自2019年開始活躍,通常針對中東和南亞的政府和外交機構。攻擊途徑 研究人員發現攻擊者假冒Skype安裝程序,使用惡意Word文檔。“Gallery of Officers Who Have Received National And Foreign Awards.docx”的文件似乎是合法的,旨在收集巴基斯坦政府授予勛章的官員的信息。
    蔓靈花(BITTER),國外著名APT組織,因該組織常用的特種木馬數據包頭部為“BITTER”而得名,近一兩年持續針對我國重點行業單位進行釣魚攻擊,其中攻擊方式較多樣,橫跨PC端到移動端。
    摩訶草,又名Hangover、Patchwork、白象等,奇安信內部跟蹤編號為APT-Q-36,最早由國外安全廠商Norman披露并命名為Hangover,2016年8月其他廠商后續披露了摩訶草組織的詳細報告。國內其他安全廠商通常也稱其為“白象”。該APT組織被廣泛認為來自南亞地區某國,其最早攻擊活動可以追溯到2009年11月,從2015年開始變得更加活躍。該組織主要針對Windows系統進行攻
    Hook技術入門
    2021-07-20 16:26:02
    要說在Hook技術里面最基礎的,那就是IAT Hook,它的原理就是通過修改PE結構中的IAT表,將其替換成我們自己定義的函數,最終實現Hook,所以在進行Hook之前,我們得很清楚的PE結構,接下來我們先講解一下怎么索引到IAT表。
    CS-exe木馬分析
    2023-02-06 10:03:07
    分析Windows Executable 生成的artifact.exe查殼:無殼二、具體分析401840關鍵函數:獲取系統時間,通過sprintf拼接管道名,建線程,寫加密數據到建的管道內,最后解密執行。讀取管道內的數據,解密數據,跳轉執行。shellcode分析:1.loadlibrary加載wininet.dllInternetOpen函數:在進行HTTP、FTP和服務器通信前初始化 WinInet.dll 。簡單的說通過 InternetOpen 函數建位于根部的 Hinternet 句柄。HttpSendRequestA發送HTTP請求到指定的服務器。跳轉到申請的內存處,解密出dll。; ebx+ReflectiveLoader函數偏移-7call ebx ; call ReflectiveLoader
    通過威脅情報碰撞郵件附件MD5信息和惡意URL信息,并對可疑的文件投放到沙箱中進行動態檢測,基于威脅情報和沙箱行為的威脅評級模型進行判定,產生告警信息投遞到消息隊列系統中,同時在運營平臺生成告警工單。如發現高危釣魚郵件樣本,則第一時間由分析人員跟進深度安全分析,對內網資產進行威脅判定和應急處置工作。
    一個以前未曾報道過的網絡間諜框架,我們將其命名為Ramsay,他是專門用于收集和泄露敏感文檔,并且能夠在對氣隙網絡中運行。 我們最初在VirusTotal中找到了Ramsay的實例。該樣本是從日本上傳的,并導致我們發現了該...
    AI安全論文第21篇介紹S&P經典的離地攻擊論文,希望您喜歡
    HOOK技術實戰
    2021-10-19 05:55:56
    對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。hook(鉤子)是一種特殊的消息處理機制,它可以監視系統或者進程中的各種事件消息,截獲發往目標口的消息并進行處理。所以說,我們可以在系統中自定義鉤子,用來監視系統中特定事件的發生,完成特定功能,如屏幕取詞,監視日志,截獲鍵盤、鼠標輸入等等。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类