From 3da553081f7c57f29fef51ba580dd82f7f9d847f Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Tue, 4 Oct 2022 11:38:29 +0200 Subject: [PATCH] WIP: pe: Add decoder --- format/all/all.go | 1 + format/format.go | 3 ++ format/pe/pe.go | 37 +++++++++++++++++++++++++ format/pe/pe_coff.go | 35 ++++++++++++++++++++++++ format/pe/pe_msdos_stub.go | 56 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 format/pe/pe.go create mode 100644 format/pe/pe_coff.go create mode 100644 format/pe/pe_msdos_stub.go diff --git a/format/all/all.go b/format/all/all.go index c68a1577b..60f4d9be4 100644 --- a/format/all/all.go +++ b/format/all/all.go @@ -39,6 +39,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/postgres" _ "github.com/wader/fq/format/prores" diff --git a/format/format.go b/format/format.go index 9fb544d6b..26e04ff23 100644 --- a/format/format.go +++ b/format/format.go @@ -144,6 +144,9 @@ var ( Opus_Packet = &decode.Group{Name: "opus_packet"} PCAP = &decode.Group{Name: "pcap"} PCAPNG = &decode.Group{Name: "pcapng"} + PE = &decode.Group{Name: "pe"} + PE_COFF = &decode.Group{Name: "pe_coff"} + PE_MSDOS_Stub = &decode.Group{Name: "pe_msdos_stub"} Pg_BTree = &decode.Group{Name: "pg_btree"} Pg_Control = &decode.Group{Name: "pg_control"} Pg_Heap = &decode.Group{Name: "pg_heap"} diff --git a/format/pe/pe.go b/format/pe/pe.go new file mode 100644 index 000000000..5870cad96 --- /dev/null +++ b/format/pe/pe.go @@ -0,0 +1,37 @@ +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? +// TODO: not pe_ prefix for format names? + +var peMSDosStubGroup decode.Group +var peCOFFGroup decode.Group + +func init() { + interp.RegisterFormat( + format.PE, + &decode.Format{ + Description: "Portable Executable", + Groups: []*decode.Group{format.Probe}, + Dependencies: []decode.Dependency{ + {Groups: []*decode.Group{format.PE_MSDOS_Stub}, Out: &peMSDosStubGroup}, + {Groups: []*decode.Group{format.PE_COFF}, Out: &peCOFFGroup}, + }, + DecodeFn: peDecode, + }) +} + +func peDecode(d *decode.D) any { + + d.FieldFormat("ms_dos_stub", &peMSDosStubGroup, nil) + d.FieldFormat("coff", &peCOFFGroup, nil) + + return nil +} diff --git a/format/pe/pe_coff.go b/format/pe/pe_coff.go new file mode 100644 index 000000000..8312dedac --- /dev/null +++ b/format/pe/pe_coff.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" + "github.com/wader/fq/pkg/scalar" +) + +// TODO: probe? + +func init() { + interp.RegisterFormat( + format.PE_COFF, + &decode.Format{ + Description: "Common Object File Format", + DecodeFn: peCoffStubDecode, + }) +} + +func peCoffStubDecode(d *decode.D) 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..2cb85f174 --- /dev/null +++ b/format/pe/pe_msdos_stub.go @@ -0,0 +1,56 @@ +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( + format.PE_MSDOS_Stub, + &decode.Format{ + Description: "MS-DOS Stub", + DecodeFn: msDosStubDecode, + }) +} + +func msDosStubDecode(d *decode.D) 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 +}