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

A Number of Reusable PE File Format Scanning Functions

, 5 May 2010
Rate this:
Please Sign up or sign in to vote.
Useful functions to retrieve information from PE files

Introduction

This article accompanies a number of command line sample applications that wrap some common code of mine. This common code can be used to extract various information from PE format files (PE format stands for Portable Executable Format). The four samples are named bitness, pefileuses, dotnetsearch and pdbget.

bitness expects a file name as the command line parameter and will tell you if the file passed as an argument is a 32 bit or a 64 bit PE file. It wraps the following common code functions:

BOOL IsFile64BitPEFileW(LPCWSTR szFile, PBOOL pbIs64Bits);
BOOL IsFile64BitPEFileA(LPCSTR szFile, PBOOL pbIs64Bits);

The parameters should be pretty self-explanatory. If the function succeeds, it returns a non-zero value. If it fails, the return value is FALSE and extended error information is available via GetLastError. In case of success, the out-Parameter pbIs64Bits will contain a non-zero value if the PE file passed as parameter szFile is 64 bits.

pefileuses is meant to determine if a given PE file links against a certain DLL or uses a function from a given DLL. It expects 3 command line parameters and optionally a fourth parameter. The first parameter is a number between zero and 2. This number determines whether the import table or the table for delayloaded functions should be scanned or both. Passing "0" means, both tables are scanned. Passing "1" means, only the import table, passing "2" means, only the table for delayloads are scanned. The second parameter is the PE file to be scanned. The third parameter denotes the DLL name that the tables should be scanned for. Finally the fourth parameter is an optional function name. The application will print on stdout whether or not the specified binary links against the given DLL or even uses the optional function name. This tool wraps the following common code functions:

BOOL __stdcall PeFileUsesImportA(LPCSTR szPeFile, LPCSTR szDllName, 
                                 LPCSTR szFunction, 
                                 PBOOL pbUse, DWORD dwFlags);
BOOL __stdcall PeFileUsesImportW(LPCWSTR szPeFile, LPCWSTR szDllName, 
                                 LPCWSTR szFunction, PBOOL pbUse, 
                                 DWORD dwFlags);

The flags to be passed for this function are those that are passed as the first parameter to pefiluses.exe and are defined as such:

#define PUI_USE_IMPORT_ONLY    0x1
#define PUI_USE_DELAYLOAD_ONLY 0x2

Passing 0L as the dwFlags parameter scans both tables as described above. The other parameters should be pretty self-explanatory. If the function succeeds, it returns a non-zero value. If it fails, the return value is FALSE and extended error information is available via GetLastError.

dotnetsearch is a tool to scan an entire directory tree and evaluate each DLL and EXE file found, whether it is a .NET binary. I wrote this tool in order to look at each new build of Windows Vista and to find out how many files on the entire Vista harddisk use the .NET-Framework. A binary that uses the .NET-Framework can be easily identified as it links against mscoree.dll. The dotnetsearch tool wraps the following common code functions:

BOOL __stdcall BinaryUsesDotNetA(LPCSTR szFileName, PBOOL pbUse);
BOOL __stdcall BinaryUsesDotNetW(LPCWSTR szFileName, PBOOL pbUse);

Again, the parameters should be pretty self-explanatory. If the function succeeds, it returns a non-zero value. If it fails, the return value is FALSE and extended error information is available via GetLastError;.

pdbget examines a given PE file for the location of its debugging information. Nowadays, if you use Microsoft compilers, CodeView debugging information is located in PDB files. In order for the debugger to find the PDB file for a given PE file, its file path is embedded within the PE file as an ANSI string. The pdbget sample application expects the path to the PE file to be examined as a command line parameter and will print the location of the associated pdb file on stdout. The location of debugging information in the two formats PDB 2.0 (VC 6) and PDB 7.0 (Visual Studio .NET and later) are properly detected and this tool wraps the following common code functions:

BOOL __stdcall GetPDBFileA(LPCSTR szPeFile, LPSTR szPdbFile, PDWORD pdwSize);
BOOL __stdcall GetPDBFileW(LPCWSTR szPeFile, LPWSTR szPdbFile, PDWORD pdwSize);

The first parameter to these functions is the path to the PE file to be examined. The second parameter is an optional parameter to the memory buffer, where the function will write the path of the PDB file as a null terminated string. The third parameter is the size of the memory buffer in characters and is acting as an in/out parameter. The memory buffer has to be allocated by the caller but NULL can be specified as the szPdbFile parameter, in which case only the required size is written to pdwSize. This way you can first call the functions with NULL as the second parameter and allocate the required memory with the size that has been retrieved via the third parameter. Using this allocated memory, you can then call the functions a second time to retrieve the path to the PDB file.

If the function succeeds, it returns a non-zero value. If it fails, the return value is FALSE and extended error information is available via GetLastError.

Using the Code

The code compiles cleanly in both UNICODE and ANSI builds and for x86 and x64 targets on Visual Studio 2005. You can also use Visual Studio 2008 and convert the project and solution files into its newer format.

Kudos

The functions that I am using in this common code of mine are mostly stolen from Matt Pietrek and a sample that came with an MSDN magazine article. All I did was to separate the functionality a bit better into reusable chunks, remove the globals that were used throughout the original code and reorganize things a bit better for proper usage in x86 and x64 builds and with the latest header files. If anything works well for you using this code, it is the sole merit of Matt Pietrek, if the code fails or breaks, it is my fault. The information about the CodeView 2.0 debugging information in PE files comes from an article from the fine folks of debuginfo.com.

History

  • 1st version: 07/30/2006: Initial version
  • 2nd version: 04/13/2010: Removed the VC6 support, added pdbget
  • 3rd version: 05/05/2010: The GetPDBFile function now determines the PDB location from x64 binaries as well, PeFileUsesImportW doesn't convert the PE file parameter to MBCS anymore

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Stefan Kuhr
Software Developer
Germany Germany
Stefan has been writing programs in C/C++ since 1991, and for Windows since 1993. He holds a German engineer's degree Dipl.-Ing. (FH) in "Microelectronics/Technical Computer Science" from the Aalen (Germany) University of Applied Sciences and an MSc in "Software Technology" from the Stuttgart (Germany) University of Applied Sciences. Currently, he is employed by a software company in the south-west of Germany that specializes in PC life-cycle products and software deployment technology. In his spare time, Stefan likes to go swimming and enjoys listening to jazz music from the fifties. And yes, he has a Weblog at http://mcblogs.craalse.de/sku (German only).

Comments and Discussions

 
GeneralPeParser Library Pinmembermarc ochsenmeier11-May-10 5:32 
GeneralSimple Approach PinmemberIzzet Kerem Kusmezer15-Apr-10 3:44 
Generalquestion PinmemberSkizmo31-Jul-06 21:25 
GeneralRe: question PinmemberLeo Davidson1-Aug-06 0:45 
GeneralRe: question PinmemberSkizmo1-Aug-06 0:46 
GeneralRe: question PinmemberGrazM8-Aug-06 4:04 
GeneralRe: question PinmemberJohnWallis4214-Apr-10 14:24 
GeneralRe: question PinmemberJohnWallis4214-Apr-10 14:30 
GeneralRe: question PinmemberJohnWallis4214-Apr-10 14:34 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 5 May 2010
Article Copyright 2006 by Stefan Kuhr
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid