Skip to content

Commit 95c988e

Browse files
committed
WIP: pe: Add decoder
1 parent a7d54ff commit 95c988e

File tree

5 files changed

+216
-0
lines changed

5 files changed

+216
-0
lines changed

format/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
_ "github.com/wader/fq/format/ogg"
4040
_ "github.com/wader/fq/format/opus"
4141
_ "github.com/wader/fq/format/pcap"
42+
_ "github.com/wader/fq/format/pe"
4243
_ "github.com/wader/fq/format/png"
4344
_ "github.com/wader/fq/format/postgres"
4445
_ "github.com/wader/fq/format/prores"

format/format.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ var (
144144
Opus_Packet = &decode.Group{Name: "opus_packet"}
145145
PCAP = &decode.Group{Name: "pcap"}
146146
PCAPNG = &decode.Group{Name: "pcapng"}
147+
PE = &decode.Group{Name: "pe"}
148+
PE_COFF = &decode.Group{Name: "pe_coff"}
149+
PE_MSDOS_Stub = &decode.Group{Name: "pe_msdos_stub"}
147150
Pg_BTree = &decode.Group{Name: "pg_btree"}
148151
Pg_Control = &decode.Group{Name: "pg_control"}
149152
Pg_Heap = &decode.Group{Name: "pg_heap"}

format/pe/pe.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package pe
2+
3+
// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/
4+
5+
import (
6+
"github.com/wader/fq/format"
7+
"github.com/wader/fq/pkg/decode"
8+
"github.com/wader/fq/pkg/interp"
9+
)
10+
11+
// TODO: probe?
12+
// TODO: not pe_ prefix for format names?
13+
14+
var peMSDosStubGroup decode.Group
15+
var peCOFFGroup decode.Group
16+
17+
func init() {
18+
interp.RegisterFormat(
19+
format.PE,
20+
&decode.Format{
21+
Description: "Portable Executable",
22+
Groups: []*decode.Group{format.Probe},
23+
Dependencies: []decode.Dependency{
24+
{Groups: []*decode.Group{format.PE_MSDOS_Stub}, Out: &peMSDosStubGroup},
25+
{Groups: []*decode.Group{format.PE_COFF}, Out: &peCOFFGroup},
26+
},
27+
DecodeFn: peDecode,
28+
})
29+
}
30+
31+
func peDecode(d *decode.D) any {
32+
33+
d.FieldFormat("ms_dos_stub", &peMSDosStubGroup, nil)
34+
d.FieldFormat("coff", &peCOFFGroup, nil)
35+
36+
return nil
37+
}

format/pe/pe_coff.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package pe
2+
3+
// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/
4+
5+
import (
6+
"github.com/wader/fq/format"
7+
"github.com/wader/fq/pkg/decode"
8+
"github.com/wader/fq/pkg/interp"
9+
"github.com/wader/fq/pkg/scalar"
10+
)
11+
12+
// TODO: probe?
13+
14+
func init() {
15+
interp.RegisterFormat(
16+
format.PE_COFF,
17+
&decode.Format{
18+
Description: "Common Object File Format",
19+
DecodeFn: peCoffStubDecode,
20+
})
21+
}
22+
23+
const (
24+
MachineTypeUNKNOWN = 0x0
25+
MachineTypeALPHA = 0x184
26+
MachineTypeALPHA64 = 0x284
27+
MachineTypeAM33 = 0x1d3
28+
MachineTypeAMD64 = 0x8664
29+
MachineTypeARM = 0x1c0
30+
MachineTypeARM64 = 0xaa64
31+
MachineTypeARMNT = 0x1c4
32+
MachineTypeAXP64 = 0x284
33+
MachineTypeEBC = 0xebc
34+
MachineTypeI386 = 0x14c
35+
MachineTypeIA64 = 0x200
36+
MachineTypeLOONGARCH32 = 0x6232
37+
MachineTypeLOONGARCH64 = 0x6264
38+
MachineTypeM32R = 0x9041
39+
MachineTypeMIPS16 = 0x266
40+
MachineTypeMIPSFPU = 0x366
41+
MachineTypeMIPSFPU16 = 0x466
42+
MachineTypePOWERPC = 0x1f0
43+
MachineTypePOWERPCFP = 0x1f1
44+
MachineTypeR4000 = 0x166
45+
MachineTypeRISCV32 = 0x5032
46+
MachineTypeRISCV64 = 0x5064
47+
MachineTypeRISCV128 = 0x5128
48+
MachineTypeSH3 = 0x1a2
49+
MachineTypeSH3DSP = 0x1a3
50+
MachineTypeSH4 = 0x1a6
51+
MachineTypeSH5 = 0x1a8
52+
MachineTypeTHUMB = 0x1c2
53+
MachineTypeWCEMIPSV2 = 0x169
54+
)
55+
56+
var MachineTypeNames = scalar.UintMap{
57+
MachineTypeUNKNOWN: {Sym: "UNKNOWN", Description: "The content of this field is assumed to be applicable to any machine type"},
58+
MachineTypeALPHA: {Sym: "ALPHA", Description: "Alpha AXP, 32-bit address space"},
59+
MachineTypeALPHA64: {Sym: "ALPHA64", Description: "Alpha 64, 64-bit address space"},
60+
MachineTypeAM33: {Sym: "AM33", Description: "Matsushita AM33"},
61+
MachineTypeAMD64: {Sym: "AMD64", Description: "x64"},
62+
MachineTypeARM: {Sym: "ARM", Description: "ARM little endian"},
63+
MachineTypeARM64: {Sym: "ARM64", Description: "ARM64 little endian"},
64+
MachineTypeARMNT: {Sym: "ARMNT", Description: "ARM Thumb-2 little endian"},
65+
//MachineTypeAXP64: {Sym: "AXP64", Description: "AXP 64 (Same as Alpha 64)"},
66+
MachineTypeEBC: {Sym: "EBC", Description: "EFI byte code"},
67+
MachineTypeI386: {Sym: "I386", Description: "Intel 386 or later processors and compatible processors"},
68+
MachineTypeIA64: {Sym: "IA64", Description: "Intel Itanium processor family"},
69+
MachineTypeLOONGARCH32: {Sym: "LOONGARCH32", Description: "LoongArch 32-bit processor family"},
70+
MachineTypeLOONGARCH64: {Sym: "LOONGARCH64", Description: "LoongArch 64-bit processor family"},
71+
MachineTypeM32R: {Sym: "M32R", Description: "Mitsubishi M32R little endian"},
72+
MachineTypeMIPS16: {Sym: "MIPS16", Description: "MIPS16"},
73+
MachineTypeMIPSFPU: {Sym: "MIPSFPU", Description: "MIPS with FPU"},
74+
MachineTypeMIPSFPU16: {Sym: "MIPSFPU16", Description: "MIPS16 with FPU"},
75+
MachineTypePOWERPC: {Sym: "POWERPC", Description: "Power PC little endian"},
76+
MachineTypePOWERPCFP: {Sym: "POWERPCFP", Description: "Power PC with floating point support"},
77+
MachineTypeR4000: {Sym: "R4000", Description: "MIPS little endian"},
78+
MachineTypeRISCV32: {Sym: "RISCV32", Description: "RISC-V 32-bit address space"},
79+
MachineTypeRISCV64: {Sym: "RISCV64", Description: "RISC-V 64-bit address space"},
80+
MachineTypeRISCV128: {Sym: "RISCV128", Description: "RISC-V 128-bit address space"},
81+
MachineTypeSH3: {Sym: "SH3", Description: "Hitachi SH3"},
82+
MachineTypeSH3DSP: {Sym: "SH3DSP", Description: "Hitachi SH3 DSP"},
83+
MachineTypeSH4: {Sym: "SH4", Description: "Hitachi SH4"},
84+
MachineTypeSH5: {Sym: "SH5", Description: "Hitachi SH5"},
85+
MachineTypeTHUMB: {Sym: "THUMB", Description: "Thumb"},
86+
MachineTypeWCEMIPSV2: {Sym: "WCEMIPSV2", Description: "MIPS little-endian WCE v2"},
87+
}
88+
89+
func peCoffStubDecode(d *decode.D) any {
90+
d.Endian = decode.LittleEndian
91+
92+
d.FieldRawLen("signature", 4*8, d.AssertBitBuf([]byte("PE\x00\x00")))
93+
d.FieldU16("machine", MachineTypeNames, scalar.UintHex)
94+
d.FieldU16("number_of_sections")
95+
d.FieldU32("time_date_stamp")
96+
d.FieldU32("pointer_to_symbol_table", scalar.UintHex)
97+
d.FieldU32("number_of_symbol_table")
98+
d.FieldU16("size_of_optional_header")
99+
d.FieldStruct("characteristics", func(d *decode.D) {
100+
d.FieldBool("BYTES_REVERSED_HI") // 0x8000 // Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
101+
d.FieldBool("UP_SYSTEM_ONLY") // 0x4000 // The file should be run only on a uniprocessor machine.
102+
d.FieldBool("DLL") // 0x2000 // The image file is a dynamic-link library (DLL). Such files are considered executable files for almost all purposes, although they cannot be directly run.
103+
d.FieldBool("SYSTEM") // 0x1000 // The image file is a system file, not a user program.
104+
d.FieldBool("NET_RUN_FROM_SWAP") // 0x0800 // If the image is on network media, fully load it and copy it to the swap file.
105+
d.FieldBool("REMOVABLE_RUN_") // FROM_SWAP 0x0400 // If the image is on removable media, fully load it and copy it to the swap file.
106+
d.FieldBool("DEBUG_STRIPPED") // 0x0200 // Debugging information is removed from the image file.
107+
d.FieldBool("32BIT_MACHINE") // 0x0100 // Machine is based on a 32-bit-word architecture.
108+
d.FieldBool("BYTES_REVERSED_LO") // 0x0080 // Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in memory. This flag is deprecated and should be zero.
109+
d.FieldBool("RESERVED") // 0x0040 // This flag is reserved for future use.
110+
d.FieldBool("LARGE_ADDRESS_") // AWARE 0x0020 // Application can handle > 2-GB addresses.
111+
d.FieldBool("AGGRESSIVE_WS_TRIM") // 0x0010 // Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later and must be zero.
112+
d.FieldBool("LOCAL_SYMS_STRIPPED") // 0x0008 // COFF symbol table entries for local symbols have been removed. This flag is deprecated and should be zero.
113+
d.FieldBool("LINE_NUMS_STRIPPED") // 0x0004 // COFF line numbers have been removed. This flag is deprecated and should be zero.
114+
d.FieldBool("EXECUTABLE_IMAGE") // 0x0002 // Image only. This indicates that the image file is valid and can be run. If this flag is not set, it indicates a linker error.
115+
d.FieldBool("RELOCS_STRIPPED") // 0x0001 // Image only, Windows CE, and Microsoft Windows NT and later. This indicates that the file does not contain base relocations and must therefore be loaded at its preferred base address. If the base address is not available, the loader reports an error. The default behavior of the linker is to strip base relocations from executable (EXE) files.
116+
})
117+
118+
return nil
119+
}

format/pe/pe_msdos_stub.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package pe
2+
3+
// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/
4+
5+
import (
6+
"github.com/wader/fq/format"
7+
"github.com/wader/fq/pkg/decode"
8+
"github.com/wader/fq/pkg/interp"
9+
"github.com/wader/fq/pkg/scalar"
10+
)
11+
12+
// TODO: probe?
13+
14+
func init() {
15+
interp.RegisterFormat(
16+
format.PE_MSDOS_Stub,
17+
&decode.Format{
18+
Description: "MS-DOS Stub",
19+
DecodeFn: msDosStubDecode,
20+
})
21+
}
22+
23+
func msDosStubDecode(d *decode.D) any {
24+
d.Endian = decode.LittleEndian
25+
26+
d.FieldU16("e_magic", scalar.UintDescription("Magic number"), d.UintAssert(0x5a4d), scalar.UintHex)
27+
d.FieldU16("e_cblp", scalar.UintDescription("Bytes on last page of file"))
28+
d.FieldU16("e_cp", scalar.UintDescription("Pages in file"))
29+
d.FieldU16("e_crlc", scalar.UintDescription("Relocations"))
30+
d.FieldU16("e_cparhdr", scalar.UintDescription("Size of header in paragraphs"))
31+
d.FieldU16("e_minalloc", scalar.UintDescription("Minimum extra paragraphs needed"))
32+
d.FieldU16("e_maxalloc", scalar.UintDescription("Maximum extra paragraphs needed"))
33+
d.FieldU16("e_ss", scalar.UintDescription("Initial (relative) SS value"))
34+
d.FieldU16("e_sp", scalar.UintDescription("Initial SP value"))
35+
d.FieldU16("e_csum", scalar.UintDescription("Checksum"))
36+
d.FieldU16("e_ip", scalar.UintDescription("Initial IP value"))
37+
d.FieldU16("e_cs", scalar.UintDescription("Initial (relative) CS value"))
38+
d.FieldU16("e_lfarlc", scalar.UintDescription("File address of relocation table"))
39+
d.FieldU16("e_ovno", scalar.UintDescription("Overlay number"))
40+
d.FieldRawLen("e_res", 4*16, scalar.BitBufDescription("Reserved words"))
41+
d.FieldU16("e_oemid", scalar.UintDescription("OEM identifier (for e_oeminfo)"))
42+
d.FieldU16("e_oeminfo", scalar.UintDescription("OEM information; e_oemid specific"))
43+
d.FieldRawLen("e_res2", 10*16, scalar.BitBufDescription("Reserved words"))
44+
lfanew := d.FieldU32("e_lfanew", scalar.UintDescription("File address of new exe header"))
45+
46+
// TODO: x86 format in the future
47+
d.FieldRawLen("stub", 64*8, scalar.BitBufDescription("Sub program"))
48+
49+
subEndPos := d.Pos()
50+
51+
// TODO: is not padding i guess?
52+
padding := lfanew*8 - uint64(subEndPos)
53+
d.FieldRawLen("padding", int64(padding))
54+
55+
return nil
56+
}

0 commit comments

Comments
 (0)