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:
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;
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);
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 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
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.