metasploit-framework/lib/metasm/doc/core/SerialStruct.txt

109 lines
3.1 KiB
Plaintext

SerialStruct
============
This is a helper class to handle binary packed data, especially to
represent <core/ExeFormat.txt> structures.
The implementation is in `metasm/exe_format/serialstruct.rb`.
Basics
------
The class defines some class methods, such as:
* `dword`
* `byte`
* `strz`
These methods can be used directly in subclass definitions, e.g.
class MyHeader < SerialStruct
dword :signature
dword :length
end
This will associate the sequence of fields to this structure, which
is used in the `#encode` and `#decode` methods.
These methods rely on an <core/ExeFormat.txt> instance to define
the corresponding `decode_dword` and `encode_dword` methods.
You can then simply call:
hdr = MyHeader.decode(myexefmt)
which will call `myexefmt.decode_word` twice to populate the
`signature` and `length` fields of the MyHeader.instance.
You can also redefine the `#decode` method to handle special cases.
The fields defined this way can be assigned a default value that
will be used when encoding the structure. The syntax is:
dword :fieldname, defaultvalue
If you have a long sequence of identically-typed fields, you can use
the plural form:
dwords :f1, :f2, :f3, :f4
To define your own field types, you should create a new subclass and call the
`new_field` class method. For integral fields, use `new_int_field(fldname)`
that will automatically define the decode/encode routines, and create the
plural form.
class MyStruct < SerialStruct
new_int_field :zword
zwords :offset, :length
end
Symbolic constants
------------------
The class has built-in support for symbolic constants and bit fields.
For exemple, suppose you have a numeric `:type` field, which corresponds
to a set of numeric constants `TYPE_FOO TYPE_BAR TYPE_LOL`. You can use:
TYPES = { 2 => 'FOO', 3 => 'BAR', 4 => 'LOL' }
dword :type
fld_enum :type, TYPES
With this, the standard '#decode' method will first decode the numeric value
of the field, and then lookup the value in the enum hash to find the
corresponding symbol, and use it as the field value.
If there is no mapping, the numeric value is retained. The reverse operation
is done with `#encode`.
For the bitfields, the method is `fld_bits`, and the software will try to
match *OR-ed* values from the bitfield to generate an array of symbols.
BITS = { 1 => 'B1', 2 => 'B2', 4 => 'B4' }
dword :foo
fld_bits :foo, BITS
which will give, for the numeric value `0x15`, `["B1", "B4", 0x10]`
The hashes used for fld_bits or fld_enum can be dynamically determined, by
using the block version of those methods. The block will receive the ExeFormat
instance and the SerialStruct instance, and should return the Hash.
This can be useful when a bitfield signification varies given some generic
property of the exe, eg the target architecture.
Hooks
-----
It is also possible to define a hook that will be called at some point during
the object binary decoding. It will receive the exe and struct instances.
class Header < SerialStruct
dword :machine
decode_hook { |exe, hdr| raise "unknown machine" if hdr.machine > 4 }
dword :bodylength
end