吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|排列三5码组三最大遗漏 www.ynjqb.tw

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 5450|回復: 42
上一主題 下一主題

彩票助手组六组三: [原創] PE文件基本解析

  [復制鏈接]
跳轉到指定樓層
樓主
zmbilx 發表于 2019-9-13 11:41 回帖獎勵
本帖最后由 zmbilx 于 2019-9-13 22:25 編輯




鏈接已補



PDF 下載 鏈接,注:兩者完全一樣,可能論壇發布時沒有一些圖,但是PDF里面有的。
鏈接:https://pan.baidu.com/s/1nsUO2XCAQumCY64MRkq-Eg
提取碼:faru
復制這段內容后打開百度網盤手機App,操作更方便哦
PE文件基本解析
2019年8月~ 9月
感謝網絡上各類免費資源,由于引用資源太多,無法一一標注,故不在進行標注,LOG不在去除。如果侵權,請及時聯系,我第一時間進行刪除。取之免費,發之免費,故此套資料全部免費,如果侵權,請及時和我聯系,必馬上刪除。特別感謝魚C工作室!

一、PE文件是什么?
PE(Portable Execute)文件是Windows下可執行文件的總稱,常見的有DLL,EXE,OCX,SYS等,事實上,一個文件是否是PE文件與其擴展名無關,PE文件可以是任何擴展名。那Windows是怎么區分可執行文件和非可執行文件的呢?我們調用LoadLibrary傳遞了一個文件名,系統是如何判斷這個文件是一個合法的動態庫呢?這就涉及到PE文件結構了。PE文件的結構一般來說如下圖所示:從起始位置開始依次是DOS頭,NT頭,節表以及具體的節。

二、DOS頭
DOS頭是用來兼容MS-DOS操作系統的,目的是當這個文件在MS-DOS上運行時提示一段文字,大部分情況下是:This program cannot be run in DOS mode.還有一個目的,就是指明NT頭在文件中的位置。

typedef struct_IMAGE_DOS_  {  // DOS .EXE header
// offset: 0H
WORD  e_magic;                // Magic number
// offset: 2H
WORD   e_cblp;                 // Bytes on last page of file
// offset: 4H
WORD  e_cp;                   // Pages infile
// offset: 6H
WORD   e_crlc;                 // Relocations
// offset: 8H
WORD  e_cparhdr;             // Size of header in paragraphs
// offset: AH
WORD  e_minalloc;            // Minimumextra paragraphs needed
// offset: CH
WORD  e_maxalloc;            // Maximumextra paragraphs needed
// offset: EH
WORD  e_ss;                   // Initial(relative) SS value
// offset: 10H
WORD  e_sp;                   // Initial SPvalue
// offset: 12H
WORD   e_csum;                 // Checksum
// offset: 14h
WORD  e_ip;                   // Initial IPvalue
// offset: 16H
WORD  e_cs;                   // Initial(relative) CS value
// offset: 18H
WORD  e_lfarlc;              // File address of relocation table
// offset: 1AH
WORD  e_ovno;                // Overlaynumber
// offset: 1CH
WORD  e_res[4];              // Reservedwords
// offset: 24H
WORD  e_oemid;               // OEMidentifier (for e_oeminfo)
// offset: 26H
WORD  e_oeminfo;             // OEMinformation; e_oemid specific
// offset: 28H
WORD  e_res2[10];            // Reservedwords
// offset: 3CH
LONG   e_lfanew;              // File address of new exe header
  }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

批:WORD 為一個16bit 的無符號數
1、需要關注的兩個域:
1.1、e_magic
一個WORD類型,值是一個常數0x4D5A,用文本編輯器查看該值位‘MZ’,可執行文件必須都是'MZ'開頭。

批:4DH 為M的ASCLL碼的16進制, 5AH為Z的ASCLL碼的16進制。
1.2、e_lfanew
為32位可執行文件擴展的域,用來表示DOS頭之后的NT頭相對文件起始地址的偏移。

三、NT頭
NT頭包含windows PE文件的主要信息,其中包括一個‘PE’字樣的簽名,PE文件頭(IMAGE_FILE_HEADER)和PE可選頭(IMAGE_OPTIONAL_HEADER32)。
typedef struct _IMAGE_NT_HEADERS{
// offset: 0H
DWORD Signature;
// offset: 4H
IMAGE_FILE_HEADER FileHeader;
// offset: 18H
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;
1、需要關注的域
1.1、Signature
類似于DOS頭中的e_magic,其高16位是0,低16是0x4550,用字符表示是’PE’。

批:45H 為P的ASCLL碼的16進制, 50H為E的ASCLL碼16進制。
1.2、IMAGE_FILE_HEADER
IMAGE_FILE_HEADER是PE文件頭,C語言的定義是這樣的:

typedefstruct _IMAGE_FILE_HEADER {
+4H  WORD    Machine;
+6H  WORD    NumberOfSections;
+8H  DWORD   TimeDateStamp;
+CH  DWORD   PointerToSymbolTable;
+10HDWORD  NumberOfSymbols;
+14HWORD   SizeOfOptionalHeader;
+16HWORD   Characteristics;
}IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


每個域的具體含義:
Machine
該文件的運行平臺,是x86、x64還是I64等等,可以是下面值里的某一個。
#defineIMAGE_FILE_MACHINE_UNKNOWN      0
#defineIMAGE_FILE_MACHINE_I386         0x014c  // Intel 386.
#defineIMAGE_FILE_MACHINE_R3000        0x0162  // MIPS little-endian, 0x160big-endian
#defineIMAGE_FILE_MACHINE_R4000        0x0166  // MIPS little-endian
#defineIMAGE_FILE_MACHINE_R10000       0x0168  // MIPS little-endian
#defineIMAGE_FILE_MACHINE_WCEMIPSV2   0x0169  // MIPS little-endian WCE v2
#defineIMAGE_FILE_MACHINE_ALPHA         0x0184  // Alpha_AXP
#defineIMAGE_FILE_MACHINE_SH3          0x01a2  // SH3 little-endian
#defineIMAGE_FILE_MACHINE_SH3DSP       0x01a3
#defineIMAGE_FILE_MACHINE_SH3E        0x01a4  // SH3E little-endian
#defineIMAGE_FILE_MACHINE_SH4         0x01a6  // SH4 little-endian
#defineIMAGE_FILE_MACHINE_SH5         0x01a8  // SH5
#defineIMAGE_FILE_MACHINE_ARM         0x01c0  // ARM Little-Endian
#defineIMAGE_FILE_MACHINE_THUMB        0x01c2
#defineIMAGE_FILE_MACHINE_AM33         0x01d3
#defineIMAGE_FILE_MACHINE_POWERPC    0x01F0  // IBM PowerPC Little-Endian
#defineIMAGE_FILE_MACHINE_POWERPCFP   0x01f1
#defineIMAGE_FILE_MACHINE_IA64        0x0200  // Intel 64
#defineIMAGE_FILE_MACHINE_MIPS16      0x0266  // MIPS
#defineIMAGE_FILE_MACHINE_ALPHA64     0x0284 //ALPHA64
#defineIMAGE_FILE_MACHINE_MIPSFPU     0x0366  // MIPS
#defineIMAGE_FILE_MACHINE_MIPSFPU16  0x0466  // MIPS
#defineIMAGE_FILE_MACHINE_AXP64       IMAGE_FILE_MACHINE_ALPHA64
#defineIMAGE_FILE_MACHINE_TRICORE    0x0520  // Infineon
#defineIMAGE_FILE_MACHINE_CEF          0x0CEF
#defineIMAGE_FILE_MACHINE_EBC          0x0EBC  // EFI Byte Code
#defineIMAGE_FILE_MACHINE_AMD64       0x8664  // AMD64 (K8)
#defineIMAGE_FILE_MACHINE_M32R        0x9041  // M32R little-endian
#defineIMAGE_FILE_MACHINE_CEE          0xC0EE

NumberOfSections
該PE文件中有多少個節,也就是節表中的項數。

TimeDateStamp
PE文件的創建時間,一般有連接器填寫。表明文件是何時被創建的。這個值是自1970年1月1日以來用格林威治時間(GMT)計算的秒數,這個值是比文件系統(FILESYSTEM)的日期時間更加精確的指示器。

PointerToSymbolTable
COFF文件符號表在文件中的偏移,主要指向調式信息

NumberOfSymbols
符號表的數量。

SizeOfOptionalHeader
緊隨其后的可選頭的大小,對于32位系統,通常為0X00E0H,64位系統為0X00F0H。

Characteristics
可執行文件的屬性,可以是下面這些值按位相或,定義在winnt.h頭文件中。


1.3、IMAGE_OPTIONAL_HEADER32
IMAGE_OPTIONAL_HEADER32是PE可選頭,別看他名字叫可選頭,其實一點都不能少,它在不同的平臺下是不一樣的,例如32位下是IMAGE_OPTIONAL_HEADER32,而在64位下是IMAGE_OPTIONAL_HEADER64。為了簡單起見,我們只看32位。

typedef struct _IMAGE_OPTIONAL_HEADER {
// 必選部分
+18H  WORD    Magic;
+1AH  BYTE    MajorLinkerVersion;
+1BH  BYTE    MinorLinkerVersion;
+1CH DWORD   SizeOfCode;
+20H  DWORD   SizeOfInitializedData;
+24H  DWORD   SizeOfUninitializedData;
+28H  DWORD   AddressOfEntryPoint;
+2CH  DWORD   BaseOfCode;
+30H  DWORD   BaseOfData;
// 可選部分
+34H  DWORD   ImageBase;
+38H  DWORD   SectionAlignment;
+3CH  DWORD   FileAlignment;
+40H  WORD    MajorOperatingSystemVersion;
+42H  WORD    MinorOperatingSystemVersion;
+44H  WORD    MajorImageVersion;
+46H  WORD    MinorImageVersion;
+48H  WORD    MajorSubsystemVersion;
+4AH  WORD    MinorSubsystemVersion;
+4CH  DWORD   Win32VersionValue;
+50H  DWORD   SizeOfImage;
+54H  DWORD   SizeOfHeaders;
+58H  DWORD   CheckSum;
+5CH  WORD    Subsystem;
+5EH  WORD    DllCharacteristics;
+60H  DWORD   SizeOfStackReserve;
+64H  DWORD   SizeOfStackCommit;
+68H  DWORD   SizeOfHeapReserve;
+6CH  DWORD   SizeOfHeapCommit;
+70H  DWORD   LoaderFlags;
+74H  DWORD   NumberOfRvaAndSizes;
+78H IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;

Magic
表示可選頭的類型。

#define IMAGE_NT_OPTIONAL_HDR32_MAGIC    0x10b  // 32PE可選頭
#defineIMAGE_NT_OPTIONAL_HDR64_MAGIC     0x20b  // 64PE可選頭
#defineIMAGE_ROM_OPTIONAL_HDR_MAGIC      0x107  

MajorLinkerVersion
鏈接器的版本號
MinorLinkerVersion
鏈接器的版本號
SizeOfCode
代碼段的長度,如果有多個代碼段,則是代碼段長度的總和。
SizeOfInitializedData
初始化的數據長度。
SizeOfUninitializedData
未初始化的數據長度。
AddressOfEntryPoint
程序入口的RVA,對于exe可以理解為WinMain的RVA。對于DLL可以理解為DllMain的RVA,對于驅動程序,可以理解為DriverEntry的RVA。當然,實際上入口點并非是WinMain,DllMain和DriverEntry,在這些函數之前還有一系列初始化要完成。
BaseOfCode
代碼段起始地址的RVA。
BaseOfData
數據段起始地址的RVA。
可選字段部分ImageBase
映象(加載到內存中的PE文件)的基地址,這個基地址是建議,對于DLL來說,如果無法加載到這個地址,系統會自動為其選擇地址。鏈接器產生可執行文件的時候對應這個地址來生成機器碼,所以當文件被裝入這個地址時不需要進行重定位操作,裝入的速度最快。當文件被裝載到其他地址時,進行重定位操作,會慢一點。
對于EXE文件來說,由于每個文件總是使用獨立的虛擬地址空間,優先裝入地址不可能被其他??檎季?,所以EXE總是能夠按照這個地址裝入。
這也意味著EXE文件不再需要重定位信息。對于DLL文件來說,由于多個DLL文件全部使用宿主EXE文件的地址空間,不能保證優先裝入地址沒有被其他的DLL使用,所以DLL文件中必須包含重定位信息以防萬一。
因此,在前面介紹的 IMAGE_FILE_HEADER 結構的 Characteristics 字段中,DLL 文件對應的 IMAGE_FILE_RELOCS_STRIPPED 位總是為0,而EXE文件的這個標志位總是為1,即DLL中不刪除重定位信息,EXE文件中刪除重定位信息。

批:#defineIMAGE_FILE_RELOCS_STRIPPED 0x0001
//Relocation info stripped from file.(從文件中刪除重定位信息。)
在鏈接的時候,可以通過對link.exe指定/base:address選項來自定義優先裝入地址,如果不指定這個選項的話,一般EXE文件的默認優先裝入地址被定為00400000h,而DLL文件的默認優先裝入地址被定為10000000h。

SectionAlignment
節對齊,PE中的節被加載到內存時會按照這個域指定的值來對齊,比如這個值是0x1000,那么每個節的起始地址的低12位都為0。
FileAlignment
節在文件中按此值對齊,SectionAlignment必須大于或等于FileAlignment。
MajorOperatingSystemVersion
所需操作系統的版本號,隨著操作系統版本越來越多,這個好像不是那么重要了。
MinorOperatingSystemVersion
所需操作系統的版本號,隨著操作系統版本越來越多,這個好像不是那么重要了。
MajorImageVersion
映象的版本號,這個是開發者自己指定的,由連接器填寫。
MinorImageVersion
映象的版本號,這個是開發者自己指定的,由連接器填寫。
MajorSubsystemVersion
所需子系統版本號。
MinorSubsystemVersion
所需子系統版本號。
Win32VersionValue
保留,必須為0。
SizeOfImage
映象的大小,PE文件加載到內存中空間是連續的,這個值指定占用虛擬空間的大小。
SizeOfHeaders
所有文件頭(包括節表)的大小,這個值是以FileAlignment對齊的。
CheckSum
映象文件的校驗和。
Subsystem
運行該PE文件所需的子系統,可以是下面定義中的某一個:
DllCharacteristics
DLL的文件屬性,只對DLL文件有效,可以是下面定義中某些的組合:

#defineIMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE        0x0040     // DLL can move.
#defineIMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY   0x0080     // Code Integrity Image
#defineIMAGE_DLLCHARACTERISTICS_NX_COMPAT            0x0100     // Image is NX compatible
#defineIMAGE_DLLCHARACTERISTICS_NO_ISOLATION        0x0200     // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH               0x0400     // Image does not use SEH.  No SE handler may reside in this image
#defineIMAGE_DLLCHARACTERISTICS_NO_BIND              0x0800     // Do not bind this image.//                                           0x1000     // Reserved.
#defineIMAGE_DLLCHARACTERISTICS_WDM_DRIVER           0x2000    //Driver uses WDM model//                                           0x4000     // Reserved.
#defineIMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000

SizeOfStackReserve
運行時為每個線程棧保留內存的大小。
SizeOfStackCommit
運行時每個線程棧初始占用內存大小。
SizeOfHeapReserve
運行時為進程堆保留內存大小。
SizeOfHeapCommit
運行時進程堆初始占用內存大小。
LoaderFlags
保留,必須為0。
NumberOfRvaAndSizes
數據目錄的項數,即下面這個數組的項數。
DataDirectory
數據目錄,這是一個數組,數組的項定義如下:
typedefstruct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;VirtualAddress
是一個RVA,Size:是一個大小。這兩個數有什么用呢?一個是地址,一個是大小,可以看出這個數據目錄項定義的是一個區域。那他定義的是什么東西的區域呢?前面說了,DataDirectory是個數組,數組中的每一項對應一個特定的數據結構,包括導入表,導出表等等,根據不同的索引取出來的是不同的結構,頭文件里定義各個項表示哪個結構,如下面的代碼所示:

批:15未使用,共16項
四、節(塊)表(Section Table)
節表是PE文件后續節的描述,Windows根據節表的描述加載每個節。PE文件中所有節的屬性都被定義在節表中,節表由一系列的IMAGE_SECTION_HEADER結構排列而成,每個結構用來描述一個節,結構的排列順序和它們描述的節在文件中的排列順序是一致的。全部有效結構的最后以一個空的IMAGE_SECTION_HEADER結構作為結束,所以節表中IMAGE_SECTION_HEADER結構數量等于節的數量加一。
節表總是被存放在緊接在PE文件頭的地方。節表中 IMAGE_SECTION_HEADER結構的總數總是由PE文件頭IMAGE_NT_HEADERS(
注:即本資料中的
NT) 結構中的FileHeader.NumberOfSections 字段來指定的。
typedef struct_IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
       union {   
           DWORD PhysicalAddress;  
           DWORD VirtualSize; } Misc;
           DWORD VirtualAddress;
           DWORD SizeOfRawData;
           DWORD PointerToRawData;
           DWORDPointerToRelocations;
           DWORDPointerToLinenumbers;
           WORD  NumberOfRelocations;
           WORD  NumberOfLinenumbers;
           DWORD Characteristics;
} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;

1、需要關注的域
Name
區塊名。這是一個由8個ASCII碼組成,用來定義區塊的名稱的數組。多數區塊名都習慣性以一個“.”作為開頭(例如:.text),這個“.”實際上是不是必須的。值得我們注意的是,如果區塊名達到8 個字節,后面就沒有0字符了。前邊帶有一個“$” 的區塊名字會從連接器那里得到特殊的待遇,前邊帶有“$”的相同名字的區塊在載入時候將會被合并,在合并之后的區塊中,他們是按照“$”后邊的字符的字母順序進行合并的。每個區塊的名稱都是唯一的,不能有同名的兩個區塊。但事實上節的名稱不代表任何含義,他的存在僅僅是為了正規統一編程的時候方便程序員查看方便而設置的一個標記而已。所以將包含代碼的區塊命名為“.Data”或者說將包含數據的區塊命名為“.Code”都是合法的。當我們要從PE 文件中讀取需要的區塊時候,不能以區塊的名稱作為定位的標準和依據,正確的方法是按照IMAGE_OPTIONAL_HEADER32 結構中的數據目錄字段結合進行定位。
VirtualSize
對表對應的區塊的大小,這是區塊的數據在沒有進行對齊處理前的實際大小。
VirtualAddress
該區塊裝載到內存中的RVA地址。這個地址是按照內存頁來對齊的,因此它的數值總是SectionAlignment的值的整數倍。
PointerToRawData
指出節在磁盤文件中所處的位置。這個數值是從文件頭開始算起的偏移量。
SizeOfRawData
該區塊在磁盤中所占的大小,這個數值等于VirtualSize字段的值按照FileAlignment的值對齊以后的大小。
Characteristics
該區塊的屬性。該字段是按位來指出區塊的屬性(如代碼/數據/可讀/可寫等)的標志。

批:更多可查MSDN
2、裝載過程
依靠PointerToRawData,SizeOfRawData,VirtualAddress,VirtualSize4個字段的值,裝載器就可以從PE文件中找出某個節(從PointerToRawData偏移開始的SizeOfRawData字節)的數據,并將它映射到內存中去(映射到從??榛刂菲?i>VirtualAddress的地方,并占用以VirtualSize的值按照頁的尺寸對齊后的空間大小)。
五、節(塊)
每個節實際上是一個容器,可以包含代碼、數據等等,每個節可以有獨立的內存權限,比如代碼節默認有讀/執行權限,節的名字和數量可以自己定義。
通常,區塊中的數據在邏輯上是關聯的。PE 文件一般至少都會有兩個區塊:一個是代碼塊,另一個是數據塊。每一個區塊都需要有一個截然不同的名字,這個名字主要是用來表達區塊的用途。例如有一個區塊叫.rdata,表明他是一個只讀區塊。注意:區塊在映像中是按起始地址(RVA)來排列的,而不是按字母表順序。
另外,使用區塊名字只是人們為了認識和編程的方便,而對操作系統來說這些是無關緊要的。微軟給這些區塊取了個有特色的名字,但這不是必須的。當編程從PE 文件中讀取需要的內容時,如輸入表、輸出表,不能以區塊名字作為參考,正確的方法是按照數據目錄表中的字段來進行定位。

1、塊的偏移地址
塊起始地址在磁盤中是按照IMAGE_OPTIONAL_HEADER32中的FileAlignment字段的值進行對齊的,而當被加載到內存中時是按照同一結構中的SectionAlignment字段的值設置對齊的,兩者的值可能不同。所以一個塊表被裝載到內存后相對于文件頭的偏移地址和磁盤中的偏移地址可能是不同的。

2、區塊名稱以及意義我們在Visual C++中也可以自己命名我們的區塊,用#pragma 來聲明,告訴編譯器插入數據到一個區塊內,格式如下:
        #pragma data_msg( "FC_data" )
以上語句告訴編譯器將數據都放進一個叫“FC_data”的區塊內,而不是默認的.data 區塊。區塊一般是從OBJ 文件開始,被編譯器放置的。鏈接器的工作就是合并左右OBJ 和庫中需要的塊,使其成為一個最終合適的區塊。鏈接器會遵循一套相當完整的規則,它會判斷哪些區塊將被合并以及如何被合并。
   
3、合并區塊
鏈接器的一個有趣特征就是能夠合并區塊。如果兩個區塊有相似、一致性的屬性,那么它們在鏈接的時候能被合并成一個單一的區塊。這取決于是否開啟編譯器的 /merge 開關。事實上合并區塊有一個好處就是可以節省磁盤的內存空間……注意:我們不應該將.rsrc、.reloc、.pdata 合并到**的區塊里。
4、區塊的對齊值
之前我們簡單了解過區塊是要對齊的,無論是在內存中存放還是在磁盤中存放,但他們一般的對齊值是不同的。
PE 文件頭里邊的FileAligment 定義了磁盤區塊的對齊值。每一個區塊從對齊值的倍數的偏移位置開始存放。而區塊的實際代碼或數據的大小不一定剛好是這么多,所以在多余的地方一般以00h 來填充,這就是區塊間的間隙。
例如,在PE文件中,一個典型的對齊值是200h,這樣,每個區塊都將從200h 的倍數的文件偏移位置開始,假設第一個區塊在400h 處,長度為90h,那么從文件400h 到490h 為這一區塊的內容,而由于文件的對齊值是200h,所以為了使這一區塊的長度為FileAlignment 的整數倍,490h 到 600h 這一個區間都會被00h 填充,這段空間稱為區塊間隙,下一個區塊的開始地址為600h 。
PE 文件頭里邊的SectionAligment 定義了內存中區塊的對齊值。PE 文件被映射到內存中時,區塊總是至少從一個頁邊界開始。
一般在X86 系列的CPU 中,頁是按4KB(1000h)來排列的;在IA-64 上,是按8KB(2000h)來排列的。所以在X86 系統中,PE文件區塊的內存對齊值一般等于 1000h,每個區塊按1000h 的倍數在內存中存放。
5、RVA 和文件偏移的轉換
RVA 是相對虛擬地址(RelativeVirtual Address)的縮寫,顧名思義,它是一個“相對地址”。PE 文件中的各種數據結構中涉及地址的字段大部分都是以 RVA 表示的。
更為準確的說,RVA 是當PE 文件被裝載到內存中后,某個數據位置相對于文件頭的偏移量。舉個例子,如果 Windows 裝載器將一個PE 文件裝入到 00400000h 處的內存中,而某個區塊中的某個數據被裝入 0040**xh 處,那么這個數據的 RVA 就是(0040**xh - 00400000h )= **xh,反過來說,將 RVA 的值加上文件被裝載的基地址,就可以找到數據在內存中的實際地址。
6、換算 RVA 和文件偏移
當處理PE 文件時候,任何的 RVA 必須經過到文件偏移的換算,才能用來定位并訪問文件中的數據,但換算卻無法用一個簡單的公式來完成,事實上,唯一可用的方法就是最土最笨的方法:
步驟一:循環掃描區塊表得出每個區塊在內存中的起始 RVA(根據IMAGE_SECTION_HEADER 中的VirtualAddress 字段),并根據區塊的大?。ǜ軮MAGE_SECTION_HEADER 中的SizeOfRawData 字段)算出區塊的結束 RVA(兩者相加即可),最后判斷目標 RVA 是否落在該區塊內。
步驟二:通過步驟一定位了目標 RVA 處于具體的某個區塊中后,那么用目標 RVA 減去該區塊的起始 RVA ,這樣就能得到目標 RVA 相對于起始地址的偏移量 RVA2.
步驟三:在區塊表中獲取該區塊在文件中所處的偏移地址(根據IMAGE_SECTION_HEADER 中的PointerToRawData 字段), 將這個偏移值加上步驟二得到的 RVA2 值,就得到了真正的文件偏移地址。
六、PE文件加載過程
在執行一個PE文件的時候,Windows并不在一開始就將整個文件讀入內存的,而是采用與內存映射文件類似的機制。也就是說,Windows 裝載器在裝載的時候僅僅建立好虛擬地址和PE文件之間的映射關系。當且僅當真正執行到某個內存頁中的指令或者訪問某一頁中的數據時,這個頁面才會被從磁盤提交到物理內存,這種機制使文件裝入的速度和文件大小沒有太大的關系。
`
當一個PE文件被加載到內存中以后,我們稱之為“映象”(image),一般來說,PE文件在硬盤上和在內存里是不完全一樣的,被加載到內存以后其占用的虛擬地址空間要比在硬盤上占用的空間大一些,這是因為各個節在硬盤上是連續的,而在內存中是按頁對齊的,所以加載到內存以后節之間會出現一些“空洞”。
Windows 裝載器在裝載DOS部分,PE文件頭部分和節表(節表也稱為區塊表,塊表)部分是不進行任何特殊處理的,而在裝載節(節也稱為區塊)的時候則會自動按節(區塊)的屬性的不同做不同的處理。
因為存在這種對齊,所以在PE結構內部,表示某個位置的地址采用了兩種方式,針對在硬盤上存儲文件中的地址,稱為原始存儲地址或物理地址表示距離文件頭的偏移;另外一種是針對加載到內存以后映象中的地址,稱為相對虛擬地址(RVA,表示相對內存映象頭的偏移。
然而CPU的某些指令是需要使用絕對地址的,比如取全局變量的地址,傳遞函數的地址編譯以后的匯編指令中肯定需要用到絕對地址而不是相對映象頭的偏移,因此PE文件會建議操作系統將其加載到某個內存地址(這個叫基地址),編譯器便根據這個地址求出代碼中一些全局變量和函數的地址,并將這些地址用到對應的指令中。例如在IDA里看上去是這個樣子:
這種表示方式叫做虛擬地址(VA。

也許有人要問,既然有VA這么簡單的表示方式為什么還要有前面的RVA呢?因為雖然PE文件為自己指定加載的基地址,但是windows有茫茫多的DLL,而且每個軟件也有自己的DLL,如果指定的地址已經被別的DLL占了怎么辦?如果PE文件無法加載到預期的地址,那么系統會幫他重新選擇一個合適的基地址將他加載到此處,這時原有的VA就全部失效了,NT頭保存了PE文件加載所需的信息,在不知道PE會加載到哪個基地址之前,VA是無效的,所以在PE文件頭中大部分是使用RVA來表示地址的,而在代碼中是用VA表示全局變量和函數地址的。那又有人要問了,既然加載基址變了以后VA都失效了,那存在于代碼中的那些VA怎么辦呢?答案是:重定位。系統有自己的辦法修正這些值,到后續重定位表的文章中會詳細描述。既然有重定位,為什么NT頭不能依靠重定位采用VA表示地址呢(十萬個為什么)?因為不是所有的PE都有重定位,早期的EXE就是沒有重定位的。

七、導(輸)入表
輸入表是PE(Portable Executable File Format)文件結構中不可或缺的部分,輸入表也被稱之為“導入表”??芍蔥形募褂美醋雜諂淥唇涌?DLL)的代碼或數據時,稱為輸入。
輸入表就相當于 EXE文件與 DLL文件溝通的鑰匙,形象的可以比喻成兩個城市之間交流的高速公路,所有的導入函數信息都會寫入輸入表中,在PE 文件映射到內存后,Windows 將相應的 DLL文件裝入,EXE 文件通過“輸入表”找到相應的 DLL 中的導入函數,從而完成程序的正常運行,這一動態連接的過程都是由“輸入表”參與的。
1、輸入函數
輸入函數,表示被程序調用但是它的代碼不在程序代碼中的,而在DLL中的函數。對于這些函數,磁盤上的可執行文件只是保留相關的函數信息,如函數名,DLL文件名等。在程序運行前,程序是沒有保存這些函數在內存中的地址。當程序運行起來時,windows加載器會把相關的DLL裝入內存,并且將輸入函數的指令與函數真在內存中正的地址聯系起來。輸入表(導入表)就是用來保存這些函數的信息的。
2、DataDirectory
在IMAGE_OPTIONAL_HEADER 中的 DataDirectory數組保存了輸入表的RVA跟大小。通過RVA可以在OD中加載程序通過ImageBase+RVA 找到輸入表,或者通過RVA計算出文件偏移地址,查看磁盤中的可執行文件,通過文件偏移地址找到輸入表。
在 PE文件頭的 IMAGE_OPTIONAL_HEADER 結構中的DataDirectory(數據目錄表) 的第二個成員就是指向輸入表的。而輸入表是以一個IMAGE_IMPORT_DESCRIPTOR(簡稱IID) 的數組開始。每個被 PE文件鏈接進來的 DLL文件都分別對應一個 IID數組結構。在這個 IID數組中,并沒有指出有多少個項(就是沒有明確指明有多少個鏈接文件),但它最后是以一個全為NULL(0) 的 IID 作為結束的標志。
3、IMAGE_IMPORT_DESCRIPTOR
輸入表是以一個IMAGE_IMPORT_DESCRIPTOR(IID)數組 開始的,每一個被PE文件隱式的鏈接進來的DLL都有一個IID,IID數組的最后一個單元用NULL表示。
typedef struct_IMAGE_IMPORT_DESCRIPTOR {     
_ANONYMOUS_UNION union{              //00h      
  DWORDCharacteristics;         
  DWORDOriginalFirstThunk;      
} DUMMYUNIONNAME;   
   DWORD TimeDateStamp;                  //04h  
   DWORDForwarderChain;                 //08h   
   DWORD Name;                             //0Ch  
    DWORD FirstThunk;                      //10h
}IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

OriginalFirstThunk
指向一個IMAGE_THUNK_DATA數組叫做輸入名稱表Import Name Table(INT),用來保存函數。
TimeDateStamp
該字段可以忽略。如果那里有綁定的話它包含時間/數據戳(time/data stamp)。如果它是0,就沒有綁定在被導入的DLL中發生。在最近,它被設置為0xFFFFFFFF以表示綁定發生。
ForwarderChain
一般情況下我們也可以忽略該字段。在老版的綁定中,它引用API的第一個forwarder chain(傳遞器鏈表)。它可被設置為0xFFFFFFFF以代表沒有forwarder。
Name
DLL名字的指針, 指向一個用NULL作為結束符的ASCII字符串的一個RVA,該字符串是該導入DLL文件的名稱,如:KERNEL32.DLL
FirstThunk
它也指向IMAGE_THUNK_DATA數組叫做輸入地址表Import Address Table(IAT)。
IMAGE_THUNK_DATA結構
typedef struct_IMAGE_THUNK_DATA32 {     
union {         
  DWORDForwarderString;        
  DWORDFunction;        
  DWORDOrdinal;         
  DWORDAddressOfData;   
} u1;
}IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;

當IMAGE_THUNK_DATA 的值最高位為1時,表示函數是以序號方式輸入,這時低31為被當作函數序號。當最高位是0時,表示函數是以字符串類型的函數名方式輸入的,這時,IMAGE_THUNK_DATA 的值為指向IMAGE_IMPORT_BY_NAME 的結構的RVA。
typedef struct_IMAGE_IMPORT_BY_NAME {     
WORD Hint;   
BYTE Name[1];  
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;

Hint
表示這個函數在其所駐留DLL的輸出表的序號,不是必須的。

Name
表示 函數名,是一個ASCII字符串以0結尾,大小不固定。
4、需要兩個 IMAGE_THUNK_DATA 數組的原因
當程序加載時,IAT 會被PE加載器重寫,PE加載器先搜索INT,PE加載器迭代搜索INT數組中的每個指針,找出 INT所指向的IMAGE_IMPORT_BY_NAME結構中的函數在內存中的真正的地址,并把它替代原來IAT中的值。當完成后,INT就沒有用了,程序只需要IAT就可以正常運行了。
可執行程序在磁盤中的時:

當程序被加載后時:

八、導(輸)出表
導出表是用來描述??櫓械牡汲齪慕峁?,如果一個??櫚汲雋撕?,那么這個函數會被記錄在導出表中,這樣通過GetProcAddress函數就能動態獲取到函數的地址。函數導出的方式有兩種,一種是按名字導出,一種是按序號導出。這兩種導出方式在導出表中的描述方式也不相同。??櫚牡汲齪梢醞ü鼶ependency walker工具來查看:
上圖中紅框位置顯示的就是??櫚牡汲齪?,有時候顯示的導出函數名字中有一些符號,像 [email protected]@[email protected]@@Z,這種是導出了C++的函數名,編譯器將名字進行了修飾。

1、導出表的定義
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD  Characteristics;  
    DWORD  TimeDateStamp;   
    WORD   MajorVersion;   
   WORD   MinorVersion;   
   DWORD  Name;   
   DWORD  Base;   
  DWORD  NumberOfFunctions;  
  DWORD  NumberOfNames;  
  DWORD  AddressOfFunctions;     // RVAfrom base of image  
  DWORD  AddressOfNames;          // RVA frombase of image   
DWORD  AddressOfNameOrdinals;  // RVAfrom base of image
}IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
結構還算比較簡單,具體每一項的含義如下:
Characteristics
現在沒有用到,一般為0。
TimeDateStamp
導出表生成的時間戳,由連接器生成。
MajorVersion,MinorVersion
看名字是版本,實際貌似沒有用,都是0。
Name
??櫚拿?。
Base
序號的基數,按序號導出函數的序號值從Base開始遞增。
NumberOfFunctions
所有導出函數的數量。
NumberOfNames
按名字導出函數的數量。
AddressOfFunctions
一個RVA,指向一個DWORD數組,數組中的每一項是一個導出函數的RVA,順序與導出序號相同。
AddressOfNames
一個RVA,依然指向一個DWORD數組,數組中的每一項仍然是一個RVA,指向一個表示函數名字。
AddressOfNameOrdinals
一個RVA,還是指向一個WORD數組,數組中的每一項與AddressOfNames中的每一項對應,表示該名字的函數在AddressOfFunctions中的序號。

基本各項間的圖解
在上圖中,AddressOfNames指向一個數組,數組里保存著一組RVA,每個RVA指向一個字符串,這個字符串即導出的函數名,與這個函數名對應的是AddressOfNameOrdinals中的對應項?;袢〉汲齪刂肥?,先在AddressOfNames中找到對應的名字,比如Func2,他在AddressOfNames中是第二項,然后從AddressOfNameOrdinals中取出第二項的值,這里是2,表示函數入口保存在AddressOfFunctions這個數組中下標為2的項里,即第三項,取出其中的值,加上??榛刂繁閌塹汲齪牡刂?。如果函數是以序號導出的,那么查找的時候直接用序號減去Base,得到的值就是函數在AddressOfFunctions中的下標。
2、從序號查找函數入口地址
Windows 裝載器的工作步驟如下:
1.定位到PE 文件頭
2.從PE 文件頭中的 IMAGE_OPTIONAL_HEADER32 結構中取出數據目錄表,并從第一個數據目錄中得到導出表的RVA
3.從導出表的 Base 字段得到起始序號
4.將需要查找的導出序號減去起始序號,得到函數在入口地址表中的索引
5.檢測索引值是否大于導出表的 NumberOfFunctions 字段的值,如果大于后者的話,說明輸入的序號是無效的
6.用這個索引值在 AddressOfFunctions 字段指向的導出函數入口地址表中取出相應的項目,這就是函數入口地址的RVA 值,當函數被裝入內存的時候,這個RVA 值加上??槭導首叭氳幕刂?,就得到了函數真正的入口地址
3、從函數名稱查找入口地址
Windows 裝載器的工作步驟如下:
1.最初的步驟是一樣的,那就是首先得到導出表的地址
2.從導出表的 NumberOfNames 字段得到已命名函數的總數,并以這個數字作為循環的次數來構造一個循環
3.從 AddressOfNames 字段指向得到的函數名稱地址表的第一項開始,在循環中將每一項定義的函數名與要查找的函數名相比較,如果沒有任何一個函數名是符合的,表示文件中沒有指定名稱的函數
4.如果某一項定義的函數名與要查找的函數名符合,那么記下這個函數名在字符串地址表中的索引值,然后在 AddressOfNamesOrdinals 指向的數組中以同樣的索引值取出數組項的值,我們這里假設這個值是x
5.最后,以 x 值作為索引值,在 AddressOfFunctions 字段指向的函數入口地址表中獲取的 RVA 就是函數的入口地址
九、重定位1、重定位定義
重定位就是把程序的邏輯地址空間變換成內存中的實際物理地址空間的過程,也就是說在裝入時對目標程序中指令和數據的修改過程。他是實現多道程序在內存中同時運行的基礎。它保存在Data Directory數組中。2、重定位的作用
這里給出幾句代碼,來說明重定位的作用
從這幾句代碼中不難發現,這幾句代碼的目的地址都是用直接尋址的方式來表示的,在代碼的十六進制中,可以看到都是直接使用地址來表示的,當文件運行時,系統會分配一塊內存給文件,如果分配的內存與文件鏡像基址相同,這些代碼則可以正常執行,但是當分配到的內存與文件鏡像基址不同的時候,這些指令就會出現錯誤了,這個時候系統將會獲取文件的重定位信息,并把錯誤指令修正.
比如PUSH 403010這一句是在某個基址為400000的文件中的,當文件運行的時候,系統分配到的內存為500000,那么PUSH 403010這一指令如果是在重定位中,系統就會在加載時把它修復為PUSH 503010,這樣就保證了分配到的內存與基址不同的時候也能正常運行。
3、重定位結構
struct_IMAGE_BASE_RELOCATION
{
    DWORD  VirtualAddress;  //重定位數據開始的RVA地址
    DWORD  SizeOfBlock;     //重定位塊的長度
    WORD    TypeOffset;     //重定位項位數組
}IMAGE_BASE_RELOCATION;

VirtualAddress
是這一組重定位數據的開始RVA地址.各重定位項的地址加上這個值才是該重定位項完整的RVA地址.
SizeOfBlock
是重定位結構的大小
TypeOffset
是一個數組.數組每項大小為兩個字節,共16位.它又分為高4位和低12位,高4位代表重定位類型;低12位是重定位地址,它與VirtualAddress相加即是指向PE映像中需要修改的地址數據的指針.
4、深入分析重定位結構
我們繼續深入解析一下重定位結構IMAGE_BASE_RELOCATION,我們就用DLL來分析.假設,已經知道其重定位的偏移量為4000,大小為10,現在我們把它載入到winhex中,跳到重定位,可以看到

十、資源
1、簡介
程序內部和外部的界面等元素的二進制數據統稱為資源,程序把它們放在一個特定的表中,符合數據和程序分離的設計原則。資源包括加速鍵(Accelerator)、位圖(Bitmap)、光標(Cursor)、對話框(Dialog Box)、圖標(Icon)、菜單(Menu)、串表(String Table)、工具欄(Toolbar)和版本信息(Version Information)等。
資源有很多種類型,每種類型的資源中可能存在多個資源項,這些資源項用不同的ID或者名稱來區分。但是要將這么多種類型的不同ID 的資源有序地組織起來是一件非常痛苦的事情,因此,我們采取類似于磁盤目錄結構的方式保存。
PE文件中的資源是按照資源類型 -> 資源ID -> 資源代碼頁的3層樹型目錄結構來組織資源的,通過層層索引才能夠進入相應的子目錄找到正確的資源。
每一層都是以IMAGE_RESOURCE_DIRECTORY結構為頭部的,并且后面跟著一個IMAGE_RESOURCE_DIRECTORY_ENTRY結構數組。其中IMAGE_RESOURCE_DIRECTORY負責指出后面數組中的成員個數,IMAGE_RESOURCE_DIRECTORY_ENTRY數組成員分別指向下一層目錄結構。
2、位置
PE文件頭可選映像頭中數據目錄表的第3成員IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]指向映像調試信息,它保存在PE文件中,通常在".rsrc"區段。
3、資源目錄結構

4、IMAGE_RESOURCE_DIRECTORY
我們來看下 IMAGE_RESOURCE_DIRECTORY 這個結構,該結構長度為16 字節,共有 6 個字段,定義如下:
typedef struct _IMAGE_RESOURCE_DIRECTORY {
    DWORD  Characteristics;       //屬性,一般為0   
DWORD  TimeDateStamp;          //資源的產生時刻,一般為0   
WORD   MajorVersion;           //主版本號,一般為0   
WORD   MinorVersion;           //次版本號,一般為0   
WORD   NumberOfNamedEntries; //以名稱(字符串)命名的資源數量   
WORD   NumberOfIdEntries;    //ID(整型數字)命名的資源數量}
IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY;
其實在這里邊我們唯一要注意的就是 NameberOfNamedEntries 和 NumberOfIdEntries,它們說明了本目錄中目錄項的數量。兩者加起來就是本目錄中的目錄項總和。也就是后邊跟著的IMAGE_RESOURCE_DIRECTORY_ENTRY 數目。

5、IMAGE_RESOURCE_DIRECTORY_ENTRY(資源目錄入口的結構)
IMAGE_RESOURCE_DIRECTORY_ENTRY 緊跟在資源目錄結構后,此結構長度為 8 個字節,包含 2 個字段。該結構定義如下:
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
    union {
        struct {
            DWORD NameOffset:31;
            DWORD NameIsString:1;
        };
        DWORD  Name;        WORD   Id;
    };
    union {
        DWORD  OffsetToData;
        struct {
            DWORD   OffsetToDirectory:31;
            DWORD   DataIsDirectory:1;
        };
    };
} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY;
根目錄(資源目錄頭)下面存放的是這個結構體,這個結構體是一個聯合體,所以會有不同的解釋
1.首先,聯合體是8個字節大小.
2.其中第一個DWORD大小,看高位,如果高位是1,那么低31位是指向新的目錄項名稱的結構體IMAGE_RESOURCE_DIR_STRING_U,當結構用于第一層目錄時,定義的是資源類型;當結構定義于第二層目錄時,定義的是資源的名稱;當結構用于第三層目錄時,定義的是代碼頁編號。

批:NameOffset相對地址指向的是IMAGE_RESOURCE_DIR_STRING_U結構體,該結構體定義如下:typedef  struct_IMAGE_RESOURCE_DIR_STRING_U {
    WORD    Length;           //字符串的長度
    WCHAR   NameString[ 1 ];  //UNICODE字符串,由于字符串是不定長的。由Length制定長度
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
3.如果高位為0,則是ID號,這個ID號說的是 資源ID類型,比如3類型指的就是ICON
第二個DWORD,也是RVA偏移,如果高位為1,那么代表它還是一個目錄,也就是指向了一個新的根目錄了,這是個不斷遞歸的過程,如果為0,則指向文件偏移結構體了。

OffsetToData,指針;當最高位為1時,表示低位數據指向下一層目錄;當最高位為0時,表示沒有下一層目錄,低位數據指向一個IMAGE_RESOURCE_DATA_ENTRY結構。
注意,當Name和OffsetToData當做指針使用時,其值并不是RVA,而是表示相對于資源區塊起始位置的偏移值。

6、_IMAGE_RESOURCE_DATA_ENTRY(資源數據結構體)
文件偏移結構體(應該是資源數據結構體),共4個字段,16個字節
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
    DWORD  OffsetToData;  //資源數據的RVA   
DWORD  Size;            //資源數據的長度   
DWORD  CodePage;      //代碼頁, 一般為0   
DWORD  Reserved;      //保留字段
} IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY;
結構中的OffsetOfData 指向資源數據的指針,其為 RVA 值。

附錄:圖1:PE文件的基本結構如圖示


PDF 下載 鏈接,注:兩者完全一樣,可能論壇發布時沒有一些圖,但是PDF里面有的。
鏈接:https://pan.baidu.com/s/1nsUO2XCAQumCY64MRkq-Eg
提取碼:faru
復制這段內容后打開百度網盤手機App,操作更方便哦

免費評分

參與人數 20吾愛幣 +23 熱心值 +18 收起 理由
1051496412 + 1 + 1 我很贊同!
fsjt2016 + 1 + 1 我很贊同!
天秤 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
idiot_ccq + 1 我很贊同!
hardiness + 1 + 1 感謝,正在學習相關內容
Hmily + 5 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
加油 + 1 頭暈 惡心 SHELLCODE
xiaomumu + 1 + 1 [email protected]!
qingye110 + 1 + 1 好文章,收藏了
學習使人進步 + 1 [email protected]!
塵世迷途小書童 + 1 + 1 熱心回復!
l261178929 + 1 + 1 [email protected]!
gdf87521 + 1 + 1 好文章,我先收藏了
xzq1245 + 1 + 1 看不懂也給
china-ray + 1 + 1 [email protected]!
Pear + 1 + 1 吾愛有你更精彩!
朱朱你墮落了 + 1 + 1 一篇文章把PE講完,666!
念隨風 + 1 + 1 雖然看不懂QAQ
不拍電影不掉淚 + 1 我很贊同!
NewType + 2 + 1 我很贊同!

查看全部評分

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
 樓主| zmbilx 發表于 2019-9-13 21:22 <
本帖最后由 zmbilx 于 2019-9-13 21:25 編輯
你與明日 發表于 2019-9-13 20:50
個別圖片有其他論壇的水印,真的是你原創的嗎?.....

這個是我自己這幾天學習整理的,參考了好多好多的資料,由于參考的太多太雜太亂了,就沒加各處出處。如果哪個不合適,我立馬刪掉,在帖子開頭就說了哈,尊重原創。

開頭這一部分哈:
2019年8月~ 9月
感謝網絡上各類免費資源,由于引用資源太多,無法一一標注,故不在進行標注,LOG不在去除。如果侵權,請及時聯系,我第一時間進行刪除。取之免費,發之免費,故此套資料全部免費,如果侵權,請及時和我聯系,必馬上刪除。特別感謝魚C工作室!
推薦
hackyou 發表于 2019-9-13 21:41
本帖最后由 hackyou 于 2019-9-13 21:59 編輯

現在的PE解析工具都太差了,我覺得一個好的工具應該是這樣的,比如每個部分的二進制數據用不同顏色表示,然后每個有意義二進制數據塊是什么意義,如果選定,能立馬顯示出來,然后如果它是指示性數據,應該顯示一條指示線指向另外一塊二進制數據??梢允凳痹黽?,刪除了某塊二進制數據,軟件應該立馬可以告知該PE文件是否仍然是合法的PE文件,如果不是應該告知原因。
4#
 樓主| zmbilx 發表于 2019-9-13 11:59 <
本帖最后由 zmbilx 于 2019-9-13 14:33 編輯

先占一個樓,hhhhhhhhhh


鏈接補好了啦,不好意思哈



5#
NewType 發表于 2019-9-13 12:46
啊哦,你來晚了,分享的文件已經被取消了,下次要早點喲。
6#
2623666 發表于 2019-9-13 13:26
好好學習 天天向上
7#
仿佛悟道 發表于 2019-9-13 13:48
鏈接已掛,望樓主補鏈!
8#
 樓主| zmbilx 發表于 2019-9-13 14:32 <
zmbilx 發表于 2019-9-13 11:59
先占一個樓,hhhhhhhhhh

鏈接補上上哦
9#
alpt6285 發表于 2019-9-13 14:41
學習一下,elf
10#
Pear 發表于 2019-9-13 15:08
謝謝謝謝,學習學習!~
11#
dyh8283221 發表于 2019-9-13 15:12
多謝樓主,已經下載pdf,認真學習一下
12#
逍遙枷鎖 發表于 2019-9-13 15:15
圖片文件太模糊了,清晰就好了。
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:本版塊禁止灌水或回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|排列三5码组三最大遗漏 ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2020-2-27 12:37

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回復 排列三5码组三最大遗漏 返回列表