Skip to content

Instantly share code, notes, and snippets.

@withzombies
Last active October 3, 2018 19:00
Show Gist options
  • Save withzombies/e244473387affa045f4a4947bcbdde57 to your computer and use it in GitHub Desktop.
Save withzombies/e244473387affa045f4a4947bcbdde57 to your computer and use it in GitHub Desktop.
Apply a structure to an address and access its members in BinaryNinja
#!/usr/bin/env python
# Copyright 2017 Ryan Stortz (@withzombies)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import struct
from collections import OrderedDict
from binaryninja import *
class StructuredDataValue(object):
def __init__(self, type, address, value):
self._type = type
self._address = address
self._value = value
@property
def type(self):
return self._type
@property
def width(self):
return self._type.width
@property
def address(self):
return self._address
@property
def value(self):
return self._value
@property
def int(self):
return int(self)
@property
def str(self):
return str(self)
def __int__(self):
if self._type.width == 1:
code = "B"
elif self._type.width == 2:
code = "H"
elif self._type.width == 4:
code = "I"
elif self._type.width == 8:
code ="Q"
else:
raise Exception("Could not convert to integer with width {}".format(self._type.width))
return struct.unpack(code, self._value)[0]
def __str__(self):
decode_str = "{}B".format(self._type.width)
return ' '.join(["{:02x}".format(x) for x in struct.unpack(decode_str, self._value)])
def __repr__(self):
return "<StructuredDataValue type:{} value:{}>".format(str(self._type), str(self))
class StructuredDataView(object):
_structure = None
_structure_name = None
_address = 0
_bv = None
_members = OrderedDict()
def __init__(self, bv, structure_name, address):
self._bv = bv
self._structure_name = structure_name
self._address = address
self._lookup_structure()
self._define_members()
def _lookup_structure(self):
s = self._bv.types.get(self._structure_name, None)
if s is None:
raise Exception("Could not find structure with name: {}".format(self._structure_name))
if s.type_class != TypeClass.StructureTypeClass:
raise Exception("{} is not a StructureTypeClass, got: {}".format(self._structure_name, s._type_class))
self._structure = s.structure
def _define_members(self):
for m in self._structure.members:
self._members[m.name] = m
def __getattr__(self, key):
m = self._members.get(key, None)
if m is None:
return self.__getattribute__(key)
return self[key]
def __getitem__(self, key):
m = self._members.get(key, None)
if m is None:
return super(StructuredDataView, self).__getitem__(key)
ty = m.type
offset = m.offset
width = ty.width
value = self._bv.read(self._address + offset, width)
return StructuredDataValue(ty, self._address + offset, value)
def __str__(self):
rv = "struct {name} 0x{addr:x} {{\n".format(name=self._structure_name, addr=self._address)
for k in self._members:
m = self._members[k]
ty = m.type
offset = m.offset
formatted_offset = "{:=+x}".format(offset)
formatted_type = "{:s} {:s}".format(str(ty), k)
value = self[k]
if value.width in (1,2,4,8):
formatted_value = str.zfill("{:x}".format(value.int), value.width * 2)
else:
formatted_value = str(value)
rv += "\t{:>6s} {:40s} = {:30s}\n".format(formatted_offset, formatted_type, formatted_value)
rv += "}\n"
return rv
def __repr__(self):
return "<StructuredDataView type:{} size:{:#x} address:{:#x}>".format(self._structure_name, self._structure.width, self._address)
if __name__ == '__main__':
if len(sys.argv) != 4:
print "Usage: {} file_to_analyze structure address".format(sys.argv[0])
sys.exit(1)
inputfile = sys.argv[1]
structure = sys.argv[2]
address = int(sys.argv[3], 0)
print "Analyzing {0}".format(inputfile)
bv = BinaryViewType.get_view_of_file(inputfile)
bv.update_analysis_and_wait()
sdv = StructuredDataView(bv, structure, address)
print repr(sdv)
print sdv
$ python StructuredDataView.py bomb.bndb Elf64_Header 0x400000
Analyzing bomb.bndb
<StructuredDataView type:Elf64_Header size:0x40 address:0x400000>
struct Elf64_Header 0x400000 {
+0 struct Elf64_Ident ident = 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
+10 uint16_t type = 0002
+12 uint16_t machine = 003e
+14 uint32_t version = 00000001
+18 void (*)() entry = 0000000000400c90
+20 uint64_t program_header_offset = 0000000000000040
+28 uint64_t section_header_offset = 00000000000048b8
+30 uint32_t flags = 00000000
+34 uint16_t header_size = 0040
+36 uint16_t program_header_size = 0038
+38 uint16_t program_header_count = 0009
+3a uint16_t section_header_size = 0040
+3c uint16_t section_header_count = 0024
+3e uint16_t string_table = 0021
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment