Click here to Skip to main content
Click here to Skip to main content

Parse a PE (EXE, DLL, OCX Files ) and New Dependency Walker

By , 28 May 2012
 

Introduction

I am introducing a new dependency walker, with a new look, but my target is not to introduce a dependency walker in front of you, but rather to make you familiar with PE (Portable Executable) format. I hope all of you have heard about PE, it is nothing but our Windows Executable (EXE, DLL, OCX, etc.) which is actually inherited from COFF (Common Object File Format), which was used for object file and executable in UNIX.

With this article, I make you familiar with coding making your own dependency walker, so that you can customize and make your own dependency walker. More than that, you can learn about PE, and how to parse a PE file with simplicity. To explain more, I am attaching an application and source code named ExeInside.

Background

The term "Portable Executable" was chosen because the intent was to have a common file format for all versions of Windows, on all supported CPUs. To a large extent, this goal has been achieved with the same format used on Windows NT and descendants, Windows 95 and descendants, and Windows CE.

To get familiar with PE format, firstly get familiar with some of the data structures, which are used to manage the data inside an executable in Windows.

  • PE Headers
  • PE Sections
  • Imports
  • Exports
  • Resources
  • Closing

Using the Code

Before compling the code, make sure that you have Microsoft Platform SDK installed properly. Current project is made for Visual Studio 6.0, but can be converted to later versions.

All the structures mentioned below are defined in WINNT.h file. Since PE file is basically starts withMS DOS header MZ header, to get further knowledge like import and export headers, you need to parse further based on the offset so that you can even get DEBUG information.

Let me introduce the data structures commonly used for coding with PE file format:

I am only explaining some of the data structures, if you need more information, you can refer to MSDN.

IMAGE_DOS_HEADER: Data structure holds the header of DOS, or simply the starting address from which we can take reference to get the content of a PE file.

IMAGE_OPTIONAL_HEADER: The data structure holds the import and export address, it holds the starting address for import and export based on the offset.

_IMAGE_EXPORT_DIRECTORY: This data structure holds the export address, based on this address we can get the exported functions of PE file.

IMAGE_IMPORT_DESCRIPTOR: This data structure holds the import address, based on this address we can get the imported functions of PE file.

Examples are illustrated below:

// This code loads a Module (say a DLL) and its start address 
// is given as the base address of the DOS header.
HMODULE hMod;
hMod = LoadLibrary( lpctszModName_i )
IMAGE_DOS_HEADER* IDH = (IMAGE_DOS_HEADER*)hMod;

// This code get the optional header from DOS 
// header based on the offset from DOS header.
IMAGE_OPTIONAL_HEADER* IOH = 
        (IMAGE_OPTIONAL_HEADER*)((BYTE*)hMod + IDH->e_lfanew + 24);
 
// This code gets the import descriptor from the base 
// address by taking the offset of start address and address of       
// IMAGE_DIRECTORY_ENTRY_IMPORT, after getting IMAGE_IMPORT_DESCRIPTOR, 
// you can get the imported functions or ordinals.
IMAGE_IMPORT_DESCRIPTOR* IID = 
       (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hMod + 
IOH->DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
 
// Same as above code below will give the Export information.
_IMAGE_EXPORT_DIRECTORY* pExportDescriptor = 
               (_IMAGE_EXPORT_DIRECTORY*)((BYTE*)hMod + 
  IOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

Points of Interest

I am giving you a small example with an implementation that will surely help you understand how our dependency walker may have been coded, but never compare with it, just a overview. I cannot compare my code with the Mark E. Russinovich. Leave those things, this is my first article, and I will surely write a lot of articles only if it is helpful to you. If it is not worthy or if you have any suggestions, then please inform me. I am planning for more topics, if my lord allows me to write it.

History

This ExeInside Beta is an application written just to understand how a dependency walker works, and still I am trying to improve it more effectively, I will never say it's fully bug free, yet it tested up to some extent and it has some additional functionality like, you can specify a PE file (EXE, DLL, OCX) and specify a directory, it will search which PE files have dependency with the specified PE file.

Well I am expecting your cooperation to make it more better than ever.

For more information, go and understand the below link for study purpose http://www.skynet.ie/~caolan/pub/winresdump/winresdump/doc/pefile.html

History

  • 2nd June, 2009: Initial post
  • 29th May, 2012: Minor corrections.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

About the Author

Adam Roderick J
Software Developer (Senior) Philips
Russian Federation Russian Federation
Member
"Great works are performed, not by strength, but by perseverance."

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionan error is found when compile the codememberjoshua013730 May '12 - 23:02 
exe_inside\Exe Inside\PEFormatParser.cpp(94) : error C2110: cannot add two pointers
AnswerRe: an error is found when compile the codememberAdam Roderick J4 Jun '12 - 0:35 
It is due to absence of platform SDK or It is not given in VC++ directories Include.
Величие не Бога может быть недооценена.

GeneralMy vote of 3memberYaroslav.Liulko29 May '12 - 6:06 
Unknown archive !
General[My vote of 2] to much hard coded..membermarc ochsenmeier5 May '10 - 4:29 
Hi Adam,
 
in order to browse the table of exported functions names, you don't even use the 'AddressOfNames' pointer existing in the IMAGE_EXPORT_DIRECTORY structure.
The way you retrieve these is really hard coded...
 
You should instead retrieve all exported symbols using the existing IMAGE_EXPORT_DIRECTORY pointers.
 
Bests,
Marc
GeneralMy vote of 2membermarc ochsenmeier5 May '10 - 4:25 
to much hard coded.
GeneralCrash with some dlls (with bug fix)memberregnier11 Jun '09 - 2:11 
Before all congratulation for your great work.
I just have found a small issue that crash the application with some dlls (eg mfc90d.dll) in PEFormatParser::GetImportAndExportData at the line csFunctioname = szFunctionName2;
 
I have investigate on it and for resolving the problem you have to add following test when you try to retreive the ordinal and the name of function :
if ((ITD->u1.Function &  IMAGE_ORDINAL_FLAG32)==0)
{
--> your management
}
else
{ // the ordinal can be retreive like this 
csOrdinal.Format( "%d(0X%x)", IMAGE_ORDINAL32(ITD->u1.Ordinal), IMAGE_ORDINAL32(ITD->u1.Ordinal));
}
With this correction your application works perfectly.
You can also undecorate names with UnDecorateSymbolName function.
General[Message Deleted]memberAllah Rahim K J23 Jun '09 - 6:19 

GeneralRe: Crash with some dlls (with bug fix)memberEric Haddan29 Jun '09 - 14:33 
Once your article is out of the unedited category, you must follow these instructions to update your article: http://www.codeproject.com/info/Submit.aspx#Update[^]
GeneralMissing things compared to MS Dependency WalkermemberJoel Lucsy2 Jun '09 - 10:13 
Just to help you improve, there are a number of things that'd I'd need if I wanted to use this as opposed to Microsoft's version:
C++ unmangling
Delay loaded dlls
WinSxS support
 
--
Joel Lucsy

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 29 May 2012
Article Copyright 2009 by Adam Roderick J
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid