d0c-s4vage/gramfuzz

add feature - relations

dzonerzy opened this issue · 3 comments

Would be nice to have some kind of predefined relations to make it more customizable, i mean something like:

RDef("value",
    Int | Float | RRef("boolean") | RRef("key") | UInt | UFloat | RRef("null")
)
RDef("key-object",

     RRef("key", relation=relation.sizeOf("value")) & ":"
 
)

Something similar would allow more flexibility!

Regards,
Daniele Linguaglossa

@dzonerzy that could be really useful

@dzonerzy I have things like this in pfp, like this https://pfp.readthedocs.io/en/latest/metadata.html#watch-metadata

However, pfp is best suited to parsing existing data, and then modifying/rebuilding it. I think there could be a straightforward way to do this. Bulding on your example:

# PNG is composed of a header, and multiple chunks. Each chunk has the format
#
#    | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
#    -----------------------------------------------------------------
#    |    LENGTH     |      TYPE     |  ... DATA ... |     CRC       |
#
# Where the LENGTH is the length of the DATA, and the CRC is the CRC of the
# TYPE and the DATA concatenated

BinULong = UInt(min=0, max=0x10000, pack=">L")

def chunk_crc(field):
    return calc_crc(field.rel("cname") + field.rel("data"))

RDef("chunk",
    BinULong(name="length"),
    String(name="cname", min=4, max=4, charset=String.charset_alpha),
    String(name="data", min=Rel("length"), max=Rel("length")),
    BinULong(data=chunk_crc),
)

# --- OR having the length based on the data, which would have to be generated
#        first

RDef("chunk",
    BinULong(name="length", data=len(Rel("data"))),
    String(name="cname", min=4, max=4, charset=String.charset_alpha),
    String(name="data", min=0, max=0x10002),
    BinULong(data=chunk_crc),
)

# --- OR Creating a custom Crc type that accepts as parameters the fields to
#        calculate the CRC from

class CRC(UInt):
    self.pack = ">L"

    def __init__(self, *rel_field_names):
        self.rel_field_names = rel_field_names

    def build(self, pre=None, shortest=False, data=None):
        res = And(*list(map(Rel, self.rel_field_names)))
        crc = calc_crc_of_data(res)
        return UInt.build(self, pre, shortest=False, data=crc)

RDef("chunk",
    BinULong(name="length", data=len(Rel("data"))),
    String(name="cname", min=4, max=4, charset=String.charset_alpha),
    String(name="data", min=0, max=0x10002),
    CRC("cname", "data"),
)

To make this work, I think we'd need to add/change/make sure that:

  • gramfuzz can track the context that fields are built within
    • all fields can accept an optional name parameter in their __init__ - this will make them referenceable
    • the context needs to be tied to the build context, not the field instance (field instances can be reused)
    • the Field class should have a rel() function that can be used as a way to get a reference to a named field in the current context
    • the correct order to generate fields based on their dependencies (relations) would have to be determined, and the resulting built values cached in the current scope/context
    • a Rel top-level field class should exist that can be used to define relationships to other named fields in the current context/scope
  • All gramfuzz.fields.Field:build() functions need to accept an optional data argument, which may be:
    • a gramfuzz field that needs to be built (like Rel)
    • a python function that will return data to use, instead of randomly creating it
    • a raw value

I have a javascript-specific wrapper of gramfuzz that I use for browser fuzzing that I haven't released that has some of this functionality, specifically tracking scope/context that things are built within and being able to reference other fields by name. This would be a decent amount of work, but definitely doable, and I think worthwhile.

Also, PRs are welcome too :^) If you @dzonerzy or anyone else wanted to start work on it, I should be able to be more responsive and provide feedback/direction, as I've taken less stressful employment.