Tải bản đầy đủ - 0 (trang)
II. CẤU TRÚC FILE PE

II. CẤU TRÚC FILE PE

Tải bản đầy đủ - 0trang





Thành phần e_magic của DOS header chứa 2 giá trị là 4Dh và 5Ah( là 2 ký tự

“M” và “Z” ) của Mark Zbikowsky một trong những người sáng tạo chính của

MS-DOS (MZ là 2 bytes đầu tiên mà bạn sẽ nhìn thấy trong bất kỳ file PE nào).







Thành phần e_lfanew là một giá trị DWORD( 1 double word=4 bytes), nó nằm ở

vị trí cuối cùng của DOS Header và nằm ở vị trí bắt đầu của DOS Stub, chứa

offset của PE Header.







Các ánh xạ file thường được sử dụng vì chúng nạp vào bộ nhớ và sử dụng file

một cách dễ dàng.

Khi sử dụng win32 API đọc một file PE thì:



Trang 4



LBase



CreateFile():

//Open the Exe File

hFile = CreateFile("D:\\Test\\no.exe", GENERIC_READ, FILE_SHARE_READ,

NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (hFile == INVALID_HANDLE_VALUE) {

printf("\nERROR : Could not open the file specified\n");

_getch();

}







Hàm này được sử dụng để tạp và mở các file. Nó có thể mở các file, pipe,

stream hoặc các thiết bị I/O có sẵn và tạo file mở.



Ban đầu file đọc được sẽ ở Disk sau đó chúng ta sẽ lưu trữ tồn bộ nội dung của

file PE vào Physical Memory sử dụng hàm sau:

hMapObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);



Một File Mapping Object sẽ có thể Map tới nhiều file View sử dụng hàm:

lpBase = MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0);




Memory>



 Hàm MapViewOfFile() sẽ trả về một con trỏ trỏ đến địa chỉ cơ sở của ánh xạ

FileView, pointer này sẽ được sử dụng để truy cập trong bộ nhớ, nhờ đó mà ta có

thể đọc và ghi tại bất kỳ vị trí nào trong file.

Ta sẽ gán vị trí con trỏ dosHeader =lpBase nó có giá trị default là 0x04000000

//Get the DOS Header Base

dosHeader = (PIMAGE_DOS_HEADER)lpBase;// 0x04000000



Kiểm tra xem đó có phải là file PE hợp lệ hay khơng:

if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {

//Dump the Dos Header info



Trang 5



dumMSDOSHeader(dosHeader);

}

else {

printf("\nGiven File is not a valid DOS file\n");

goto end;

}



Code hiển thị dữ liệu MS DOS:

void dumMSDOSHeader(PIMAGE_DOS_HEADER dosHeader) {

printf("\nValid Dos Exe File\n------------------\n");

printf("\nDumping DOS Header Info....\n---------------------------");

printf("\n%-36s%s ", "Magic number : ", dosHeader->e_magic ==

0x5a4d ? "MZ(Mark Zbikowski)" : "-");

printf("\n%-36s%#x", "Bytes on last page of file :", dosHeader>e_cblp);

printf("\n%-36s%#x", "Pages in file : ", dosHeader->e_cp);

printf("\n%-36s%#x", "Relocation : ", dosHeader->e_crlc);

printf("\n%-36s%#x", "Size of header in paragraphs : ", dosHeader>e_cparhdr);

printf("\n%-36s%#x", "Minimum extra paragraphs needed : ",

dosHeader->e_minalloc);

printf("\n%-36s%#x", "Maximum extra paragraphs needed : ",

dosHeader->e_maxalloc);

printf("\n%-36s%#x", "Initial (relative) SS value : ", dosHeader>e_ss);

printf("\n%-36s%#x", "Initial SP value : ", dosHeader->e_sp);

printf("\n%-36s%#x", "Checksum : ", dosHeader->e_csum);

printf("\n%-36s%#x", "Initial IP value : ", dosHeader->e_ip);

printf("\n%-36s%#x", "Initial (relative) CS value : ", dosHeader>e_cs);

printf("\n%-36s%#x", "File address of relocation table : ",

dosHeader->e_lfarlc);

printf("\n%-36s%#x", "Overlay number : ", dosHeader->e_ovno);

printf("\n%-36s%#x", "OEM identifier : ", dosHeader->e_oemid);

printf("\n%-36s%#x", "OEM information(e_oemid specific) :",

dosHeader->e_oeminfo);

printf("\n%-36s%#x", "RVA address of PE header : ", dosHeader>e_lfanew);



printf("\n===========================================

====================================\n");

}



IV.



PE HEADER

PE Header là thuật ngữ chung đại diện cho một cấu trúc được đặt tên là

IMAGE_NT_HEADERS. Cấu trúc này bao gồm 3 thành phần và được định nghĩa trong

file windows.inc như sau:



Trang 6



Con trỏ trỏ đến NT HEADER được tính bằng con trỏ đầu file + địa chỉ RVA của PE

Header

//Get the Base of NT Header(PE Header) = lpBase + RVA address of PE header

ntHeader = (PIMAGE_NT_HEADERS)((DWORD)lpBase + (dosHeader->e_lfanew));







Signature:

Là một biến DWORD chứa những giá trị sau: 50h, 45h, 00( các ký tự “PE” được

đi kèm bởi các giá trị tận cùng là 0)

Chúng ta cần kiểm tra giá trị này để xem đó có phải là file PE hợp lệ hay không:



if (ntHeader->Signature == IMAGE_NT_SIGNATURE) {

printf("NTHEADER: %x", ntHeader);

printf("\nValid PE file \n-------------\n");

…………………

}







FileHeader ( 20bytes)

IMAGE_FILE_HEADERS: chứa thơng tin về sơ đồ bố trí vật lý và nhũng đặc

tính của file. Ví dụ: số lượng các section,…

o FileHeader được định nghĩa như sau:



Trong cấu trúc này thì thành phần chúng ta cần quan tâm là

NumberOfSections. Trong trường hợp muốn thêm hoặc xóa bất kỳ các

sections nào trong 1 file PE thì thành phần này phải thay đổi.

Characteristics bao gồm các cờ mà các cờ này xác định những thể hiện để

chúng ta biết được đang làm việc với 1 file dll hay file thực thi.

Code hiển thị thông tin File Header:

void DumFileHeader(PIMAGE_NT_HEADERS ntHeader) {

//Get the IMAGE FILE HEADER Structure

IMAGE_FILE_HEADER header = ntHeader->FileHeader;

//Determine Machine Architechture

printf("\n%-36s", "Machine Architechture :");

checkMachineOfFileHeader(header);

//Determine the characteristics of the given file

printf("\n%-36s %#x \n", "Characteristics:", header.Characteristics);

checkCharacteristics(header);

char buff[40];



Trang 7



printf("\n%-36s%x", "Time Stamp :", header.TimeDateStamp);

ctime_s(buff, sizeof buff, &(header.TimeDateStamp));

printf("- %s\n", buff);

//Determine Time Stamp

printf("%-36s%d",

"No.sections(size)

:",

header.NumberOfSections);

//Determine number of sections

printf("\n%-36s%d",

"No.entries

in

symbol

table

:",

header.NumberOfSymbols);

printf("\n%-36s%d",

"Size

of

optional

header

:",

header.SizeOfOptionalHeader);

}



Trên Lord thì nó được xác định như sau:







Optional Header( 224 bytes tiếp theo)

IMAGE_OPTINAL_HEADER32: chứa thông tin về sơ đồ logic bên trong của 1

file PE. Ví dụ: AddressOpEntryPoint. Kích thước của nó được quy định bởi

một thành phần của FileHeader. Các cấu trúc của những thành phần này cũng

được định nghĩa trong file windows.h.

o Optional Header được định nghĩa như sau:



Trang 8























AddressOfEntryPoint- RVA(địa chỉ tương đối ) của câu lệnh

đầu tiên mà sẽ được thực thi khi chương trình PE Loader sẵn sàng

để run PE File( thơng thường nó trỏ tới section .text ) hay CODE.

Magic: Xác định xem nhị phân là 32 bit hay 64 bit.

• 0x10B: 32 bit

• 0x20B: 64 bit

ImageBase- Địa chỉ nạp được ưu tiên cho PE file. Lấy ví dụ: Nếu

như giá trị trong trường hợp này là 400000h, Pe Loader sẽ cố gắng

để nạp vào trong không gian địa chỉ ảo mà bắt đầu tại 4000000h.

Từ được ưu tiên vào đây có nghĩ là PE Loader không thể nạp file

tại địa chỉ đó nếu như có một module nào khác đã chiếm giữ vùng

địa chỉ này, 99% các trường hợp giá trị của ImageBase luôn là

400000h.

SectionAlignment- Phần liên kết của các Sections trong bộ nhớ.

Khi file thực thi được ánh xạ vào trong bộ nhớ thì mỗi section phải

bắt đầu tại một địa chỉ ảo mà là một bội số của giá trị này. Ví dụ:

Nếu giá trị tại trường này là 4096(1000h) thì mỗi section tiếp

theo sẽ phải bắt đầu tại vị trí mà section trước đó cộng với 4096

bytes.

Nếu section đầu tiên là tại 401000h và kích thước của nó là 10

bytes, vậy section tiếp theo tại 402000h cho dù không gian địa chỉ

giữa 401000h và 402000h sẽ hầu không được sử dụng.

FileAlignment- Phần liên kết của các Section trong file. Ví dụ:

nếu giá trị cụ thể của trường này là 512(200h) thì mỗi secti(tương

tự như SectionAlignment)

Trang 9













SizeOfImage- Tồn bộ kích thước của PE Image trong bộ nhớ. I

SizeOfHeader- Kích thước của tất cả các headers+section table.

Tóm lại nó bằng Kích thước file- kích thước được tổng hợp của

tồn bộ sections trong file. Có thể dùng giá trị này như một file

offset của section đầu tiên trong file PE.

DataDirectoryMột

mảng

của

16

IMAGE_DATA_DIRECTORY structures, mỗi một phần có liên

quan tới một cấu trúc dữ liệu quan trọng trong PE file chẳng hạn

như import address table.



Code hiển thị thông tin Optional Header:

void DumOptionalHeader(PIMAGE_NT_HEADERS ntHeader) {

printf("\n\nDumping PE Optional Header Info....\n-----------------------------------");

//Info about Optional Header

IMAGE_OPTIONAL_HEADER opHeader = ntHeader->OptionalHeader;

//printf("\n\nInfo of optional Header\n-----------------------");

printf("\n%-36s%#x", "Address of Entry Point : ", opHeader.AddressOfEntryPoint);

printf("\n%-36s%#x", "Base Address of the Image : ", opHeader.ImageBase);

printf("\n%-36s%s", "SubSystem type : ",

opHeader.Subsystem == 1 ? "Device Driver(Native windows Process)" :

opHeader.Subsystem == 2 ? "Windows GUI" :

opHeader.Subsystem == 3 ? "Windows CLI" :

opHeader.Subsystem == 9 ? "Windows CE GUI" :

"Unknown"

);

printf("\n%-36s%s", "Given file is a : ", opHeader.Magic == 0x20b ? "PE32+(64)" :

"PE32");

printf("\n%-36s%d", "Size of code segment(.text) : ", opHeader.SizeOfCode);

printf("\n%-36s%#x", "Base address of code segment(RVA) :",

opHeader.BaseOfCode);

printf("\n%-36s%d", "Size of Initialized data : ", opHeader.SizeOfInitializedData);

printf("\n%-36s%#x", "Base address of data segment(RVA) :",

opHeader.BaseOfData);

printf("\n%-36s%#x", "Section Alignment :", opHeader.SectionAlignment);

printf("\n%-36s%d", "Major Linker Version : ", opHeader.MajorLinkerVersion);

printf("\n%-36s%d", "Minor Linker Version : ", opHeader.MinorLinkerVersion);



Trang 10



}



Trên Lord thì nó được xác định như sau:



Cấu trúc DATA DIRECTORY

Data Directory là 128 bytes cuối cùng của OptionalHeader, và lần lượt là những

thành phần cuối cùng của IMAGE_NT_HEADERS.



Cấu trúc của Data Directory có 2 thành phần mà bao gồm thơng tin về vị trí và

kích thước của cấu trúc dữ liệu.

o VirtualAddress: là một địa chỉ ảo tương đối (relative virtual address) của

cấu trúc dữ liệu

o isize: bao gồm kích thước theo bytes của cấu trúc dữ liệu

o 16 directories mà những cấu trúc này tham chiếu đến, bản thân chúng

được được nghĩa trong file window.inc:



Trang 11



Trong một chương trình đọc file PE thì 2 giá trị này được xác định như sau:



Virtual

Address



isize



Trên hình minh họa trên , vị trí được tơ màu hồng chính là Import Table, với 8

bytes đầu chính là Virtual Address= 02D000h và 8 bytes cuối cùng thể hiện

kích thước của cấu trúc Import = 181Eh

Trong win32 fuction, 2 giá trị này được xác định như sau:

dwImportDirectoryVA = ntHeader->OptionalHeader.DataDirectory[1].VirtualAddress;

ImportSize = ntHeader->OptionalHeader.DataDirectory[1].Size;



với ntHeader là con trỏ trỏ đến cấu trúc IMAGE_NT_HEADER.

Để xác định được vị trí của một directory đặc biệt, bạn xác định rõ địa chỉ tương

đối từ data directory. Sau đó sử dụng địa chỉ ảo để xác định section nào directory

ở trong. Một khi bạn phân tích section nào chứa directory, thì Section Header cho

section đó sau đó sẽ được sử dụng để tìm ra offset chính xác.



Ở đây chúng ta cần xác định 2 khái niệm đó là RVA( relative virtual address) và

VA( virtual address). VA chính là địa chỉ đầu tiên mà file được nạp. còn RVA

được xác định là địa chỉ đầu tiên mà file được nạp trừ đi Image Base.

RVA=VA- Image Base

Ví dụ: Nếu một File PE nạp tại địa chỉ 400000h trong virtual address(VA)

space và chương trình bắt đầu thực thi tại virtual address 401000h, chúng ta có

thể nói rằng chương trình bắt đầu thực thi tại RVA 1000h.

Trang 12



Tại sao lại sử dụng RVA? Đó là để giảm bởi q trình nạp cả trình loader. Đó là

bởi vì nếu một module có thể được relocated bất kỳ vị trí nào trong khơng gian địa

chỉ ảo, nó sẽ gây trở ngại cho trình loader để fix mọi hardcode address trong

module. Nhưng ngược lại, nếu tất cả relocatable items trong file use RVA, there is

no need for the loader to fix anything: nó chỉ đơn giản relocates toàn bộ module

tới một new starting VA.

Chuyển đổi từ Virtual Offset đến RawOfsset:



Cơng thức chung là:

RVA= RawOffset_YouHaveRawOffsetOfSection+VirtualOffsetOfSection+ImageBase





IMAGE_EXPORT_DIRECTORY: trỏ tới 3 mảng và một bảng những

chuỗi ký tự ASCII. Mảng quan trọng là Export Address Table( EAT), vì

nó là một mảng con của các con trỏ hàm mà chứa địa chỉ của các export

functions. Hai mảng tiếp theo là Export Name table và Export Ordinal

Table chạy song song theo thứ tự sắp xếp tăng dần dựa theo tên của các

hàm để có thể được thực hiện và đưa ra kết quả là số thứ tự của hàm đó

được tìm thấy vào một mảng khác



Trang 13



Thơng thường, NumberOfFunction phải ít nhất bằng NumberOfNames.

Tuy nhiên trong một số trường hợp thì NumberOfNames ít hơn

NumberFunctions. Khi một hàm được Export thơng quan số thứ tự, nó

khơng có trong danh sách 2 mảng ENT và EOT- nó khơng có tên. Những

hàm khơng có tên này sẽ được Export thông qua số thứ tự.



Code hiển thị nội dung Export:

void DumpExportDirectory32(LPVOID lpBase, PIMAGE_NT_HEADERS32 ntHeader,

PIMAGE_DOS_HEADER dosHeader) {

DWORD dwExportDirectoryVA, ExportSize, dwRawOffset;

dwExportDirectoryVA = ntHeader>OptionalHeader.DataDirectory[0].VirtualAddress; //get address of

ExportDirectory

ExportSize = ntHeader->OptionalHeader.DataDirectory[0].Size; //get size of

ExportDirectory



Trang 14



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

II. CẤU TRÚC FILE PE

Tải bản đầy đủ ngay(0 tr)

×