diff --git a/format/all/all.go b/format/all/all.go index 484230cbf..47ae87a52 100644 --- a/format/all/all.go +++ b/format/all/all.go @@ -41,6 +41,7 @@ import ( _ "github.com/wader/fq/format/ogg" _ "github.com/wader/fq/format/opus" _ "github.com/wader/fq/format/pcap" + _ "github.com/wader/fq/format/pe" _ "github.com/wader/fq/format/png" _ "github.com/wader/fq/format/prores" _ "github.com/wader/fq/format/protobuf" diff --git a/format/format.go b/format/format.go index 219b23b43..472510646 100644 --- a/format/format.go +++ b/format/format.go @@ -112,6 +112,9 @@ const ( OPUS_PACKET = "opus_packet" PCAP = "pcap" PCAPNG = "pcapng" + PE = "pe" + PE_COFF = "pe_coff" + PE_MSDOS_STUB = "pe_msdos_stub" PNG = "png" PRORES_FRAME = "prores_frame" PROTOBUF = "protobuf" diff --git a/format/pe/pe.go b/format/pe/pe.go new file mode 100644 index 000000000..5ed5616a4 --- /dev/null +++ b/format/pe/pe.go @@ -0,0 +1,35 @@ +package pe + +// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/ + +import ( + "github.com/wader/fq/format" + "github.com/wader/fq/pkg/decode" + "github.com/wader/fq/pkg/interp" +) + +// TODO: probe? + +var peMSDosStubFormat decode.Group +var peCOFFFormat decode.Group + +func init() { + interp.RegisterFormat(decode.Format{ + Name: format.PE, // TODO: not PE_ prefix? + Description: "Portable Executable", + Groups: []string{format.PROBE}, + Dependencies: []decode.Dependency{ + {Names: []string{format.PE_MSDOS_STUB}, Group: &peMSDosStubFormat}, + {Names: []string{format.PE_COFF}, Group: &peCOFFFormat}, + }, + DecodeFn: peDecode, + }) +} + +func peDecode(d *decode.D, _ any) any { + + d.FieldFormat("ms_dos_stub", peMSDosStubFormat, nil) + d.FieldFormat("coff", peCOFFFormat, nil) + + return nil +} diff --git a/format/pe/pe_coff.go b/format/pe/pe_coff.go new file mode 100644 index 000000000..98adbe7ec --- /dev/null +++ b/format/pe/pe_coff.go @@ -0,0 +1,34 @@ +package pe + +// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/ + +import ( + "github.com/wader/fq/format" + "github.com/wader/fq/pkg/decode" + "github.com/wader/fq/pkg/interp" + "github.com/wader/fq/pkg/scalar" +) + +// TODO: probe? + +func init() { + interp.RegisterFormat(decode.Format{ + Name: format.PE_COFF, // TODO: not PE_ prefix? + Description: "Common Object File Format", + DecodeFn: peCoffStubDecode, + }) +} + +func peCoffStubDecode(d *decode.D, _ any) any { + + d.FieldU32("signature", scalar.UintHex, d.UintAssert(0x50450000)) + d.FieldU16("machine") + d.FieldU16("number_of_sections") + d.FieldU32("time_date_stamp") + d.FieldU32("pointer_to_symbol_table") + d.FieldU32("number_of_symbol_table") + d.FieldU16("size_of_optional_header") + d.FieldU16("characteristics") + + return nil +} diff --git a/format/pe/pe_msdos_stub.go b/format/pe/pe_msdos_stub.go new file mode 100644 index 000000000..95e5fecb6 --- /dev/null +++ b/format/pe/pe_msdos_stub.go @@ -0,0 +1,55 @@ +package pe + +// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/ + +import ( + "github.com/wader/fq/format" + "github.com/wader/fq/pkg/decode" + "github.com/wader/fq/pkg/interp" + "github.com/wader/fq/pkg/scalar" +) + +// TODO: probe? + +func init() { + interp.RegisterFormat(decode.Format{ + Name: format.PE_MSDOS_STUB, // TODO: not PE_ prefix? + Description: "MS-DOS Stub", + DecodeFn: msDosStubDecode, + }) +} + +func msDosStubDecode(d *decode.D, _ any) any { + d.Endian = decode.LittleEndian + + d.FieldU16("e_magic", scalar.UintDescription("Magic number"), d.UintAssert(0x5a4d), scalar.UintHex) + d.FieldU16("e_cblp", scalar.UintDescription("Bytes on last page of file")) + d.FieldU16("e_cp", scalar.UintDescription("Pages in file")) + d.FieldU16("e_crlc", scalar.UintDescription("Relocations")) + d.FieldU16("e_cparhdr", scalar.UintDescription("Size of header in paragraphs")) + d.FieldU16("e_minalloc", scalar.UintDescription("Minimum extra paragraphs needed")) + d.FieldU16("e_maxalloc", scalar.UintDescription("Maximum extra paragraphs needed")) + d.FieldU16("e_ss", scalar.UintDescription("Initial (relative) SS value")) + d.FieldU16("e_sp", scalar.UintDescription("Initial SP value")) + d.FieldU16("e_csum", scalar.UintDescription("Checksum")) + d.FieldU16("e_ip", scalar.UintDescription("Initial IP value")) + d.FieldU16("e_cs", scalar.UintDescription("Initial (relative) CS value")) + d.FieldU16("e_lfarlc", scalar.UintDescription("File address of relocation table")) + d.FieldU16("e_ovno", scalar.UintDescription("Overlay number")) + d.FieldRawLen("e_res", 4*16, scalar.BitBufDescription("Reserved words")) + d.FieldU16("e_oemid", scalar.UintDescription("OEM identifier (for e_oeminfo)")) + d.FieldU16("e_oeminfo", scalar.UintDescription("OEM information; e_oemid specific")) + d.FieldRawLen("e_res2", 10*16, scalar.BitBufDescription("Reserved words")) + lfanew := d.FieldU32("e_lfanew", scalar.UintDescription("File address of new exe header")) + + // TODO: x86 format in the future + d.FieldRawLen("stub", 64*8, scalar.BitBufDescription("Sub program")) + + subEndPos := d.Pos() + + // TODO: is not padding i guess? + padding := lfanew*8 - uint64(subEndPos) + d.FieldRawLen("padding", int64(padding)) + + return nil +}