如何判斷PE檔案合法,主要就是兩個地方,頭為"MZ"簽名,跟著DOS頭部的就是"PE"簽名,任何標準的PE檔案都會包含這兩個簽名。如下這段代碼所示,這是一個判斷是否為合法PE檔案的API。
通過檔案對應實現PE檔案內容的讀取。
BOOL IsValidPEFile( CString strPathName ){ if ( ! PathFileExists( strPathName ) ) return FALSE; HANDLE hFile = CreateFile( strPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { TRACE1( "Failed To Open File %s !/n", strPathName ); return FALSE; } HANDLE hMMFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); if ( hMMFile == INVALID_HANDLE_VALUE ) { CloseHandle( hFile ); return FALSE; } LPVOID pvMem = MapViewOfFile( hMMFile, FILE_MAP_READ, 0, 0, 0 ); if ( ! pvMem ) { CloseHandle( hMMFile ); CloseHandle( hFile ); return FALSE; } if ( *( USHORT* ) pvMem != IMAGE_DOS_SIGNATURE ) { UnmapViewOfFile( pvMem ); CloseHandle( hMMFile ); CloseHandle( hFile ); return FALSE; } if ( *( ( DWORD* ) ( ( PBYTE ) pvMem + ( ( PIMAGE_DOS_HEADER ) pvMem )->e_lfanew ) ) != IMAGE_NT_SIGNATURE ) { UnmapViewOfFile( pvMem ); CloseHandle( hMMFile ); CloseHandle( hFile ); return FALSE; } UnmapViewOfFile( pvMem ); CloseHandle( hMMFile ); CloseHandle( hFile ); return TRUE;}這段代碼實現了對PE檔案合法性的判斷。
但是,我還希望對應用程式的類型作一個更加徹底的判斷,如何知道應用程式是基於視窗形式的還是基於命令列形式的程式呢?
其實PE檔案中早已經包含了這種程式類型的標誌!這個標誌包含在PE檔案的頭部IMAGE_NT_HEADER的結構中的 IMAGE_OPTIONAL_HEADER的Sybsystem記錄! 看看"winnt.h"中對Sybsystem的宏定義。
#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem.#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character System#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image runs in the Posix character subsystem.#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Image runs in the Windows CE subsystem.
通過這些定議則可以輕易的判斷應用程式是何種形式的,當Subsystem的值為IMAGE_SUBSYSTEM_WINDOWS_GUI的時候,則可以確定這個程式是基於圖形介面的,當它的值為IMAGE_SUBSYSTEM_WINDOWS_CUI的時候可以確定它為命令列的程式了。 核心的代碼如下:
BOOL IsWindowsApp( CString strPathName )
{
if ( ! PathFileExists( strPathName ) )
return FALSE;
// 根據 PE 簽名判斷當前檔案是否合法的 可攜式執行檔
HANDLE hFile = CreateFile( strPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile == INVALID_HANDLE_VALUE ) {
TRACE1( "Failed To Open File %s !/n", strPathName );
return FALSE;
}
HANDLE hMMFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
if ( hMMFile == INVALID_HANDLE_VALUE ) {
CloseHandle( hFile );
return FALSE;
}
LPVOID pvMem = MapViewOfFile( hMMFile, FILE_MAP_READ, 0, 0, 0 );
if ( ! pvMem ) {
CloseHandle( hMMFile );
CloseHandle( hFile );
return FALSE;
}
// 是否包含有 DOS 簽名
if ( *( USHORT* ) pvMem != IMAGE_DOS_SIGNATURE ) {
UnmapViewOfFile( pvMem );
CloseHandle( hMMFile );
CloseHandle( hFile );
return FALSE;
}
// 是否包含有 NT 簽名
if ( *( ( DWORD* ) ( ( PBYTE ) pvMem + ( ( PIMAGE_DOS_HEADER ) pvMem )->e_lfanew ) ) != IMAGE_NT_SIGNATURE ) {
UnmapViewOfFile( pvMem );
CloseHandle( hMMFile );
CloseHandle( hFile );
return FALSE;
}
LPVOID pvOptionalHeader = ( PBYTE ) pvMem + ( ( PIMAGE_DOS_HEADER ) pvMem )->e_lfanew + sizeof( DWORD ) + sizeof( IMAGE_FILE_HEADER );
IMAGE_OPTIONAL_HEADER ioh;
CopyMemory( & ioh, pvOptionalHeader, sizeof( IMAGE_OPTIONAL_HEADER ) );
if ( ioh.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ) {
UnmapViewOfFile( pvMem );
CloseHandle( hMMFile );
CloseHandle( hFile ); return TRUE;
}
return FALSE;
}
BOOL IsCosoleApp( CString strPathName )
{
if ( ! PathFileExists( strPathName ) )
return FALSE;
// 根據 PE 簽名判斷當前檔案是否合法的 可攜式執行檔
HANDLE hFile = CreateFile( strPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile == INVALID_HANDLE_VALUE ) {
TRACE1( "Failed To Open File %s !/n", strPathName );
return FALSE;
}
HANDLE hMMFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
if ( hMMFile == INVALID_HANDLE_VALUE ) {
CloseHandle( hFile );
return FALSE;
}
LPVOID pvMem = MapViewOfFile( hMMFile, FILE_MAP_READ, 0, 0, 0 );
if ( ! pvMem ) {
CloseHandle( hMMFile );
CloseHandle( hFile );
return FALSE;
}
// 是否包含有 DOS 簽名
if ( *( USHORT* ) pvMem != IMAGE_DOS_SIGNATURE ) {
UnmapViewOfFile( pvMem );
CloseHandle( hMMFile );
CloseHandle( hFile );
return FALSE;
}
// 是否包含有 NT 簽名
if ( *( ( DWORD* ) ( ( PBYTE ) pvMem + ( ( PIMAGE_DOS_HEADER ) pvMem )->e_lfanew ) ) != IMAGE_NT_SIGNATURE ) {
UnmapViewOfFile( pvMem );
CloseHandle( hMMFile );
CloseHandle( hFile );
return FALSE;
}
LPVOID pvOptionalHeader = ( PBYTE ) pvMem + ( ( PIMAGE_DOS_HEADER ) pvMem )->e_lfanew + sizeof( DWORD ) + sizeof( IMAGE_FILE_HEADER );
IMAGE_OPTIONAL_HEADER ioh;
CopyMemory( & ioh, pvOptionalHeader, sizeof( IMAGE_OPTIONAL_HEADER ) );
if ( ioh.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI ) {
UnmapViewOfFile( pvMem );
CloseHandle( hMMFile );
CloseHandle( hFile ); return TRUE;
}
return FALSE;
}