.EXE / .DLL PE Explorer - Felix John COLIBRI. |
- abstract : presents and analyzes the content of .EXE and .DLL files
- key words : Windows - Portable Executable - System Programming - tTreeView - Memory Mapped files
- software used : Windows XP, Delphi 6
- hardware used : Pentium 2.800Mhz, 512 M memory, 140 G hard disc
- scope : Delphi 1 to 2006, Turbo Delphi for Windows
- level : Windows developer
- plan :
1 - Analyzing the PE format
In order to perform some logging on an database application, we had to monitor each call to the Sql Engine. To do so, we chose to capture calls to the Client DLL, and this required some .DLL Injection technique. So we took our old .EXE
analyzer and added the required code. Spelunking into the .EXE was not that easy, since the original code dated back to Windows 3.1. And since it turns out that the format is still used (event for
64 bits and for .Net compiled files), we decided to publish the project. This paper presents the overall organization, and the project allows to present the structure and content of those files.
2 - The Portable Executable Format 2.1 - General PE properties Programs and DLLs compiled for Windows are saved to disc in the PE (Portable Executable) format.
The main properties of the format are:
2.2 - Overall format The overall structure contains - a DOS stub
- a NT header
- a Section header list
- the list of Sections
Here is the overall picture:
2.3 - The Dos stub The historical part allowed to check the nature of the file at the time when DOS was the base OS, and Windows (3.1) was loaded from DOS. This $100 byte part mainly contains
- a signature ($544D, which is MZ, Mark Zbikowski, a Dos architect)
- m_nt_header_file_address field: he address of the main table which is the NT header
2.4 - The NT header The header contains
- the "PE" signature
- a file header
- the "optional" header (which is not optional at all)
- the section directory
Here is the definition
t_nt_header= Record
m_nt_signature: dWord;
m_nt_file_header: t_nt_file_header;
m_nt_optional_header: t_nt_optional_header;
m_nt_section_directory: t_nt_section_directory;
end; // t_nt_header | with the following figure:
2.4.1 - The File Header Here is the definition
t_nt_file_header= packed record
Machine: Word;
m_number_of_sections: Word;
TimeDateStamp: dWord;
PointerToSymbolTable: dWord;
NumberOfSymbols: dWord;
SizeOfOptionalHeader: Word;
Characteristics: Word;
end; // t_nt_file_header | and
- SizeOfOptionalHeader is the size of the t_nt_optional_header
2.5 - The optional header This header is defined by
t_nt_optional_header= packed record
// -- Standard fields.
Magic: Word;
MajorLinkerVersion: Byte;
MinorLinkerVersion: Byte;
SizeOfCode: dWord;
SizeOfInitializedData: dWord;
SizeOfUninitializedData: dWord;
AddressOfEntryPoint: dWord;
BaseOfCode: dWord;
BaseOfData: dWord;
// --Nt additional fields
ImageBase: dWord;
SectionAlignment: dWord;
FileAlignment: dWord;
MajorOperatingSystemVersion: Word;
MinorOperatingSystemVersion: Word;
MajorImageVersion: Word;
MinorImageVersion: Word;
MajorSubsystemVersion: Word;
MinorSubsystemVersion: Word;
Win32VersionValue: dWord;
SizeOfImage: dWord;
SizeOfHeaders: dWord;
CheckSum: dWord;
Subsystem: Word;
DllCharacteristics: Word;
SizeOfStackReserve: dWord;
SizeOfStackCommit: dWord;
SizeOfHeapReserve: dWord;
SizeOfHeapCommit: dWord;
LoaderFlags: dWord;
m_section_entry_count: dWord;
end; // t_nt_optional_header |
2.5.1 - The Section Directory (alias DataDirectory) This is an array of 16 structures telling where the Sections are located. Each section entry is defined by
t_section_entry= record
m_section_relative_virtual_address: dWord;
m_section_size: dWord;
end; // t_section_entry | where:
- m_section_relative_virtual_address is the address of the section start (relative to the base load address)
- m_section_size is the section size
and the directory is an array of those entries:
const k_section_directory_count= 16;
type t_nt_section_directory=
packed array[0..k_section_directory_count- 1] of t_section_entry;
| Note that - the WINNT.H names this structure DataDirectory, and it is included in the ImageOptionalHeader structure
2.6 - The Section Headers
This structure is located just after the t_optional_header, and is an array or t_section_header records:
Each section header is defined by:
const k_section_name_max= 8;
type t_section_address_and_size= packed record
case Integer of
0: (m_section_physical_address: dWord);
1: (m_section_virtual_size: dWord);
end; // t_section_address_and_size
t_section_header= packed record
m_name: packed array[0..k_section_name_max- 1] of Byte;
m_address_and_size: t_section_address_and_size;
m_virtual_address: dWord;
m_size_of_raw_data: dWord;
m_pointer_to_raw_data: dWord;
m_pointer_to_relocations: dWord;
PointerToLinenumbers: dWord;
NumberOfRelocations: Word;
NumberOfLinenumbers: Word;
Characteristics: dWord;
end; // t_section_header |
The header count is given by t_nt_file_header.m_number_of_sections
2.7 - The Sections 2.7.1 - The different sections Section can contain executable code, data (globals), resources etc.
- the imported and exported symbols (functions, variables)
- the Windows resources (bitmaps, cursors etc)
2.7.2 - Function Import and Export
When a DLL exports a function, it can either use an index or an identifier name. Since using names involves a search in a name list, using function indexes is quicker. However developer might prefer the usage of names for maintenance or
readability considerations. In any case, this explains why both import and export structures contain both name lists and index lists.
2.7.3 - The Import Section
This section contains an list of import descriptors. At the end of the list there is an 0 filled descriptor. Each import descriptor is defined by
t_imported_module= record
// -- INT: Import Name table
m_pt_first_function_original: t_pt_imported_function;
m_import_timestamp: dWord;
m_import_forwarder_chain: dWord;
m_imported_module_name_rva: dWord;
// -- IAT: Import Address Table
m_pt_first_function: t_pt_imported_function;
end; // t_imported_module |
where - m_imported_module_name_rva is the relative address of the .DLL name
- m_import_forwarder_chain allows to forwad the imported name from one .DLL to another one
- m_pt_first_function_original and m_pt_first_function are pointers to 2 tables containing information about each imported function.
Each function is described by a variant record:
t_imported_by_name_function= record
m_import_index_hint: Word;
m_import_name: Byte;
end; // t_imported_by_name_function
t_pt_imported_by_name_function= ^t_imported_by_name_function; t_imported_function=
record case Integer of
1: (m_pt_forwarder_string: ^Byte);
2: (m_function_address: pdWord);
3: (m_function_index: dWord);
4: (m_pt_imported_by_name_function: t_pt_imported_by_name_function);
end; // t_imported_function t_pt_imported_function= ^t_imported_function; |
Let's recap the import structure: - the t_nt_header allows to get the t_section_header
- having the section base address, we compute the individual .DLL imported module record
- this record contains the module name and pointers to 2 function lists with identical structure and slightly different content. The end of the function list is indicated by a zero record
The overall picture is
or with more detail
For the INT, the content for each imported function is a dWord. And the dWord contains
- if the high bit of this value is 1, the 31 low bit part is a function index
- if the high bit is 0, the 31 low bit part are a relative value address pointing to a t_imported_by_name_function record
For the IAT, the content on disc is the same, as the INT, but once loaded into memory, the dWord is overwritten with the actual address of the code of the imported function
The presence of two structure allows binding: if the loader overwrites the dWord value with the true code address, there must be a way to still keep the original information. The INT was long ignored by Borland compilers
2.7.4 - The Export Section The export section is defined by:
t_exported_functions= record
Characteristics: dWord;
TimeDateStamp: dWord;
MajorVersion: Word;
MinorVersion: Word;
m_dll_name_rva: dWord;
m_export_start_index: dWord;
m_exported_function_count: dWord;
m_exported_name_count: dWord;
// -- export Address Table (EAT)
m_exported_function_address: Pdword;
// -- export name table (ENT)
m_exported_function_name_address: pdWord;
m_exported_function_index_address: pdWord;
end; // t_exported_functions |
and: - m_dll_name_rva: this .DLL name
- for the exported name list:
- exported_name_count: how many functions are in the table name
- m_exported_function_name_address: a table of the the export name addresses
- for each of those names, there is a corresponding entry in the m_exported_function_index_address table of function indexes. To the
indexes, you have to add the m_export_start_index (usually the index starts at 1)
- the index plus the starting index point to the m_exported_function_address table, which contains the code address of the function
This looks like this:
2.7.5 - The Resource Section The resource section is organized like a file directory: it contains folders
and entries. The base directory (folder) structure is:
t_resource_directory= packed record
Characteristics: DWORD;
TimeDateStamp: DWORD;
MajorVersion: WORD;
MinorVersion: WORD;
m_name_entry_count: WORD;
m_id_entry_count: WORD;
end; // t_resource_directory |
and: - m_name_entry_count is the number of name entries
- m_id_entry_count is the name of id entries
Each (nested) directory is followed by a table of entries (the count is the sum
of both counts). The entries are defined by:
t_resource_entry= packed record
m_name_or_id: DWORD;
m_offset_to_data: DWORD;
end; // t_resource_entry | where:
- m_offset_to_data:
- if the high bit is set, the entry is a nested directory, and if not, it is a data entry
- the low bits are the offset RELATIVE TO THE RESOURCE SECTION (not a rva)
- m_name_or_id:
- for the first level, and if the high bit is 0, the value is a resource type (1 for Cursor, 2 for Bitmap and so on)
- in the other cases, this field is a resource id (a number or an address to a WideString name)
And each data entry looks like this
t_resource_data_entry= packed record
m_data_offset_to_data: DWORD;
m_data_size: DWORD;
m_data_code_page: DWORD;
Reserved: DWORD;
end; // t_resource_data_entry |
This traditional recursive structure can then be displayed like this
3 - The Delphi PE Explorer source code 3.1 - Basic organization The code include 3 parts - a PE structure definition UNIT (which was used in the previous presentation)
- a CLASS allowing to compute and display the different parts
- the main tForm
3.2 - The definitions This UNIT is the straight Pascal version of the WinNT.H, with simple renaming applied.
Notice that many of the definitions are already in the WINDOWS.PAS Delphi file
3.3 - The c_pe CLASS This CLASS has the ability to access and display the different parts of a PE
structure. The definition is the following:
c_pe= Class(tComponent) private
public m_file_name: String;
m_is_file_exe: Boolean;
m_file_handle: tHandle;
m_mapping_handle: tHandle;
m_base_address: dWord;
m_c_display_strings: tStrings;
constructor Create(p_file_name: String; p_c_strings: tStrings);
procedure display_pe(p_text: String);
function f_display_address(p_pt: Pointer): String;
procedure display_address_and_text(p_pt: Pointer; p_text: String);
function f_pt_nt_header: t_pt_nt_header;
function f_pt_section_header(p_section: dWord): t_pt_section_header;
function f_pt_section_by_name_header(p_pt_section_name_z: pChar):
t_pt_section_header;
function f_pt_enclosing_header_section(p_enclosed_address: dWord):
t_pt_section_header;
function f_pt_imported_module(p_dll_index: dWord;
var pv_delta_mapping: dWord): t_pt_imported_module;
function f_pt_exports_directory(var pv_delta_mapping,
pv_start_address, pv_end_address: dWord): t_pt_exported_functions;
function f_pt_buffer(p_address: Integer): t_pt_bytes;
function f_pt_word(p_address: Integer): t_pt_word;
procedure analyze_dos_header;
procedure analyze_nt_header;
procedure analyze_nt_file_header;
procedure analyze_nt_optional_header;
procedure analyze_section_directory;
procedure analyze_section_header_table;
procedure analyze_imported_dlls(p_c_dll_name_stringlist: tStrings);
procedure analyze_imported_functions(p_dll_name: String; p_c_strings: tStrings;
p_borland: String);
function f_pt_imported_function_address(p_dll_name, p_function_name: String): pdWord;
procedure analyze_exports;
procedure analyze_resources;
end; // c_pe |
The original code was written using Memory Mapped Files, which is a Windows
technique allowing to access with pointer a disc file. We also wanted to be able to explore an in-memory module, so we included a flag allowing to compute addresses from file or memory. Here is the constructor:
constructor c_pe.Create(p_file_name: String; p_c_strings: tStrings);
begin Inherited Create(Nil);
m_file_name:= p_file_name;
m_c_visited_list:= c_address_range_list.create_address_range_list('visited_list');
if p_file_name= ''
then begin
m_is_file_exe:= False;
m_base_address:= hInstance; end
else begin
m_file_handle:= CreateFile(pChar(p_file_name),
Generic_Read, File_Share_Read, k_security_nil,
Open_Existing, File_Attribute_Normal, k_template_0);
// -- create a mapping
m_mapping_handle:= CreateFileMapping(m_file_handle,
k_security_nil, Page_ReadOnly, k_high_max_0, k_low_max_0,
k_name_nil);
// -- create a view
m_base_address:= dWord(MapViewOfFile(m_mapping_handle, File_Map_Read,
k_high_offset_0, k_low_offset_0,
k_all_offsets_0));
m_is_file_exe:= True; end;
m_c_display_strings:= p_c_strings; end; // Create |
There are several function which compute the addresses or return pointers to the different parts of a PE. For instance, here is the NT header access function:
function c_pe.f_pt_nt_header: t_pt_nt_header; begin
Result:= t_pt_nt_header(m_base_address
+ t_pt_dos_header(m_base_address)^.m_nt_header_file_address);
end; // f_pt_nt_header | Using those access functions, it is then easy to display each PE element content.
The TreeView explorer To load the PE information into a tTreeView, we first started to directly create the nodes by using the c_pe routines. This was quite akward, since we
had to handle both our access routines and the recursive tree structure. In addition, no object was associated with each tTreeNode. So we finally created a c_pe_element tree, with specific nodes for each part
of the PE, and those nodes were added to each tTreeNode. The structure of our pe elements follow the classic composite pattern, with a separate element for each PE record
Once the structure was filled, initializing the tTreeNode was a ten minute job.
3.4 - The Main Form This Form allows - to select the target .EXE or .DLL
- to display the content of some part in a tMemo
- to build a tTreeView displaying the PE content
3.5 - sample DLL To illustrate the analysis of the PE structure, we will use a simple Delphi
.DLL, with the following code: library d_min_max;
var g_integer: Integer;
function f_min(p_one, p_two: Integer): Integer; stdcall;
var l_local: Integer; begin
l_local:= $AAAA;
g_integer:= l_local+ $7777;
if p_one < p_two
then Result := p_one
else Result:= p_two;
end; // f_min
function f_max(p_one, p_two: Integer): Integer; stdcall;
var l_local: Integer; begin
l_local:= $BBBB;
if p_one > p_two
then Result:= p_one
else Result:= p_two;
end; // f_max exports f_min,
f_max; begin end. |
The compiled .DLL is a 8 K file, d_min_max.dll. A simplified hex dump of this file is:
Dos Header
0000: 4D 5A 50 00 02 00 00 00 04 00 0F 00 FF FF 00 00 : MZP..... ......
0010: B8 00 00 00 00 00 00 00 40 00 1A 00 00 00 00 00 : ....... @.......
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
0030: 00 00 00 00 00 00 00 00 00 00 00 00
m_nt_header_file_address
00 01 00 00 : ........ ........
...ooo...
NT header
nt_signature
0100: 50 45 00 00
nt_file_header
4C 01 07 00 19 5E 42 2A 00 00 00 00 : PE..L... .^B*....
0110: 00 00 00 00 E0 00 8E A1
nt_optional_header
0B 01 02 19 00 10 00 00 : ..... ........
0120: 00 0C 00 00 00 00 00 00 DC 1F 00 00 00 10 00 00 : ........ .......
0130: 00 20 00 00 00 00 40 00 00 10 00 00 00 02 00 00 : . ....@. ........
0140: 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 : ........ ........
0150: 00 80 00 00 00 04 00 00 00 00 00 00 02 00 01 00 : ....... ........
0160: 00 00 00 00 00 00 00 00 00 00 10 00 00 10 00 00 : ........ ........
0170: 00 00 00 00 10 00 00 00
nt_section_directory
00 50 00 00 56 00 00 00 : ........ .P..V...
0180: 00 40 00 00 BE 02 00 00 00 70 00 00 00 02 00 00 : .@..... .p......
0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
01A0: 00 60 00 00 AC 01 00 00 00 00 00 00 00 00 00 00 : .`..... ........
01B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
01C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
01E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
01F0: 00 00 00 00 00 00 00 00
section headers
CODE section header
43 4F 44 45 00 00 00 00 : ........ CODE....
0200: F4 0F 00 00 00 10 00 00 00 10 00 00 00 04 00 00 : ....... ........
0210: 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 60 : ........ .... ..`
0220: 44 41 54 41 00 00 00 00 A0 00 00 00 00 20 00 00 : DATA.... .... ..
0230: 00 02 00 00 00 14 00 00 00 00 00 00 00 00 00 00 : ........ ........
0240: 00 00 00 00 40 00 00 C0
42 53 53 00 00 00 00 00 : ....@.. BSS.....
0250: ED 06 00 00 00 30 00 00 00 00 00 00 00 16 00 00 : ....0.. ........
0260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 : ........ .......
0270: 2E 69 64 61 74 61 00 00 BE 02 00 00 00 40 00 00 : .idata.. ....@..
0280: 00 04 00 00 00 16 00 00 00 00 00 00 00 00 00 00 : ........ ........
0290: 00 00 00 00 40 00 00 C0
2E 65 64 61 74 61 00 00 : ....@.. .edata..
02A0: 56 00 00 00 00 50 00 00 00 02 00 00 00 1A 00 00 : V....P.. ........
02B0: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 50 : ........ ....@..P
02C0: 2E 72 65 6C 6F 63 00 00 AC 01 00 00 00 60 00 00 : .reloc.. ....`..
02D0: 00 02 00 00 00 1C 00 00 00 00 00 00 00 00 00 00 : ........ ........
02E0: 00 00 00 00 40 00 00 50
2E 72 73 72 63 00 00 00 : ....@..P .rsrc...
02F0: 00 02 00 00 00 70 00 00 00 02 00 00 00 1E 00 00 : .....p.. ........
0300: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 50 : ........ ....@..P
0310: 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 : ........ .......
0320: 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 : ..... .. ........
0330: 00 00 00 00 40 00 00 50
...ooo...
Sections
CODE
...ooo...
1310: 64 89 10 68 20 1F 40 00 C3 E9 82 F6 FF FF EB F8 : d.h .@.
1320: 5D C3 8B C0 83 2D E0 36 40 00 01 C3
f_min ( $AAAA and $7777 markers )
55 8B EC 83 : ]Ë-6 @..U
1330: C4 F8 C7 45 F8 AA AA 00 00 8B 45 F8 05 77 77 00 : E. .E.ww.
1340: 00 A3 E8 36 40 00 8B 45 08 3B 45 0C 7D 08 8B 45 : .6@.E .;E.}.E
1350: 08 89 45 FC EB 06 8B 45 0C 89 45 FC 8B 45 FC 59 : .E.E .EEY
1360: 59 5D C2 08 00 8D 40 00
f_max ( $BBBB marker )
55 8B EC 83 C4 F8 C7 45 : Y]..@. UE
1370: F8 BB BB 00 00 8B 45 08 3B 45 0C 7E 08 8B 45 08 : ..E. ;E.~.E.
1380: 89 45 FC EB 06 8B 45 0C 89 45 FC 8B 45 FC 59 59 : E.E. EEYY
1390: 5D C2 08 00 55 8B EC 33 C0 55 68 B3 1F 40 00
...ooo...
DATA
1400: 00 00 00 00 00 00 00 00 02 8D 40 00 32 13 8B C0 : ........ .@.2.
1410: 00 8D 40 00 00 8D 40 00 00 8D 40 00 00 00 00 00 : .@..@. .@.....
1420: 00 00 00 00 00 CB CC C8 C9 D7 CF C8 CD CE DB D8 : .....
1430: CA D9 DA DC DD DE DF E0 E1 E3 00 E4 E5 8D 40 00 : .@.
1440: 52 75 6E 74 69 6D 65 20 65 72 72 6F 72 20 20 20 : Runtime error
1450: 20 20 61 74 20 30 30 30 30 30 30 30 30 00 8B C0 : at 000 00000.
1460: 45 72 72 6F 72 00 8B C0 30 31 32 33 34 35 36 37 : Error. 01234567
1470: 38 39 41 42 43 44 45 46 00 00 00 00 00 00 00 00 : 89ABCDEF ........
1480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
1490: 3C 1E 40 00 E8 1D 40 00 A4 1D 40 00 14 1E 40 00 :.@..@. .@...@.
...ooo...
.iData (imported symbols)
1600: 00 00 00 00 00 00 00 00 00 00 00 00 DC 40 00 00 : ........ ....@..
1610: 64 40 00 00
00 00 00 00 00 00 00 00 00 00 00 00 : d@...... ........
1620: F8 41 00 00 A4 40 00 00
00 00 00 00 00 00 00 00 : A..@.. ........
1630: 00 00 00 00 24 42 00 00 B0 40 00 00 00 00 00 00 : ....$B.. @......
1640: 00 00 00 00 00 00 00 00 64 42 00 00 C0 40 00 00 : ........ dB..@..
1650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
1660: 00 00 00 00 EA 40 00 00 02 41 00 00 1A 41 00 00 : ....@.. .A...A..
1670: 32 41 00 00 40 41 00 00 4C 41 00 00 62 41 00 00 : 2A..@A.. LA..bA..
1680: 74 41 00 00 86 41 00 00 94 41 00 00 A2 41 00 00 : tA..A.. A..A..
1690: AE 41 00 00 CA 41 00 00 D6 41 00 00 E8 41 00 00 : A..A.. A..A..
16A0: 00 00 00 00 04 42 00 00 16 42 00 00 00 00 00 00 : .....B.. .B......
16B0: 32 42 00 00 46 42 00 00 56 42 00 00 00 00 00 00 : 2B..FB.. VB......
16C0: 72 42 00 00 80 42 00 00 8E 42 00 00 98 42 00 00 : rB..B.. B..B..
16D0: A4 42 00 00 B0 42 00 00 00 00 00 00
Kernel32.Dll imported functions
6B 65 72 6E : B..B.. ....kern
16E0: 65 6C 33 32 2E 64 6C 6C 00 00 00 00 44 65 6C 65 : el32.dll ....Dele
16F0: 74 65 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F : teCritic alSectio
1700: 6E 00 00 00 4C 65 61 76 65 43 72 69 74 69 63 61 : n...Leav eCritica
1710: 6C 53 65 63 74 69 6F 6E 00 00 00 00 45 6E 74 65 : lSection ....Ente
1720: 72 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F 6E : rCritica lSection
1730: 00 00 00 00 56 69 72 74 75 61 6C 46 72 65 65 00 : ....Virt ualFree.
1740: 00 00 4C 6F 63 61 6C 46 72 65 65 00 00 00 47 65 : ..LocalF ree...Ge
1750: 74 43 75 72 72 65 6E 74 54 68 72 65 61 64 49 64 : tCurrent ThreadId
1760: 00 00 00 00 47 65 74 53 74 61 72 74 75 70 49 6E : ....GetS tartupIn
1770: 66 6F 41 00 00 00 47 65 74 43 6F 6D 6D 61 6E 64 : foA...Ge tCommand
1780: 4C 69 6E 65 41 00 00 00 46 72 65 65 4C 69 62 72 : LineA... FreeLibr
1790: 61 72 79 00 00 00 45 78 69 74 50 72 6F 63 65 73 : ary...Ex itProces
17A0: 73 00 00 00 57 72 69 74 65 46 69 6C 65 00 00 00 : s...Writ eFile...
17B0: 55 6E 68 61 6E 64 6C 65 64 45 78 63 65 70 74 69 : Unhandle dExcepti
17C0: 6F 6E 46 69 6C 74 65 72 00 00 00 00 52 74 6C 55 : onFilter ....RtlU
17D0: 6E 77 69 6E 64 00 00 00 52 61 69 73 65 45 78 63 : nwind... RaiseExc
17E0: 65 70 74 69 6F 6E 00 00 00 00 47 65 74 53 74 64 : eption.. ..GetStd
17F0: 48 61 6E 64 6C 65 00 00
75 73 65 72 33 32 2E 64 : Handle.. user32.d
1800: 6C 6C 00 00 00 00 47 65 74 4B 65 79 62 6F 61 72 : ll....Ge tKeyboar
1810: 64 54 79 70 65 00 00 00 4D 65 73 73 61 67 65 42 : dType... MessageB
1820: 6F 78 41 00
61 64 76 61 70 69 33 32 2E 64 6C 6C : oxA.adva pi32.dll
1830: 00 00 00 00 52 65 67 51 75 65 72 79 56 61 6C 75 : ....RegQ ueryValu
1840: 65 45 78 41 00 00 00 00 52 65 67 4F 70 65 6E 4B : eExA.... RegOpenK
1850: 65 79 45 78 41 00 00 00 52 65 67 43 6C 6F 73 65 : eyExA... RegClose
1860: 4B 65 79 00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C : Key.kern el32.dll
1870: 00 00 00 00 54 6C 73 53 65 74 56 61 6C 75 65 00 : ....TlsS etValue.
1880: 00 00 54 6C 73 47 65 74 56 61 6C 75 65 00 00 00 : ..TlsGet Value...
1890: 54 6C 73 46 72 65 65 00 00 00 54 6C 73 41 6C 6C : TlsFree. ..TlsAll
18A0: 6F 63 00 00 00 00 4C 6F 63 61 6C 46 72 65 65 00 : oc....Lo calFree.
18B0: 00 00 4C 6F 63 61 6C 41 6C 6C 6F 63 00 00 00 00 : ..LocalA lloc....
...ooo...
.eData (exported function section)
1A00: 00 00 00 00 00 00 00 00 00 00 00 00 3C 50 00 00 : ........ .....P..
1A10: 01 00 00 00 02 00 00 00 02 00 00 00 28 50 00 00 : ........ ....(P..
1A20: 30 50 00 00 38 50 00 00
m_exported_address (f_min at $132C, f_max at $1368)
68 1F 00 00 2C 1F 00 00 : 0P..8P.. h...,...
m_exported_name
1A30: 4A 50 00 00 50 50 00 00 : JP..PP..
m_exported_index
00 00 01 00 ....
m_dll_name
64 5F 6D 69 d_mi
1A40: 6E 5F 6D 61 78 2E 64 6C 6C 00 : n_max.dl l.
m_exported_name_table
66 5F 6D 61 78 00 : f_max.
1A50: 66 5F 6D 69 6E 00 : f_min.
00 00 00 00 00 00 00 00 00 00 : .. ........
1A60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
...ooo...
1C00: 00 10 00 00 98 01 00 00 02 30 0A 30 12 30 1A 30 : ....... .0.0.0.0
1C10: 22 30 2A 30 32 30 3A 30 42 30 4A 30 52 30 5A 30 : "0*020:0 B0J0R0Z0
1C20: 62 30 6A 30 96 30 9E 30 A6 30 AE 30 B6 30 CA 30 : b0j000 0000
...ooo...
.rsrc (Resource Section
1E00: 00 00 00 00 13 41 39 36 00 00 00 00 00 00 01 00 : .....A96 ........
1E10: 0A 00 00 00 18 00 00 80
00 00 00 00 13 41 39 36 : ....... .....A96
1E20: 00 00 00 00 02 00 00 00 88 00 00 80 38 00 00 80 : ........ ..8..
1E30: 96 00 00 80 50 00 00 80
00 00 00 00 13 41 39 36 : ..P.. .....A96
1E40: 00 00 00 00 00 00 01 00 00 00 00 00 68 00 00 00 : ........ ....h...
1E50: 00 00 00 00 13 41 39 36 00 00 00 00 00 00 01 00 : .....A96 ........
1E60: 00 00 00 00 78 00 00 00
B0 70 00 00 10 00 00 00 : ....x... p......
1E70: 00 00 00 00 00 00 00 00
C0 70 00 00 2C 00 00 00 : ........ p..,...
1E80: 00 00 00 00 00 00 00 00
06 00 44 00 56 00 43 00 : ........ ..D.V.C.
1E90: 4C 00 41 00 4C 00 0B 00 50 00 41 00 43 00 4B 00 : L.A.L... P.A.C.K.
1EA0: 41 00 47 00 45 00 49 00 4E 00 46 00 4F 00 00 00 : A.G.E.I. N.F.O...
1EB0: 26 3D 4F 38 C2 82 37 B8 F3 24 42 03 17 9B 3A 83 : &=O87 $B..:
1EC0: 01 00 00 8C 00 00 00 00 03 00 00 00 01 F9 64 5F : ....... .....d_
1ED0: 6D 69 6E 5F 6D 61 78 00 00 81 53 79 73 49 6E 69 : min_max. .SysIni
1EE0: 74 00 00 C7 53 79 73 74 65 6D 00 00 00 00 00 00 : t..Syst em......
...ooo...
1FF0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
| The source, as well as the .DLL are downloadable
3.6 - Mini Howto Manual
We will illustrate the use of the PE Explorer using our previous .DLL:
4 - Download the EXE DLL Analyzer Sources
Here are the source code files: The .ZIP file(s) contain: - the main program (.DPR, .DOF, .RES), the main form (.PAS, .DFM), and any other auxiliary form
- any .TXT for parameters, samples, test data
- all units (.PAS) for units
Those .ZIP - are self-contained: you will not need any other product (unless expressly mentioned).
- for Delphi 6 projects, can be used from any folder (the pathes are RELATIVE)
- will not modify your PC in any way beyond the path where you placed the .ZIP (no registry changes, no path creation etc).
To use the .ZIP:
- create or select any folder of your choice
- unzip the downloaded file
- using Delphi, compile and execute
To remove the .ZIP simply delete the folder.
The Pascal code uses the Alsacian notation, which prefixes identifier by program area: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lass etc. This notation is presented in the Alsacian Notation paper.
As usual:
- please tell us at fcolibri@felix-colibri.com if you found some errors, mistakes, bugs, broken links or had some problem downloading the file. Resulting corrections will
be helpful for other readers
- we welcome any comment, criticism, enhancement, other sources or reference suggestion. Just send an e-mail to fcolibri@felix-colibri.com.
- or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button
- and if you liked this article, talk about this site to your fellow developpers, add a link to your links page ou mention our articles in your blog or newsgroup posts when relevant. That's the way we operate:
the more traffic and Google references we get, the more articles we will write.
5 - References - Matt PIETRECK:
- "Windows 95 System Programming Secrets"
IDG Books - Isbn 1 56884 318 6
The best book on this topic - An In-Depth look into the Win32 Portable Executable File Format
MSJ - Feb 2002
- An In-Depth look into the Win32 Portable Executable File Format, Part 2
MSJ - March 2002 - Jeffrey RICHTER
6 - The author
Felix John COLIBRI works at the Pascal Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly
active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi
Xe_n migrations, refactoring), Delphi Consulting and Delph
training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP / UML, Design Patterns, Unit Testing training sessions. |