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

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

By , 11 Dec 2008
Rate this:
Please Sign up or sign in to vote.

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 the CXPEInfo 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 the CXPEInfoTest functions. Here is what demo app looks like:

screenshot

Step 3 - the HDPEInfo Utility

Using CXPEInfoTest 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:

screenshot

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 hdsample
and 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

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.

License

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

About the Author

Hans Dietrich
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.
 
Recently, I have moved to Los Angeles where I am doing consulting and development work.
 
For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions

 
GeneralUhm Good to read Pinmemberbunneyxxx7-Mar-11 13:03 
AnswerRe: Uhm Good to read PinmentorHans Dietrich15-Apr-11 3:45 
GeneralMy vote of 2 PinmemberTomas Rapkauskas18-Dec-08 5:57 
GeneralGreat Work! PinmemberRichard Andrew x6411-Dec-08 9:05 

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
Web02 | 2.8.140415.2 | Last Updated 11 Dec 2008
Article Copyright 2008 by Hans Dietrich
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid