How to detect the types of executable files
How to detect the types of executable files
type { IMAGE_DOS_HEADER: DOS .EXE header. } IMAGE_DOS_HEADER = packed record e_magic : Word; // Magic number ("MZ") e_cblp : Word; // Bytes on last page of file e_cp : Word; // Pages in file e_crlc : Word; // Relocations e_cparhdr : Word; // Size of header in paragraphs e_minalloc: Word; // Minimum extra paragraphs needed e_maxalloc: Word; // Maximum extra paragraphs needed e_ss : Word; // Initial (relative) SS value e_sp : Word; // Initial SP value e_csum : Word; // Checksum e_ip : Word; // Initial IP value e_cs : Word; // Initial (relative) CS value e_lfarlc : Word; // Address of relocation table e_ovno : Word; // Overlay number e_res : packed array [0..3] of Word; // Reserved words e_oemid : Word; // OEM identifier (for e_oeminfo) e_oeminfo : Word; // OEM info; e_oemid specific e_res2 : packed array [0..9] of Word; // Reserved words e_lfanew : Longint; // File address of new exe header end; { TExeFileKind: The kinds of files recognised. } TExeFileKind = ( fkUnknown, // unknown file kind: not an executable fkError, // error file kind: used for files that don't exist fkDOS, // DOS executable fkExe32, // 32 bit executable fkExe16, // 16 bit executable fkDLL32, // 32 bit DLL fkDLL16, // 16 bit DLL fkVXD // virtual device driver ); function ExeType(const FileName: string): TExeFileKind; {Examines given file and returns a code that indicates the type of executable file it is (or if it isn't an executable)} const cDOSRelocOffset = $18; // offset of "pointer" to DOS relocation table cWinHeaderOffset = $3C; // offset of "pointer" to windows header in file cNEAppTypeOffset = $0D; // offset in NE windows header of app type field cDOSMagic = $5A4D; // magic number for a DOS executable cNEMagic = $454E; // magic number for a NE executable (Win 16) cPEMagic = $4550; // magic nunber for a PE executable (Win 32) cLEMagic = $454C; // magic number for a Virtual Device Driver cNEDLLFlag = $80 // flag in NE app type field indicating a DLL var FS: TFileStream; // stream to executable file WinMagic: Word; // word containing PE or NE magic numbers HdrOffset: LongInt; // offset of windows header in exec file ImgHdrPE: IMAGE_FILE_HEADER; // PE file header record DOSHeader: IMAGE_DOS_HEADER; // DOS header AppFlagsNE: Byte; // byte defining DLLs in NE format DOSFileSize: Integer; // size of DOS file begin try // Open stream onto file: raises exception if can't be read FS := TFileStream.Create(FileName, fmOpenRead + fmShareDenyNone); try // Assume unkown file Result := fkUnknown; // Any exec file is at least size of DOS header long if FS.Size < SizeOf(DOSHeader) then Exit; FS.ReadBuffer(DOSHeader, SizeOf(DOSHeader)); // DOS files begin with "MZ" if DOSHeader.e_magic <> cDOSMagic then Exit; // DOS files have length >= size indicated at offset $02 and $04 // (offset $02 indicates length of file mod 512 and offset $04 // indicates no. of 512 pages in file) if (DOSHeader.e_cblp = 0) then DOSFileSize := DOSHeader.e_cp * 512 else DOSFileSize := (DOSHeader.e_cp - 1) * 512 + DOSHeader.e_cblp; if FS.Size < DOSFileSize then Exit; // DOS file relocation offset must be within DOS file size. if DOSHeader.e_lfarlc > DOSFileSize then Exit; // We assume we have an executable file: assume its a DOS program Result := fkDOS; // Try to find offset of Windows program header if FS.Size <= cWinHeaderOffset + SizeOf(LongInt) then // file too small for windows header "pointer": it's a DOS file Exit; // read it FS.Position := cWinHeaderOffset; FS.ReadBuffer(HdrOffset, SizeOf(LongInt)); // Now try to read first word of Windows program header if FS.Size <= HdrOffset + SizeOf(Word) then // file too small to contain header: it's a DOS file Exit; FS.Position := HdrOffset; // This word should be NE, PE or LE per file type: check which FS.ReadBuffer(WinMagic, SizeOf(Word)); case WinMagic of cPEMagic: begin // 32 bit Windows application: now check whether app or DLL if FS.Size < HdrOffset + SizeOf(LongWord) + SizeOf(ImgHdrPE) then // file not large enough for image header: assume DOS Exit; // read Windows image header FS.Position := HdrOffset + SizeOf(LongWord); FS.ReadBuffer(ImgHdrPE, SizeOf(ImgHdrPE)); if (ImgHdrPE.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then // characteristics indicate a 32 bit DLL Result := fkDLL32 else // characteristics indicate a 32 bit application Result := fkExe32; end; cNEMagic: begin // We have 16 bit Windows executable: check whether app or DLL if FS.Size <= HdrOffset + cNEAppTypeOffset + SizeOf(AppFlagsNE) then // app flags field would be beyond EOF: assume DOS Exit; // read app flags byte FS.Position := HdrOffset + cNEAppTypeOffset; FS.ReadBuffer(AppFlagsNE, SizeOf(AppFlagsNE)); if (AppFlagsNE and cNEDLLFlag) = cNEDLLFlag then // app flags indicate DLL Result := fkDLL16 else // app flags indicate program Result := fkExe16; end; cLEMagic: // We have a Virtual Device Driver Result := fkVXD; else // DOS application {Do nothing - DOS result already set}; end; finally FS.Free; end; except // Exception raised in function => error result Result := fkError; end; end;