menu
  Home  ==>  papers  ==>  colibri_utilities  ==>  exe_dll_pe_explorer   

.EXE / .DLL PE Explorer - Felix John COLIBRI.


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:

  • the disc and memory structure are the same. Whether you analyze the file (by loading the .EXE or .DLL into a buffer) or analyze the memory content, you can use the same record definitions.

    Maybe all elements have not the same size, and not the same offsets between each other, but the relative positions are the same.

  • to load a .DLL, we usually call
      my_handle:= LoadLibrary('dll_name')
    and the handle is the memory address of the loaded code. So using this handle, we can analyze the in-memory code, in the same way as we analyze the disc file
  • not all parts of the file are mapped into memory (they can be read by the loader, used to compute or recompute other parts, but are thrown away after loading the module)
  • the PE is made of tables and data. The tables are used to find the position and size of the data.
    To locate the different parts, the PE uses relative addresses. In PE language, those are called RVAs: (Relative Virtual Address). An RVA is an address relative to the memory load address. The actual memory address is called Virtual Address
  • The data parts are called sections:
    • the section have names, which are not significative (they can have any name). However there are some commonly used names, like
      • .text or CODE for x86 binary code
      • .idata for lists of imported .DLLs with their imported functions
      • .edata for the .DLL exported functions
      • .rsrc for the Windows Resources
    • Microsoft uses ".text", while Borland used "CODE" and "DATA"


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:

image



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_headerRecord
               m_nt_signaturedWord;
               m_nt_file_headert_nt_file_header;
               m_nt_optional_headert_nt_optional_header;
               m_nt_section_directoryt_nt_section_directory;
             end// t_nt_header

with the following figure:

image



2.4.1 - The File Header

Here is the definition

t_nt_file_headerpacked record
                    MachineWord;
                    m_number_of_sectionsWord;
                    TimeDateStampdWord;
                    PointerToSymbolTabledWord;
                    NumberOfSymbolsdWord;
                    SizeOfOptionalHeaderWord;
                    CharacteristicsWord;
                  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_headerpacked record
                        // -- Standard fields.
                        MagicWord;
                        MajorLinkerVersionByte;
                        MinorLinkerVersionByte;
                        SizeOfCodedWord;
                        SizeOfInitializedDatadWord;
                        SizeOfUninitializedDatadWord;
                        AddressOfEntryPointdWord;
                        BaseOfCodedWord;
                        BaseOfDatadWord;
                        // --Nt additional fields
                        ImageBasedWord;
                        SectionAlignmentdWord;
                        FileAlignmentdWord;
                        MajorOperatingSystemVersionWord;
                        MinorOperatingSystemVersionWord;
                        MajorImageVersionWord;
                        MinorImageVersionWord;
                        MajorSubsystemVersionWord;
                        MinorSubsystemVersionWord;
                        Win32VersionValuedWord;
                        SizeOfImagedWord;
                        SizeOfHeadersdWord;
                        CheckSumdWord;
                        SubsystemWord;
                        DllCharacteristicsWord;
                        SizeOfStackReservedWord;
                        SizeOfStackCommitdWord;
                        SizeOfHeapReservedWord;
                        SizeOfHeapCommitdWord;
                        LoaderFlagsdWord;
                        m_section_entry_countdWord;
                     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_entryrecord
                   m_section_relative_virtual_addressdWord;
                   m_section_sizedWord;
                 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:

image



Each section header is defined by:

const k_section_name_max= 8;
type t_section_address_and_sizepacked record
                        case Integer of
                          0: (m_section_physical_addressdWord);
                          1: (m_section_virtual_sizedWord);
                      end// t_section_address_and_size
     t_section_headerpacked record
                         m_namepacked array[0..k_section_name_max- 1] of Byte;
                         m_address_and_sizet_section_address_and_size;
                         m_virtual_addressdWord;

                         m_size_of_raw_datadWord;
                         m_pointer_to_raw_datadWord;

                         m_pointer_to_relocationsdWord;
                         PointerToLinenumbersdWord;
                         NumberOfRelocationsWord;
                         NumberOfLinenumbersWord;
                         CharacteristicsdWord;
                       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_modulerecord
                     // -- INT: Import Name table
                     m_pt_first_function_originalt_pt_imported_function;
                     m_import_timestampdWord;
                     m_import_forwarder_chaindWord;
                     m_imported_module_name_rvadWord;

                     // -- IAT: Import Address Table
                     m_pt_first_functiont_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_hintWord;
      m_import_nameByte;
    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_addresspdWord);
        3: (m_function_indexdWord);
        4: (m_pt_imported_by_name_functiont_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

image

or with more detail

image



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_functionsrecord
                        CharacteristicsdWord;
                        TimeDateStampdWord;
                        MajorVersionWord;
                        MinorVersionWord;

                        m_dll_name_rvadWord;
                        m_export_start_indexdWord;
                        m_exported_function_countdWord;
                        m_exported_name_countdWord;
                        // -- export Address Table (EAT)
                        m_exported_function_addressPdword;
                        // -- export name table (ENT)
                        m_exported_function_name_addresspdWord;
                        m_exported_function_index_addresspdWord;
                      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:

image



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_directorypacked record
                        CharacteristicsDWORD;
                        TimeDateStampDWORD;
                        MajorVersionWORD;
                        MinorVersionWORD;

                        m_name_entry_countWORD;
                        m_id_entry_countWORD;
                      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_entrypacked record
                    m_name_or_idDWORD;
                    m_offset_to_dataDWORD;
                  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_entrypacked record
                         m_data_offset_to_dataDWORD;
                         m_data_sizeDWORD;
                         m_data_code_pageDWORD;
                         ReservedDWORD;
                       end// t_resource_data_entry



This traditional recursive structure can then be displayed like this

image




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_peClass(tComponent)
        private
        public
          m_file_nameString;
          m_is_file_exeBoolean;

          m_file_handletHandle;
          m_mapping_handletHandle;
          m_base_addressdWord;

          m_c_display_stringstStrings;

          constructor Create(p_file_nameStringp_c_stringstStrings);

          procedure display_pe(p_textString);
          function f_display_address(p_ptPointer): String;
          procedure display_address_and_text(p_ptPointerp_textString);

          function f_pt_nt_headert_pt_nt_header;
          function f_pt_section_header(p_sectiondWord): t_pt_section_header;
          function f_pt_section_by_name_header(p_pt_section_name_zpChar):
              t_pt_section_header;
          function f_pt_enclosing_header_section(p_enclosed_addressdWord):
              t_pt_section_header;

          function f_pt_imported_module(p_dll_indexdWord;
              var pv_delta_mappingdWord): t_pt_imported_module;
          function f_pt_exports_directory(var pv_delta_mapping,
              pv_start_addresspv_end_addressdWord): t_pt_exported_functions;
          function f_pt_buffer(p_addressInteger): t_pt_bytes;
          function f_pt_word(p_addressInteger): 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_stringlisttStrings);
          procedure analyze_imported_functions(p_dll_nameStringp_c_stringstStrings;
              p_borlandString);
          function f_pt_imported_function_address(p_dll_namep_function_nameString): 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_nameStringp_c_stringstStrings);
  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_ReadFile_Share_Readk_security_nil,
              Open_ExistingFile_Attribute_Normalk_template_0);

          // -- create a mapping
          m_mapping_handle:= CreateFileMapping(m_file_handle,
              k_security_nilPage_ReadOnlyk_high_max_0k_low_max_0,
              k_name_nil);

          // -- create a view
          m_base_address:= dWord(MapViewOfFile(m_mapping_handleFile_Map_Read,
              k_high_offset_0k_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_headert_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

image

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_integerInteger;

  function f_min(p_onep_twoInteger): Integerstdcall;
    var l_localInteger;
    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_onep_twoInteger): Integerstdcall;
    var l_localInteger;
    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 : &=O8‚7 $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:
   compile the project
   the main form is displayed

image

   select the "dir" tab, and with the Directory/File listboxes, select target .EXE or .PE
   to visualize the different parts separately, select the "analyze tab" and click the button to display some PE part. For instance, click "Section Headers"
   this part is displayed

image

   to visualize the tree view, select the "tree_view" tab, an click "tree_view"
   the tree view is displayed. Here you can see the imported functions from User32.Dll:

image




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
    Name :
    E-mail :
    Comments * :
     

  • 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.
Created: jan-07. Last updated: jul-15 - 98 articles, 131 .ZIP sources, 1012 figures
Copyright © Felix J. Colibri   http://www.felix-colibri.com 2004 - 2015. All rigths reserved
Back:    Home  Papers  Training  Delphi developments  Links  Download
the Pascal Institute

Felix J COLIBRI

+ Home
  + articles_with_sources
    + database
    + web_internet_sockets
    + oop_components
    + uml_design_patterns
    + debug_and_test
    + graphic
    + controls
    + colibri_utilities
      – delphi_net_bdsproj
      – dccil_bat_generator
      – coliget_search_engine
      – dfm_parser
      – dfm_binary_to_text
      – component_to_code
      – exe_dll_pe_explorer
      – dll_process_viewer
      – the_alsacian_notation
      – html_help_viewer
      – cooking_the_code
      – events_record_playback
    + colibri_helpers
    + delphi
    + firemonkey
    + compilers
  + delphi_training
  + delphi_developments
  + sweet_home
  – download_zip_sources
  + links
Contacts
Site Map
– search :

RSS feed  
Blog