Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: x64_*,arm64: Add decoders #215

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions format/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
_ "github.com/wader/fq/format/icc"
_ "github.com/wader/fq/format/id3"
_ "github.com/wader/fq/format/inet"
_ "github.com/wader/fq/format/isa"
_ "github.com/wader/fq/format/jpeg"
_ "github.com/wader/fq/format/json"
_ "github.com/wader/fq/format/markdown"
Expand Down
62 changes: 54 additions & 8 deletions format/elf/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,23 @@ import (
"github.com/wader/fq/pkg/scalar"
)

var x86_64Group decode.Group
var arm64Group decode.Group

func init() {
interp.RegisterFormat(
format.Elf,
&decode.Format{
Description: "Executable and Linkable Format",
Groups: []*decode.Group{format.Probe},
DecodeFn: elfDecode,
})
Dependencies: []decode.Dependency{
// TODO: x86 32/16?
{Groups: []*decode.Group{format.X86_64}, Out: &x86_64Group},
{Groups: []*decode.Group{format.Arm64}, Out: &arm64Group},
},
},
)
}

const (
Expand Down Expand Up @@ -167,6 +176,15 @@ var phTypeNames = scalar.UintRangeToScalar{
{Range: [2]uint64{0x70000000, 0x7fffffff}, S: scalar.Uint{Sym: "proc", Description: "Processor-specific"}},
}

var machineToFormatFn = map[int]func(d *decode.D, base uint64, symLookup func(uint64) (string, uint64)){
EM_X86_64: func(d *decode.D, base uint64, symLookup func(uint64) (string, uint64)) {
d.Format(&x86_64Group, format.X86_64In{Base: int64(base), SymLookup: symLookup})
},
EM_ARM64: func(d *decode.D, base uint64, symLookup func(uint64) (string, uint64)) {
d.Format(&arm64Group, format.ARM64In{Base: int64(base), SymLookup: symLookup})
},
}

const (
NT_PRSTATUS = 1
NT_PRFPREG = 2
Expand Down Expand Up @@ -980,6 +998,8 @@ func elfDecodeDynamicTags(d *decode.D, ec elfContext, dc dynamicContext) {
}

func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
var execInstr bool

shFlags := func(d *decode.D, archBits int) {
d.FieldStruct("flags", func(d *decode.D) {
if d.Endian == decode.LittleEndian {
Expand All @@ -988,7 +1008,7 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
d.FieldBool("strings")
d.FieldBool("merge")
d.FieldU1("unused0")
d.FieldBool("execinstr")
execInstr = d.FieldBool("execinstr")
d.FieldBool("alloc")
d.FieldBool("write")
d.FieldBool("tls")
Expand Down Expand Up @@ -1018,13 +1038,14 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
d.FieldBool("strings")
d.FieldBool("merge")
d.FieldU1("unused2")
d.FieldBool("execinstr")
execInstr = d.FieldBool("execinstr")
d.FieldBool("alloc")
d.FieldBool("write")
}
})
}

var addr uint64
var offset int64
var size int64
var entSize int64
Expand All @@ -1035,7 +1056,7 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
d.FieldU32("name", strTable(ec.strTabMap[STRTAB_SHSTRTAB]))
typ = d.FieldU32("type", sectionHeaderTypeMap, scalar.UintHex)
shFlags(d, ec.archBits)
d.FieldU("addr", ec.archBits, scalar.UintHex)
addr = d.FieldU("addr", ec.archBits, scalar.UintHex)
offset = int64(d.FieldU("offset", ec.archBits)) * 8
size = int64(d.FieldU32("size", scalar.UintHex) * 8)
d.FieldU32("link")
Expand All @@ -1046,7 +1067,7 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
d.FieldU32("name", strTable(ec.strTabMap[STRTAB_SHSTRTAB]))
typ = d.FieldU32("type", sectionHeaderTypeMap, scalar.UintHex)
shFlags(d, ec.archBits)
d.FieldU("addr", ec.archBits, scalar.UintHex)
addr = d.FieldU("addr", ec.archBits, scalar.UintHex)
offset = int64(d.FieldU("offset", ec.archBits, scalar.UintHex) * 8)
size = int64(d.FieldU64("size") * 8)
d.FieldU32("link")
Expand Down Expand Up @@ -1079,9 +1100,34 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
elfDecodeSymbolTable(d, ec, int(size/entSize), ec.strTabMap[STRTAB_DYNSTR])
})
case SHT_PROGBITS:
// TODO: name progbits?
// TODO: decode opcodes
d.FieldRawLen("data", size)
// TODO: verify this, seems to result in strange relative addresses
symLookup := func(symAddr uint64) (string, uint64) {
var best *symbol

for _, sh := range ec.sections {
for i, s := range sh.symbols {
if symAddr >= s.value && (best == nil || symAddr-s.value < best.value-s.value) {
best = &sh.symbols[i]
}
}
}
if best == nil {
return "", 0
}
return strIndexNull(int(best.name), ec.strTabMap[STRTAB_STRTAB]), best.value
}

// TODO: name progbits? instructions?
if fn, ok := machineToFormatFn[ec.machine]; execInstr && ok {
d.FieldArray("code", func(d *decode.D) {
d.FramedFn(size, func(d *decode.D) {
fn(d, addr, symLookup)
})
})
} else {
d.FieldRawLen("data", size)
}

case SHT_GNU_HASH:
d.FieldStruct("gnu_hash", func(d *decode.D) {
elfDecodeGNUHash(d, ec, size, ec.strTabMap[STRTAB_DYNSTR])
Expand Down
16 changes: 15 additions & 1 deletion format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var (
Apev2 = &decode.Group{Name: "apev2"}
AppleBookmark = &decode.Group{Name: "apple_bookmark"}
Ar = &decode.Group{Name: "ar"}
Arm64 = &decode.Group{Name: "arm64"}
Asn1Ber = &decode.Group{Name: "asn1_ber"}
Av1Ccr = &decode.Group{Name: "av1_ccr"}
Av1Frame = &decode.Group{Name: "av1_frame"}
Expand Down Expand Up @@ -120,8 +121,8 @@ var (
ProtobufWidevine = &decode.Group{Name: "protobuf_widevine"}
PsshPlayready = &decode.Group{Name: "pssh_playready"}
Rtmp = &decode.Group{Name: "rtmp"}
SllPacket = &decode.Group{Name: "sll_packet"}
Sll2Packet = &decode.Group{Name: "sll2_packet"}
SllPacket = &decode.Group{Name: "sll_packet"}
Tar = &decode.Group{Name: "tar"}
TcpSegment = &decode.Group{Name: "tcp_segment"}
Tiff = &decode.Group{Name: "tiff"}
Expand All @@ -138,6 +139,9 @@ var (
Wasm = &decode.Group{Name: "wasm"}
Wav = &decode.Group{Name: "wav"}
Webp = &decode.Group{Name: "webp"}
X86_16 = &decode.Group{Name: "x86_16"}
X86_32 = &decode.Group{Name: "x86_32"}
X86_64 = &decode.Group{Name: "x86_64"}
Xml = &decode.Group{Name: "xml"}
Yaml = &decode.Group{Name: "yaml"}
Zip = &decode.Group{Name: "zip"}
Expand Down Expand Up @@ -341,3 +345,13 @@ type BitCoinBlockIn struct {
type TLSIn struct {
Keylog string `doc:"NSS Key Log content"`
}

type X86_64In struct {
SymLookup func(symAddr uint64) (string, uint64)
Base int64
}

type ARM64In struct {
SymLookup func(symAddr uint64) (string, uint64)
Base int64
}
58 changes: 58 additions & 0 deletions format/isa/arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package isa

import (
"strings"

"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
"golang.org/x/arch/arm64/arm64asm"
)

func init() {
interp.RegisterFormat(
format.Arm64,
&decode.Format{
Description: "ARM64 instructions",
DecodeFn: decodeARM64,
RootArray: true,
RootName: "instructions",
})
}

func decodeARM64(d *decode.D) any {
var symLookup func(uint64) (string, uint64)
var base int64
var ai format.ARM64In

if d.ArgAs(&ai) {
symLookup = ai.SymLookup
base = ai.Base
}

bb := d.BytesRange(0, int(d.BitsLeft()/8))
// TODO: uint64?
pc := base

for !d.End() {
d.FieldStruct("instruction", func(d *decode.D) {
i, err := arm64asm.Decode(bb)
if err != nil {
d.Fatalf("failed to decode arm64 instruction: %s", err)
}

// TODO: other syntax
d.FieldRawLen("opcode", int64(4)*8, scalar.BitBufSym(arm64asm.GoSyntax(i, uint64(pc), symLookup, nil)), scalar.RawHex)

// TODO: Enc?
d.FieldValueUint("op", uint64(i.Enc), scalar.UintSym(strings.ToLower(i.Op.String())), scalar.UintHex)

bb = bb[4:]
pc += int64(4)
})

}

return nil
}
78 changes: 78 additions & 0 deletions format/isa/x86.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package isa

import (
"strings"

"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
"golang.org/x/arch/x86/x86asm"
)

func init() {
// amd64?
interp.RegisterFormat(
format.X86_64,
&decode.Format{
Description: "x86-64 instructions",
DecodeFn: func(d *decode.D) any { return decodeX86(d, 64) },
RootArray: true,
RootName: "instructions",
})
interp.RegisterFormat(
format.X86_32,
&decode.Format{
Description: "x86-32 instructions",
DecodeFn: func(d *decode.D) any { return decodeX86(d, 32) },
RootArray: true,
RootName: "instructions",
})
interp.RegisterFormat(
format.X86_16,
&decode.Format{
Description: "x86-16 instructions",
DecodeFn: func(d *decode.D) any { return decodeX86(d, 16) },
RootArray: true,
RootName: "instructions",
})
}

func decodeX86(d *decode.D, mode int) any {
var symLookup func(uint64) (string, uint64)
var base int64
var xi format.X86_64In

if d.ArgAs(&xi) {
symLookup = xi.SymLookup
base = xi.Base
}

bb := d.BytesRange(0, int(d.BitsLeft()/8))
// TODO: uint64?
pc := base

for !d.End() {
d.FieldStruct("instruction", func(d *decode.D) {
i, err := x86asm.Decode(bb, mode)
if err != nil {
d.Fatalf("failed to decode x86 instruction: %s", err)
}

d.FieldRawLen("opcode", int64(i.Len)*8, scalar.BitBufSym(x86asm.IntelSyntax(i, uint64(pc), symLookup)), scalar.RawHex)

// log.Printf("i.Len: %#+v\n", i.Len)
// log.Printf("i.Opcode: %x\n", i.Opcode)
// log.Printf("i: %#+v\n", i)

// TODO: rebuild op lower?
d.FieldValueUint("op", uint64(i.Opcode), scalar.UintSym(strings.ToLower(i.Op.String())), scalar.UintHex)

bb = bb[i.Len:]
pc += int64(i.Len)
})

}

return nil
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ require (
gopkg.in/yaml.v3 v3.0.1
)

require golang.org/x/arch v0.0.0-20220401014709-5424468ecbac

require (
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ github.com/wader/gojq v0.12.1-0.20230308145020-2de2194791c0 h1:OjBLxUJRtmoYbNtgB
github.com/wader/gojq v0.12.1-0.20230308145020-2de2194791c0/go.mod h1:jQY39j9tgky+JYcJrKNz5OYTe/sPDAw7FvVj13JGqVk=
github.com/wader/readline v0.0.0-20230307172220-bcb7158e7448 h1:AzpBtmgdXa3uznrb3esNeEoaLqtNEwckRmaUH0qWD6w=
github.com/wader/readline v0.0.0-20230307172220-bcb7158e7448/go.mod h1:Zgz8IJWvJoe7NK23CCPpC109XMCqJCpUhpHcnnA4XaM=
golang.org/x/arch v0.0.0-20220401014709-5424468ecbac h1:05z6X/pDgf2qll8x7kbRRVdr33GjdV/GOCGiQfnaJS8=
golang.org/x/arch v0.0.0-20220401014709-5424468ecbac/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
Expand Down