XPEInfo - a non-MFC class to get info from PE file






4.95/5 (20 votes)
The XPEInfo APIs allow you to extract information from a PE file. Included in the download is a Windows demo app, and a console app that tests whether a PE file is valid, whether it is 64-bit, contains debug info, is a .Net executable, or is signed. Sample cmd files are provided.
Introduction
Recently I needed to check whether an exe contained debug information. Of course, I could have used depends.exe to see if debug DLLs were being linked in, but I was trying to set up automatic build procedure for install script, and wanted to find a way to do it from command line. Surprisingly, I could find no utility that did this. I began thinking of other situations - checking for 64-bit builds, checking if exe was signed - and realized that a general-purpose command-line utility (aimed at use in batch file) would be very handy. But before I could write command-line utility, I first had to be able to get information from PE file, in a way that would be usable by the command-line utility.
Step 1 - the CXPEInfo Class
First let me credit Matt Pietrek's MSDN article (February and March, 2002) An In-Depth Look into the Win32 Portable Executable File Format. I based much of theCXPEInfo
class on this article.
Here are functions in CXPEInfo
:
Function | Description |
CXPEInfo(LPCTSTR lpszFile = NULL) | Constructor with optional file name |
DWORD CalculateChecksum() | Returns calculated checksum |
void Close() | Closes file |
DWORD GetCertificateInfo() | Returns number of certificates |
WORD GetCharacteristics() | Returns Characteristics bit flags |
TCHAR * GetCharacteristicString(WORD bitmask) | Returns Characteristics bit flag string description |
DWORD GetChecksum() | Returns checksum stored in file |
WORD GetDllCharacteristics() | Returns DLL Characteristics bit flags |
TCHAR * GetDllCharacteristicString(WORD bitmask) | Returns DLL Characteristics bit flag string description |
DWORD GetDotNetFlags() | Returns .Net bit flags |
TCHAR * GetDotNetFlagString(DWORD bitmask) | Returns .Net bit flag string description |
DWORD GetDotNetVersion() | Returns minor runtime version in low word, major runtime version in high word |
DWORD GetImageVersion() | Returns minor image version in low word, major image version in high word |
WORD GetMachineType() | Returns machine type |
CWTLString GetMachineTypeString() | Returns machine type string description |
DWORD GetRequiredOSVersion() | Returns minor required OS version in low word, major required OS version in high word |
WORD GetSubsystem() | Returns subsystem code |
CWTLString GetSubsystemString() | Returns subsystem string description |
DWORD GetSubsystemVersion() | Returns minor subsystem version in low word, major subsystem version in high word |
time_t GetTimeStamp() | Returns PE file timestamp |
TCHAR * GetTimeStampString() | Returns PE file timestamp, as returned by ctime() |
BOOL Is64Bit() | Returns TRUE if 64-bit PE file |
BOOL IsDebug() | Returns TRUE if PE file contains debug info |
BOOL IsDotNet() | Returns TRUE if .Net PE file |
BOOL IsOpen() | Returns TRUE if PE file open |
BOOL IsSigned() | Returns TRUE if PE file is signed |
BOOL IsValid() | Returns TRUE if PE file is valid |
BOOL Open(LPCTSTR lpszFile) | Opens PE file specified by lpszFile |
Step 2 - the XPEInfoTest Demo App
The demo app tests all theCXPEInfoTest
functions.
Here is what demo app looks like:
Step 3 - the HDPEInfo Utility
UsingCXPEInfoTest
class, it is simple to write
command-line utility that can be used in batch file.
Here is main()
function of HDPEInfo:
void _tmain(int argc, TCHAR *argv[]) { int rc = -1; //_tprintf(_T("argc=%d\n"), argc); TCHAR szMessage[1000]; if (argc < 2) { usage(); } else { if (ProcessCommandLine(argc, argv)) { if ((pszFile == NULL) || (_taccess(pszFile, 00) == -1)) { _stprintf(szMessage, _T("%s: ERROR: missing file name or file not accessible"), argv[0]); _tprintf(_T("%s\n"), szMessage); //::MessageBox(0, szMessage, _T("HDPEInfo"), MB_OK|MB_ICONWARNING); TRACE(_T("%s\n"), szMessage); } else if (pszFile) { CXPEInfo info(pszFile); if (b64bit) rc = info.Is64Bit() ? 1 : 0; else if (bDebug) rc = info.IsDebug() ? 1 : 0; else if (bDotNet) rc = info.IsDotNet() ? 1 : 0; else if (bSigned) rc = info.IsSigned() ? 1 : 0; else rc = info.IsValid() ? 1 : 0; } } } exit(rc); }
Using XGetopt() to parse command-line switches, here is what batch file run_all_samples.cmd looks like:
Here is source for run_all_samples.cmd:
@rem run_all_samples.cmd @echo off echo ===== exit code should be 1 ===== call hdsample /v hdpeinfo.exe echo ===== exit code should be 0 ===== call hdsample /6 hdpeinfo.exe echo ===== exit code should be 1 ===== call hdsample /6 test64.exe echo ===== exit code should be 1 ===== call hdsample /d testD.exe echo ===== exit code should be 0 ===== call hdsample /n hdpeinfo.exe echo ===== exit code should be 0 ===== call hdsample /s hdpeinfo.exe echo ===== exit code should be 1 ===== call hdsample /s test32.exe echo ===== exit code should be 0 ===== call hdsample test.obj echo ===== exit code should be 1 ===== call hdsample /n testcs.exe echo ===== exit code should be -1 ===== call hdsample /v echo ===== exit code should be 2 ===== call hdsampleand for hdsample.cmd:
@rem hdsample.cmd @echo off hdpeinfo %1 %2 echo hdpeinfo %1 %2: exit code = %ERRORLEVEL% if %ERRORLEVEL% == -1 goto badargs if %ERRORLEVEL% == 0 goto false if %ERRORLEVEL% == 1 goto true if %ERRORLEVEL% == 2 goto end goto unknown :badargs echo bad args goto end :false echo exit code 0 goto end :true echo exit code 1 goto end :unknown echo unknown exit code %ERRORLEVEL% goto end :end
The above batch files and test files are included in download, in directory console app\vs6\bin and console app\vs2005\bin.
How To Use
To integrate CXPEInfoTest
into your own program, you first need
to add following files to your project:
- XPEInfo.cpp
- XPEInfo.h
- wtlstring.h (if MFC is not used)
If you do not include stdafx.h in XPEInfo.cpp, then you must mark XPEInfo.cpp as not using precompiled headers in the project settings.
Next, include the header file XPEInfo.h in the module where you want to call XPEInfo functions. For an example, see XPEInfoTestDlg.cpp in the demo project.
References
- Microsoft Portable Executable and Common Object File Format Specification v8.0
- An In-Depth Look into the Win32 Portable Executable File Format
Revision History
Version 1.0 - 2008 December 11
- Initial public release
Usage
This software is released into the public domain. You are free to use
it in any way you like, except that you may not sell this source code.
If you modify it or extend it, please to consider posting new code here
for everyone to share. This software is provided "as is" with no expressed
or implied warranty. I accept no liability for any damage or loss of
business that this software may cause.