I want to extract information from executable files, such as the names and sizes of sections, symbols, etc. The Wikipedia article has a diagram showing the layout of a PE. See also this diagram
It seems Mathematica isn't able to decode portable executables out of the box:
exe = Import["C:\\Windows\\System32\\notepad.exe"];
(* cannot infer the format *)
But we can at least read the bytes:
Import["C:\\Windows\\System32\\notepad.exe", "Byte"]
(* or alternatively *)
BinaryReadList["C:\\Windows\\System32\\notepad.exe"]
... so I've tried loading the bytes in myself and decoding the PE byte-by-byte:
(* extract bytes at zero-indexed offsets *)
at[bytes_, i_] := bytes[[i + 1]]
at[bytes_, i_, j_] := bytes[[i + 1 ;; j + 1]]
(* convert little-endian bytes to uint *)
uint[bytes_] := FromDigits[Reverse@bytes, 16]
(* Create a null terminated string from some bytes *)
nulltermstr[bytes_] := FromCharacterCode[TakeWhile[bytes, # > 0 &]]
exe = OpenRead["C:\\Windows\\System32\\notepad.exe", BinaryFormat -> True];
bytes = BinaryReadList[exe];
Close[exe];
peHeaderOffset = uint@at[bytes, 60, 63];
peMagic = FromCharacterCode[at[bytes, peHeaderOffset, peHeaderOffset + 1]]
(* result: PE *)
optionalHeaderSize = uint[at[bytes, peHeaderOffset + 5*4, peHeaderOffset + 5*4 + 1]];
sectionsStartOffset = peHeaderOffset + 3*8 + optionalHeaderSize;
sectionSize = 5*8;
sectionNames = Table[
nulltermstr[at[bytes, sectionsStartOffset + sectionSize*i, sectionsStartOffset + sectionSize*i + 7]]
, {i, 0, 6}]
(* result: {".text",".rdata",".data",".pdata",".didat",".rsrc",".reloc"} *)
It's quite tedious extracting pointers and getting the offsets from the binary format. As you can see, there are 'magic numbers' in my code which is not ideal.
Is there a better, ideally more declarative way to specify the format so that Mathematica can parse these binary headers? Ideally I'd like to be able to declare the structure of the PE file in a way similar to this tool: http://kaitai.io which would make decoding all sorts of binary formats much simpler from within Mathematica.
Import["C:\\Windows\\System32\\notepad.exe", "Byte"]
works for me. So doesBinaryReadList["C:\\Windows\\System32\\notepad.exe"]
$\endgroup$