Skip to content

Commit c8629ac

Browse files
committed
pe,pe_coff,pe_msdoc_stub: Add decoders
1 parent 7189798 commit c8629ac

20 files changed

+3184
-2
lines changed

format/all/all.fqtest

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ $ fq -n _registry.groups.probe
2323
"ogg",
2424
"pcap",
2525
"pcapng",
26+
"pe",
2627
"png",
2728
"tar",
2829
"tiff",
@@ -76,6 +77,7 @@ bytes Raw bytes
7677
bzip2 bzip2 compression
7778
caff Live2D Cubism archive
7879
cbor Concise Binary Object Representation
80+
coff Common Object File Format
7981
csv Comma separated values
8082
dns DNS packet
8183
dns_tcp DNS packet (TCP)
@@ -127,12 +129,14 @@ mpeg_pes MPEG Packetized elementary stream
127129
mpeg_pes_packet MPEG Packetized elementary stream packet
128130
mpeg_spu Sub Picture Unit (DVD subtitle)
129131
mpeg_ts MPEG Transport Stream
132+
msdos_stub MS-DOS Stub
130133
msgpack MessagePack
131134
ogg OGG file
132135
ogg_page OGG page
133136
opus_packet Opus packet
134137
pcap PCAP packet capture
135138
pcapng PCAPNG packet capture
139+
pe Portable Executable
136140
pg_btree PostgreSQL btree index file
137141
pg_control PostgreSQL control file
138142
pg_heap PostgreSQL heap file

format/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
_ "github.com/wader/fq/format/ogg"
4343
_ "github.com/wader/fq/format/opus"
4444
_ "github.com/wader/fq/format/pcap"
45+
_ "github.com/wader/fq/format/pe"
4546
_ "github.com/wader/fq/format/png"
4647
_ "github.com/wader/fq/format/postgres"
4748
_ "github.com/wader/fq/format/prores"

format/format.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ var (
8989
Bzip2 = &decode.Group{Name: "bzip2"}
9090
CAFF = &decode.Group{Name: "caff"}
9191
CBOR = &decode.Group{Name: "cbor"}
92+
COFF = &decode.Group{Name: "coff"}
9293
CSV = &decode.Group{Name: "csv"}
9394
DNS = &decode.Group{Name: "dns"}
9495
DNS_TCP = &decode.Group{Name: "dns_tcp"}
@@ -137,16 +138,18 @@ var (
137138
MP4 = &decode.Group{Name: "mp4"}
138139
MPEG_ASC = &decode.Group{Name: "mpeg_asc"}
139140
MPEG_ES = &decode.Group{Name: "mpeg_es"}
140-
MPES_PES = &decode.Group{Name: "mpeg_pes"}
141+
MPEG_PES = &decode.Group{Name: "mpeg_pes"}
141142
MPEG_PES_Packet = &decode.Group{Name: "mpeg_pes_packet"}
142143
MPEG_SPU = &decode.Group{Name: "mpeg_spu"}
143144
MPEG_TS = &decode.Group{Name: "mpeg_ts"}
145+
MSDOS_Stub = &decode.Group{Name: "msdos_stub"}
144146
MsgPack = &decode.Group{Name: "msgpack"}
145147
Ogg = &decode.Group{Name: "ogg"}
146148
Ogg_Page = &decode.Group{Name: "ogg_page"}
147149
Opus_Packet = &decode.Group{Name: "opus_packet"}
148150
PCAP = &decode.Group{Name: "pcap"}
149151
PCAPNG = &decode.Group{Name: "pcapng"}
152+
PE = &decode.Group{Name: "pe"}
150153
Pg_BTree = &decode.Group{Name: "pg_btree"}
151154
Pg_Control = &decode.Group{Name: "pg_control"}
152155
Pg_Heap = &decode.Group{Name: "pg_heap"}
@@ -396,3 +399,11 @@ type Pg_Heap_In struct {
396399
type Pg_BTree_In struct {
397400
Page int `doc:"First page number in file, default is 0"`
398401
}
402+
403+
type MS_DOS_Out struct {
404+
LFANew int // logical file address for the New Executable header
405+
}
406+
407+
type COFF_In struct {
408+
FilePointerOffset int `doc:"File pointer offset"`
409+
}

format/mpeg/mpeg_pes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var mpegSpuGroup decode.Group
1616

1717
func init() {
1818
interp.RegisterFormat(
19-
format.MPES_PES,
19+
format.MPEG_PES,
2020
&decode.Format{
2121
Description: "MPEG Packetized elementary stream",
2222
DecodeFn: pesDecode,

format/pe/coff.go

Lines changed: 635 additions & 0 deletions
Large diffs are not rendered by default.

format/pe/msdos_stub.go

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

format/pe/pe.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package pe
2+
3+
// https://osandamalith.com/2020/07/19/exploring-the-ms-dos-stub/
4+
5+
import (
6+
"fmt"
7+
8+
"github.com/wader/fq/format"
9+
"github.com/wader/fq/pkg/decode"
10+
"github.com/wader/fq/pkg/interp"
11+
)
12+
13+
// TODO: probe?
14+
// TODO: not pe_ prefix for format names?
15+
16+
var msDosStubGroup decode.Group
17+
var coffGroup decode.Group
18+
19+
func init() {
20+
interp.RegisterFormat(
21+
format.PE,
22+
&decode.Format{
23+
Description: "Portable Executable",
24+
Groups: []*decode.Group{format.Probe},
25+
Dependencies: []decode.Dependency{
26+
{Groups: []*decode.Group{format.MSDOS_Stub}, Out: &msDosStubGroup},
27+
{Groups: []*decode.Group{format.COFF}, Out: &coffGroup},
28+
},
29+
DecodeFn: peDecode,
30+
})
31+
}
32+
33+
func peDecode(d *decode.D) any {
34+
_, v := d.FieldFormat("ms_dos_stub", &msDosStubGroup, nil)
35+
msDOSOut, ok := v.(format.MS_DOS_Out)
36+
if !ok {
37+
panic(fmt.Sprintf("expected MS_DOS_Out got %#+v", v))
38+
}
39+
d.FieldFormat("coff", &coffGroup, format.COFF_In{FilePointerOffset: msDOSOut.LFANew})
40+
41+
return nil
42+
}

format/pe/testdata/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
PE sample from https://github.com/JonathanSalwan/binary-samples under MIT license
2+
3+
```sh
4+
rm -f *.fqtest; for i in pe-* *.efi; do echo "\$ fq dv $i" > $i.fqtest ; done
5+
```
6+
7+
EFI sample from https://github.com/badcf00d/UEFI-helloworld under BSD license

format/pe/testdata/helloworld.efi

2 KB
Binary file not shown.

0 commit comments

Comments
 (0)