binparsergen

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2019 License: Apache-2.0 Imports: 8 Imported by: 0

README

Binary Parser Generator

This is a code generator for Go that creates binary parsers. Parsers are loosely based on the Rekall VTypes language and this parser specifically aims to support the json files used and generated by Rekall.

Overview

This parser generator creates objects which represent a C struct. The layout of the struct is typically stored as a JSON file specifying the offset of each field, the type of each field (can be another struct).

The C struct does not need to be complete - i.e. we do not need to every field defined. Each field is parsed independently at its specified offset.

The JSON files can be obtained automatically from debugging symbols (i.e. MS PDB files) and therefore we can create Go parsers for data structures automatically from debugging symbols.

How do I use it?

The first step is to create a vtypes json definition file. This can be obtained from the Rekall project or you can write one by hand.

Here is an example:

{
    "_GUID": [16, {
        "Data1": [0, ["unsigned long", {}]],
        "Data2": [4, ["unsigned short", {}]],
        "Data3": [6, ["unsigned short", {}]],
        "Data4": [8, ["Array", {
            "count": 8,
            "target": "unsigned char"
        }]]
    }]
}

The JSON structure is as follows:

  1. The file is an object with keys being the struct name and values being the struct definition.

  2. The definition is a list with the first item being the size of the struct

  3. The second item is an object with the key being a field name and the value being a field definition.

  4. The field definition is a list with the first item being a struct offset and the second being a type definition

  5. The type definition is a list with the first item being a type name and the second being a parameters object.

  6. Depending on the specific type the mapping object may contain different parameters to control the object.

Note that we generally generate vtype files automatically from debugging symbols and these contain way too much information - for example for structs or fields we dont care about. In order to prevent the binary generator from creating a huge amount of useless code we need to specifically tell it which structs to generate and maybe even filter out some fields.

The spec is just a yaml file:

{
    "Module": "main",
    "Profile": "RegistryProfile",
    "Filename": "profile_vtypes.json",
    "Structs": ["_HBASE_BLOCK", "_GUID", "_LARGE_INTEGER",
                "_HBIN", "_HCELL", "_CM_KEY_NODE", "_CM_KEY_INDEX",
                "_CHILD_LIST", "_HHIVE", "_CM_KEY_VALUE",
                "_CM_KEY_INDEX_FAST", "_CM_KEY_INDEX_FAST_ELEMENT",
                "_CM_BIG_DATA"
               ],
    "FieldBlackList": {
        "_LARGE_INTEGER": ["u"]
    }
}

The spec specifies:

  1. Module: The Go module that will be generated (package name)
  2. Profile: The name of the profile class which will be generated.
  3. Filename: The path to the vtype json file.
  4. Structs: A list of structs to generate parsers for. All these structs will belong to the one profile.
  5. FieldBlackList: A mapping between struct name and fields that will be ignored.

Now we can geneate the code:

$ binparsergen myspecfile.yaml > mygenerated_code.go

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConvertSpec

func ConvertSpec(spec *ConversionSpec) (map[string]*StructDefinition, error)

func FatalIfError

func FatalIfError(err error, format string, args ...interface{})

func GenerateCode

func GenerateCode(
	spec *ConversionSpec,
	profile map[string]*StructDefinition) string

func GenerateDebugString

func GenerateDebugString(name string, profile_name string, definition *StructDefinition) string

func GenerateProfileCode

func GenerateProfileCode(
	profile_name string,
	profile map[string]*StructDefinition) string
 A profile is a factory object for all its containing types. We
   store all the member offsets for all its structs in this object so
   we can tweak offsets on the fly. This allows us to cater for
   different versions. For example:

   type RegistryProfile struct {
	Off_LARGE_INTEGER_HighPart               int64
	Off_LARGE_INTEGER_LowPart                int64
	Off_LARGE_INTEGER_QuadPart               int64
       ....
   }

   The profile is initialized with the offsets defined in the current
   profile json file but may be overridden if a more up to date file
   is available.

   Profiles also contain methods for all their structs. For example
   this method will be generated to parse a HCELL struct at the
   specified offset.

   func (self *RegistryProfile) HCELL(reader io.ReaderAt, offset int64) *HCELL {
     ....
   }

   This allows structs to be grouped into logical units all controlled
   via the same profile (typically compilation units).

func GeneratePrototypes

func GeneratePrototypes() string

func GenerateStructCode

func GenerateStructCode(name string, profile_name string, definition *StructDefinition) string

func InString

func InString(hay []string, needle string) bool

func NormalizeName

func NormalizeName(name string) string

Convert names to something which is exportable by Go.

func SortedIntKeys

func SortedIntKeys(any interface{}) []int

func SortedKeys

func SortedKeys(any interface{}) []string

Types

type ArrayParser

type ArrayParser struct {
	BaseParser
	Target *FieldDefinition
	Count  int
}

func (ArrayParser) Compile

func (self ArrayParser) Compile(struct_name string, field_name string) string

func (ArrayParser) GoType

func (self ArrayParser) GoType() string

func (ArrayParser) Prototype

func (self ArrayParser) Prototype() string

func (ArrayParser) PrototypeName

func (self ArrayParser) PrototypeName() string

func (ArrayParser) Size

func (self ArrayParser) Size(value string) string

type BaseParser

type BaseParser struct {
	Profile string
}

func (BaseParser) Compile

func (self BaseParser) Compile(struct_name string, field_name string) string

func (BaseParser) GoType

func (self BaseParser) GoType() string

func (BaseParser) GoTypePointer

func (self BaseParser) GoTypePointer() string

func (BaseParser) ProfileName

func (self BaseParser) ProfileName() string

func (BaseParser) Prototype

func (self BaseParser) Prototype() string

func (BaseParser) PrototypeName

func (self BaseParser) PrototypeName() string

func (BaseParser) Size

func (self BaseParser) Size(value string) string

type BitField

type BitField struct {
	BaseParser
	StartBit uint64 `json:"start_bit,omitempty"`
	EndBit   uint64 `json:"end_bit,omitempty"`
	Target   string `json:"target,omitempty"`
}

func (BitField) Compile

func (self BitField) Compile(struct_name string, field_name string) string

func (BitField) GoType

func (self BitField) GoType() string

func (*BitField) Prototype

func (self *BitField) Prototype() string

func (BitField) PrototypeName

func (self BitField) PrototypeName() string

func (BitField) Size

func (self BitField) Size(value string) string

type ConversionSpec

type ConversionSpec struct {
	Module              string              `yaml:"Module"`
	Profile             string              `yaml:"Profile"`
	Filename            string              `yaml:"Filename"`
	Structs             []string            `yaml:"Structs"`
	FieldWhiteList      map[string][]string `yaml:"FieldWhiteList"`
	FieldBlackList      map[string][]string `yaml:"FieldBlackList"`
	GenerateDebugString bool                `yaml:"GenerateDebugString"`
}

The conversion process is driven by the conversion spec configuration file.

func LoadSpecFile

func LoadSpecFile(filename string) (*ConversionSpec, error)

type Enumeration

type Enumeration struct {
	BaseParser
	Choices map[int]string `json:"choices,omitempty"`
	Target  string         `json:"target,omitempty"`
}

func (Enumeration) Compile

func (self Enumeration) Compile(struct_name string, field_name string) string

func (Enumeration) GoType

func (self Enumeration) GoType() string

func (*Enumeration) Prototype

func (self *Enumeration) Prototype() string

func (Enumeration) PrototypeName

func (self Enumeration) PrototypeName() string

func (Enumeration) Size

func (self Enumeration) Size(value string) string

type FieldDefinition

type FieldDefinition struct {
	// A field has an offset within the struct.
	Offset uint64

	// A field may be one of the following parsers. Only one of
	// these parsers is allowed.
	Uint64Parser      *Uint64Parser      `json:"Uint64Parser,omitempty"`
	Uint32Parser      *Uint32Parser      `json:"Uint32Parser,omitempty"`
	Uint16Parser      *Uint16Parser      `json:"Uint16Parser,omitempty"`
	Uint8Parser       *Uint8Parser       `json:"Uint8Parser,omitempty"`
	StructParser      *StructParser      `json:"StructParser,omitempty"`
	ArrayParser       *ArrayParser       `json:"ArrayParser,omitempty"`
	Pointer           *Pointer           `json:"Pointer,omitempty"`
	BitField          *BitField          `json:"BitField,omitempty"`
	Enumeration       *Enumeration       `json:"Enumeration,omitempty"`
	StringParser      *StringParser      `json:"StringParser,omitempty"`
	UTF16StringParser *UTF16StringParser `json:"UTF16StringParser,omitempty"`
}

How to represent a field in our data structure.

func ParseFieldDef

func ParseFieldDef(field_def []*json.RawMessage, spec *ConversionSpec) *FieldDefinition

func (*FieldDefinition) GetParser

func (self *FieldDefinition) GetParser() Parser

Extract the active parser from the field definition.

type NullParser

type NullParser struct {
	BaseParser
}

type Parser

type Parser interface {

	// Generate a method on struct_name that extracts field field_name.
	Compile(struct_name string, field_name string) string

	// The name of the profile we are generating.
	ProfileName() string

	// Generate a free function which can parse this object from a
	// reader at a particular offset.
	Prototype() string

	// The name of the Prototype() method.
	PrototypeName() string

	// The GoType we will use to represent this object.
	GoType() string

	// If we use a pointer to represent the object this method
	// should return a "*"
	GoTypePointer() string

	// The size of the object.
	Size(value string) string
}

A parser is an object which generates code to extract a specific object from binary data.

type Pointer

type Pointer struct {
	BaseParser
	Target *FieldDefinition
}

func (Pointer) Compile

func (self Pointer) Compile(struct_name string, field_name string) string

func (Pointer) GoType

func (self Pointer) GoType() string

func (*Pointer) Prototype

func (self *Pointer) Prototype() string

func (Pointer) PrototypeName

func (self Pointer) PrototypeName() string

func (Pointer) Size

func (self Pointer) Size(value string) string

type StringParser

type StringParser struct {
	BaseParser
	Length uint64 `json:"length,omitempty"`
}

func (*StringParser) Compile

func (self *StringParser) Compile(struct_name string, field_name string) string

func (StringParser) GoType

func (self StringParser) GoType() string

func (StringParser) Prototype

func (self StringParser) Prototype() string

func (StringParser) PrototypeName

func (self StringParser) PrototypeName() string

func (StringParser) Size

func (self StringParser) Size(value string) string

type StructDefinition

type StructDefinition struct {
	Size   uint32
	Fields map[string]*FieldDefinition
}

We can consume JSON encoded struct definitions in this format.

type StructParser

type StructParser struct {
	BaseParser
	Target string
}

func (StructParser) Compile

func (self StructParser) Compile(struct_name string, field_name string) string

func (StructParser) GoType

func (self StructParser) GoType() string

func (StructParser) GoTypePointer

func (self StructParser) GoTypePointer() string

func (StructParser) Prototype

func (self StructParser) Prototype() string

func (StructParser) PrototypeName

func (self StructParser) PrototypeName() string

func (StructParser) Size

func (self StructParser) Size(value string) string

type UTF16StringParser

type UTF16StringParser struct {
	BaseParser
	Length uint64 `json:"length,omitempty"`
}

func (*UTF16StringParser) Compile

func (self *UTF16StringParser) Compile(struct_name string, field_name string) string

func (UTF16StringParser) GoType

func (self UTF16StringParser) GoType() string

func (UTF16StringParser) Prototype

func (self UTF16StringParser) Prototype() string

func (UTF16StringParser) PrototypeName

func (self UTF16StringParser) PrototypeName() string

func (UTF16StringParser) Size

func (self UTF16StringParser) Size(value string) string

type Uint16Parser

type Uint16Parser struct {
	BaseParser
}

func (Uint16Parser) Compile

func (self Uint16Parser) Compile(struct_name string, field_name string) string

func (Uint16Parser) GoType

func (self Uint16Parser) GoType() string

func (Uint16Parser) Prototype

func (self Uint16Parser) Prototype() string

func (Uint16Parser) PrototypeName

func (self Uint16Parser) PrototypeName() string

func (Uint16Parser) Size

func (self Uint16Parser) Size(value string) string

type Uint32Parser

type Uint32Parser struct {
	BaseParser
}

func (Uint32Parser) Compile

func (self Uint32Parser) Compile(struct_name string, field_name string) string

func (Uint32Parser) GoType

func (self Uint32Parser) GoType() string

func (Uint32Parser) Prototype

func (self Uint32Parser) Prototype() string

func (Uint32Parser) PrototypeName

func (self Uint32Parser) PrototypeName() string

func (Uint32Parser) Size

func (self Uint32Parser) Size(value string) string

type Uint64Parser

type Uint64Parser struct {
	BaseParser
}

func (Uint64Parser) Compile

func (self Uint64Parser) Compile(struct_name string, field_name string) string

func (Uint64Parser) GoType

func (self Uint64Parser) GoType() string

func (Uint64Parser) Prototype

func (self Uint64Parser) Prototype() string

func (Uint64Parser) PrototypeName

func (self Uint64Parser) PrototypeName() string

func (Uint64Parser) Size

func (self Uint64Parser) Size(value string) string

type Uint8Parser

type Uint8Parser struct {
	BaseParser
}

func (Uint8Parser) Compile

func (self Uint8Parser) Compile(struct_name string, field_name string) string

func (Uint8Parser) GoType

func (self Uint8Parser) GoType() string

func (Uint8Parser) Prototype

func (self Uint8Parser) Prototype() string

func (Uint8Parser) PrototypeName

func (self Uint8Parser) PrototypeName() string

func (Uint8Parser) Size

func (self Uint8Parser) Size(v string) string

type VtypeArray

type VtypeArray struct {
	Target     json.RawMessage
	TargetArgs json.RawMessage
	Count      int
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL