Skip to content

Instantly share code, notes, and snippets.

@CitizenInsane
Created April 16, 2021 08:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save CitizenInsane/079849d25d982239ba13dbbdeec8ce93 to your computer and use it in GitHub Desktop.
Save CitizenInsane/079849d25d982239ba13dbbdeec8ce93 to your computer and use it in GitHub Desktop.
Obtaining information about Portable Executable file (.exe, .dll)
%
% PURPOSE:
%
% Returns raw information about specified portable executable file.
%
% SYNTAX:
%
% [rawInfo] = GetPortableExecutableRawInfo(filename);
% [rawInfo, PEConstants] = GetPortableExecutableRawInfo(filename);
%
% DESCRIPTION:
%
% - '[rawInfo] = GetPortableExecutableRawInfo(filename)' return raw
% information in 'rawInfo' structure about specified portable
% executable 'filename'.
%
% INPUTS:
%
% - 'filename': Path to portable executable file.
%
% OUTPUTS:
%
% - 'rawInfo': Raw information structure about specified portable
% executable file. Not fully described here but this is just
% standard 'winnt.h'-structures of PE files.
%
% NB: If some 'winnt.h' structure is present no in the file, it will
% not be present in the outputs. Make sure to test for existence when
% later examining PE data.
%
% - 'PEConstants': Predefined PE constants to help testing PE values.
%
% SEE ALSO:
%
% - 'GetPortableExecutableSimplifiedInfo'
%
%% ---
function [rawInfo, PEConstants] = GetPortableExecutableRawInfo(filename)
%[
% Helper constants
PEConstants.IMAGE_FILE_MACHINE_ARM = hex2dec('1c4');
PEConstants.IMAGE_FILE_MACHINE_I386 = hex2dec('14c');
PEConstants.IMAGE_FILE_MACHINE_IA64 = hex2dec('200');
PEConstants.IMAGE_FILE_MACHINE_AMD64 = hex2dec('8664');
% Checking arguments
if (nargin <1), error('MATLAB:minrhs', 'Not enough input argments.'); end
if (~ischar(filename) || ~exist(filename, 'file')), error('Invalid argument: filename must be path to existing file.'); end
% Opening file
[fid, errmsg] = fopen(filename, 'rb');
if (fid < 0), error('Failed to open `%s`: %s', filename, errmsg); end
cuo = onCleanup(@()fclose(fid));
% Initializing error message
errmsg = sprintf('Invalid argument: `%s` does not seem to be portable executable file.', filename);
% Reading IMAGE_DOS_HEADER structure
% NB: Endianess is little-endian in file
[DOSHeader.e_magic, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[~, c] = fread(fid, 13+4+2+10, 'uint16'); if (c ~= (13+4+2+10)), error(errmsg); end %#ok<SPERR>
[DOSHeader.e_lfanew, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
if (DOSHeader.e_magic ~= 23117), error(errmsg); end %#ok<SPERR>
% Shift and read PE_SIGNATURE
% NB: Endianess is little-endian in file
c = fseek(fid, DOSHeader.e_lfanew, 'bof'); if (c ~= 0), error(errmsg); end %#ok<SPERR>
[pe_signature, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
if (pe_signature ~= 17744), error(errmsg); end %#ok<SPERR>
% Read IMAGE_FILE_HEADER
% NB: Endianess is little-endian in file
[COFFHeader.Machine, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COFFHeader.NumberOfSections, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COFFHeader.TimeDateStamp, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COFFHeader.PointerToSymbolTable, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COFFHeader.NumberOfSymbols, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COFFHeader.SizeOfOptionalHeader, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COFFHeader.Characteristics.BitFieldValue, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
COFFHeader.Characteristics.IMAGE_FILE_RELOCS_STRIPPED = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^0) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_EXECUTABLE_IMAGE = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^1) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_LINE_NUMS_STRIPPED = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^2) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_LOCAL_SYMS_STRIPPED = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^3) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_AGGRESIVE_WS_TRIM = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^4) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_LARGE_ADDRESS_AWARE = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^5) ~= 0);
% 2^6 ( Yes there is a gap)
COFFHeader.Characteristics.IMAGE_FILE_BYTES_REVERSED_LO = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^7) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_32BIT_MACHINE = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^8) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_DEBUG_STRIPPED = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^9) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^10) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_NET_RUN_FROM_SWAP = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^11) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_SYSTEM = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^12) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_DLL = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^13) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_UP_SYSTEM_ONLY = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^14) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_BYTES_REVERSED_HI = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^15) ~= 0);
COFFHeader.Characteristics.IMAGE_FILE_RELOCS_STRIPPED = (bitand(COFFHeader.Characteristics.BitFieldValue, 2^16) ~= 0);
rawInfo.COFFHeader = COFFHeader;
% Read IMAGE_OPTIONAL_HEADER(OBJ|32|64)
% NB: Endianess is little-endian in file
if (COFFHeader.SizeOfOptionalHeader == 0)
% This is OBJ => There is no optional header
elseif ((COFFHeader.SizeOfOptionalHeader == 224) || (COFFHeader.SizeOfOptionalHeader == 240))
% This is x32 or x64 => Optional headers differ from a few elements only
[PEOptionalHeader.Magic, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MajorLinkerVersion, c] = fread(fid, 1, 'char*1'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MinorLinkerVersion, c] = fread(fid, 1, 'char*1'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfCode, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfInitializedData, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfUninitializedData, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.AddressOfEntryPoint, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.BaseOfCode, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
if (COFFHeader.SizeOfOptionalHeader == 224)
[PEOptionalHeader.BaseOfData, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.ImageBase, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
else
[PEOptionalHeader.ImageBase, c] = fread(fid, 1, 'uint64'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
end
[PEOptionalHeader.SectionAlignment, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.FileAlignment, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MajorOperatingSystemVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MinorOperatingSystemVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MajorImageVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MinorImageVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MajorSubsystemVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.MinorSubsystemVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.Win32VersionValue, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfImage, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfHeaders, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.Checksum, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.Subsystem, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.DLLCharacteristics.BitFieldValue, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
% reserved 2^0
% reserved 2^1
% reserved 2^2
% reserved 2^3
% reserved 2^4
% reserved 2^5
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^6) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^7) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_NX_COMPAT = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^8) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^9) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_NO_SEH = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^10) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_NO_BIND = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^11) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_APPCONTAINER = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^12) ~= 0);
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^13) ~= 0);
% reserved 2^14
PEOptionalHeader.DLLCharacteristics.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = (bitand(PEOptionalHeader.DLLCharacteristics.BitFieldValue, 2^15) ~= 0);
if (COFFHeader.SizeOfOptionalHeader == 224)
[PEOptionalHeader.SizeOfStackReserve, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfStackCommit, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfHeapReserve, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfHeapCommit, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
else
[PEOptionalHeader.SizeOfStackReserve, c] = fread(fid, 1, 'uint64'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfStackCommit, c] = fread(fid, 1, 'uint64'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfHeapReserve, c] = fread(fid, 1, 'uint64'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.SizeOfHeapCommit, c] = fread(fid, 1, 'uint64'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
end
[PEOptionalHeader.LoaderFlags, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.NumberOfRvaAndSizes, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
StandardRvaNames = { 'ExportTable', 'ImportTable', 'ResourceTable', 'ExceptionTable', 'CertificateTable', 'BaseRelocationTable', 'Debug', 'Architecture', ...
'GlobalPtr', 'TLSTable', 'LoadConfigTable', 'BoundImport', 'IAT', 'DelayImportDescriptor', 'CLRRuntimeHeader', 'Reserved' };
isStandardRvas = (numel(StandardRvaNames) == PEOptionalHeader.NumberOfRvaAndSizes);
for ki = 1:PEOptionalHeader.NumberOfRvaAndSizes,
PEOptionalHeader.DataDirectory(ki).Name = 'Unknown';
if (isStandardRvas), PEOptionalHeader.DataDirectory(ki).Name = StandardRvaNames{ki}; end
[PEOptionalHeader.DataDirectory(ki).VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[PEOptionalHeader.DataDirectory(ki).Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
end
rawInfo.PEOptionalHeader = PEOptionalHeader;
else
error(errmsg); %#ok<SPERR>
end
% Read IMAGE_COR20_HEADER
% NB: Endianess is little-endian in file
% https://stackoverflow.com/questions/480696/how-to-find-if-a-native-dll-file-is-compiled-as-x64-or-x86/3899746
idxClr = find(strcmpi(StandardRvaNames, 'CLRRuntimeHeader'));
if (exist('PEOptionalHeader', 'var') && isStandardRvas && isscalar(idxClr) && (PEOptionalHeader.DataDirectory(idxClr).Size == 72))
Rva = PEOptionalHeader.DataDirectory(idxClr);
offset = getOffsetFromRva(fid, DOSHeader, COFFHeader, Rva);
c = fseek(fid, offset, 'bof'); if (c ~= 0), error(errmsg); end %#ok<SPERR>
[COR20Header.cb, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.MajorRuntimeVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.MinorRuntimeVersion, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.MetaData.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.MetaData.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.Flags.BitFieldValue, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
COR20Header.Flags.COMIMAGE_FLAGS_ILONLY = (bitand(COR20Header.Flags.BitFieldValue, 2^0) ~= 0);
COR20Header.Flags.COMIMAGE_FLAGS_32BITREQUIRED = (bitand(COR20Header.Flags.BitFieldValue, 2^1) ~= 0);
COR20Header.Flags.COMIMAGE_FLAGS_IL_LIBRARY = (bitand(COR20Header.Flags.BitFieldValue, 2^2) ~= 0);
COR20Header.Flags.COMIMAGE_FLAGS_STRONGNAMESIGNED = (bitand(COR20Header.Flags.BitFieldValue, 2^3) ~= 0);
COR20Header.Flags.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT = (bitand(COR20Header.Flags.BitFieldValue, 2^4) ~= 0);
COR20Header.Flags.COMIMAGE_FLAGS_TRACKDEBUGDATA = (bitand(COR20Header.Flags.BitFieldValue, 2^16) ~= 0);
COR20Header.Flags.COMIMAGE_FLAGS_32BITPREFERRED = (bitand(COR20Header.Flags.BitFieldValue, 2^17) ~= 0);
% The main program if it is an EXE (not used if a DLL?)
% If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
% If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint
% (depricated for DLLs, use modules constructors intead).
[COR20Header.EntryPointTokenOrRva, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
% This is the blob of managed resources. Fetched using code:AssemblyNative.GetResource and
% code:PEFile.GetResource and accessible from managed code from
% System.Assembly.GetManifestResourceStream. The meta data has a table that maps names to offsets into
% this blob, so logically the blob is a set of resources.
[COR20Header.Resources.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.Resources.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
% IL assemblies can be signed with a public-private key to validate who created it. The signature goes
% here if this feature is used.
[COR20Header.StrongNameSignature.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.StrongNameSignature.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
% Depricated, not used
[COR20Header.CodeManagerTable.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.CodeManagerTable.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
% Used for manged codee that has unmaanaged code inside it (or exports methods as unmanaged entry points)
[COR20Header.VTableFixups.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.VTableFixups.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.ExportAddressTableJumps.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.ExportAddressTableJumps.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
% Null for ordinary IL images. NGEN images it points at a code:CORCOMPILE_HEADER structure
[COR20Header.ManagedNativeHeader.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
[COR20Header.ManagedNativeHeader.Size, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end %#ok<SPERR>
rawInfo.COR20Header = COR20Header;
end
%]
end
function [offset] = getOffsetFromRva(fid, DOSHeader, COFFHeader, Rva)
%[
% We need to move in file to compute offset, so just make sure to rewind whatever happens
fpos = ftell(fid);
cuo = onCleanup(@()fseek(fid, fpos, 'bof'));
%% #define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)(ntheader) + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + ((ntheader))->FileHeader.SizeOfOptionalHeader ))
%% ==> Well this mean skip [DOS](e_lfanew) + [PESignature](4) + COFFHeahder(20) + OptionalHeader(COFFHeader.SizeOfOptionalHeader)
firstSectionHeaderOffset = DOSHeader.e_lfanew + 4 + 20 + COFFHeader.SizeOfOptionalHeader;
sectionHeaderSizeInBytes = 8+6*4+2*2+4;
for si = 1:COFFHeader.NumberOfSections,
% Read section header
errmsg = 'Failed to parse section header';
sectionHeaderOffset = firstSectionHeaderOffset + (si-1) * sectionHeaderSizeInBytes;
status = fseek(fid, sectionHeaderOffset, 'bof'); if (status ~=0), error('Failed to move to section header.'); end
[sectionHeader.Name, c] = fread(fid, 8, 'char*1=>char'); if (c ~= 8), error(errmsg); end; sectionHeader.Name = sectionHeader.Name.';
[sectionHeader.PhysicalAddressOrVirtualSize, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
[sectionHeader.VirtualAddress, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
[sectionHeader.SizeOfRawData, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
[sectionHeader.PointerToRawData, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
[sectionHeader.PointerToRelocations, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
[sectionHeader.PointerToLineNumbers, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
[sectionHeader.NumberOfRelocations, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end
[sectionHeader.NumberOfLineNumbers, c] = fread(fid, 1, 'uint16'); if (c ~= 1), error(errmsg); end
[sectionHeader.Characteristics, c] = fread(fid, 1, 'uint32'); if (c ~= 1), error(errmsg); end
% Lookup which section contains this RVA so we can translate the VA to a file offset
if ((Rva.VirtualAddress >= sectionHeader.VirtualAddress) && (Rva.VirtualAddress < (sectionHeader.VirtualAddress + sectionHeader.PhysicalAddressOrVirtualSize)))
delta = sectionHeader.VirtualAddress - sectionHeader.PointerToRawData;
offset = Rva.VirtualAddress - delta;
return;
end
end
error('Failed to find section header matching selected Rva');
%]
end
%
% PURPOSE:
%
% Returns simplified information about specified portable executable file.
%
% SYNTAX:
%
% [simplifiedInfo] = GetPortableExecutableSimplifiedInfo(filename);
%
% DESCRIPTION:
%
% - '[simplifiedInfo] = GetPortableExecutableSimplifiedInfo(filename)'
% returns simplified information in 'simplifiedInfo' structure about
% specified portable executable 'filename'.
%
% INPUTS:
%
% - 'filename': Path to portable executable file.
%
% OUTPUTS:
%
% - 'simplifiedInfo': Simplified information about specified portable
% executable file.
%
% simplifiedInfo.Kind = (Executable|Library|Other);
% simplifiedInfo.CodeType = (Native|Managed|Mixed);
% simplifiedInfo.Platform = (x32|x64|AnyCpu|x32Preferred|Other)
%
% REMARKS:
%
% The goal of this function is to quickly identify if some file is an
% executable or a library, in .NET or native code and what plaform is
% targeted.
%
% It was mainly written because of programs badly installing in
% %Program files (x86)% while being x64 anyway.
%
%% ---
function [simplifiedInfo] = GetPortableExecutableSimplifiedInfo(filename)
%[
% Checking arguments
if (nargin <1), error('MATLAB:minrhs', 'Not enough input argments.'); end
% Initializing simplified info
simplifiedInfo.Kind = 'Other';
simplifiedInfo.CodeType = 'Other';
simplifiedInfo.Platform = 'Other';
% Obtaining raw info
[rawInfo, PEConstants] = GetPortableExecutableRawInfo(filename);
% Determining 'Kind' of PE
if (isfield(rawInfo, 'PEOptionalHeader') && (rawInfo.COFFHeader.Characteristics.IMAGE_FILE_EXECUTABLE_IMAGE))
if (rawInfo.COFFHeader.Characteristics.IMAGE_FILE_DLL)
simplifiedInfo.Kind = 'Library';
else
simplifiedInfo.Kind = 'Executable';
end
else
% No optional header or no IMAGE_FILE_EXECUTABLE_IMAGE flag ...
% Maybe just .obj or other thing
simplifiedInfo.Kind = 'Other';
end
% Determining 'CodeType'
% NB: 'COR20Header' is present for MSIL code, but not for native code
if (isfield(rawInfo, 'COR20Header'))
if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_ILONLY)
simplifiedInfo.CodeType = 'Managed';
else
simplifiedInfo.CodeType = 'Mixed';
end
else
simplifiedInfo.CodeType = 'Native';
end
% Determining platform
if (rawInfo.COFFHeader.Machine == PEConstants.IMAGE_FILE_MACHINE_AMD64)
simplifiedInfo.Platform = 'x64';
elseif (rawInfo.COFFHeader.Machine == PEConstants.IMAGE_FILE_MACHINE_I386)
if (isfield(rawInfo, 'COR20Header'))
% PE contains MSIL code, need more checks
if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_32BITREQUIRED)
if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_32BITPREFERRED)
simplifiedInfo.Platform = 'x32Preferred';
else
simplifiedInfo.Platform = 'x32';
end
else
simplifiedInfo.Platform = 'AnyCpu';
end
else
% This is native code so ...
simplifiedInfo.Platform = 'x32';
end
else
% ARM, ...
simplifiedInfo.Platform = 'Other';
end
%]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment