def struct_decl(node: Cursor, bv: bn.BinaryView): struct = bn.Structure() struct.width = node.type.get_size() struct.alignment = node.type.get_align() if node.spelling: struct_name = node.spelling else: # A struct can be defined anonymously and assigned via a typedef, which means the struct_decl node itself # will have no spelling. # example: typedef struct { # DWORD Version; # GUID Guid; # SYSTEM_POWER_CONDITION PowerCondition; # DWORD DataLength; # BYTE Data[1]; # } SET_POWER_SETTING_VALUE, *PSET_POWER_SETTING_VALUE; struct_name = node.type.spelling bn.log.log_debug(f'struct_decl: Processing struct {node.spelling}') # In order to avoid recursion problems with structs, always define the struct name as a binaryNinja forward decl bv.define_user_type(struct_name, bn.Type.structure_type(bn.Structure())) # check if struct is a forward declaration within the source code - if it is not a definition, then it is a forward # decl, and no fields should be defined at this point. if node.is_definition(): for field in node.type.get_fields(): bn.log.log_debug(f'struct_decl: Processing struct field {field.spelling}') if is_recursive_field(field, bv): forward_decl_struct = bn.Structure() forward_decl_struct_name = field.type.get_pointee().get_declaration().spelling bv.define_user_type(forward_decl_struct_name, bn.Type.structure_type(forward_decl_struct)) t = bv.get_type_by_name(forward_decl_struct_name) struct.append(t, forward_decl_struct_name) else: var_type = bv.get_type_by_name(field.spelling) if not var_type: # Need to define the field type var_name, var_type = define_type(field.get_definition(), bv) struct.append(var_type, field.spelling) bn.log.log_debug(f'struct_decl: Successfully processed struct field {field.spelling}') try: if node.kind == CursorKind.UNION_DECL: # set type to union struct.type = bn.StructureType.UnionStructureType bv.define_user_type(struct_name, bn.Type.structure_type(struct)) bn.log.log_debug(f'struct_decl: Successfully processed struct {struct_name}') return struct_name, bn.Type.structure_type(struct) except Exception as e: bn.log.log_debug(f'struct_decl: Failed Processing struct {struct_name} with exception {e}')
def pre_define_types(bv: bn.BinaryView, library): for var_type, var_name in library.pre_load_definition.items(): t, n = bv.parse_type_string(f'{var_type} {var_name}') bv.define_user_type(n, t) for forward_decl_struct in library.forward_declarations['struct']: struct = bn.Structure() bv.define_user_type(forward_decl_struct, bn.Type.structure_type(bn.Structure())) for forward_decl_typedef in library.forward_declarations['typedef']: print(forward_decl_typedef) var_type, var_name = bv.parse_type_string(f'{forward_decl_typedef};') bv.define_user_type(var_name, var_type)
def define_anonymous_type(node: Cursor, bv: bn.BinaryView) -> bn.Type: # An anonymous type must be either a Struct\UNION\ENUM. # In order to simplify working with binaryNinja, an anonymized type is de-anonymized: # The name of the anonymous type is a hash of its location in the source file prepended by 'anon_' bn.log.log_debug(f'define_anonymous_type: Processing {node.type.spelling}') struct = bn.Structure() struct.width = node.type.get_size() struct.alignment = node.type.get_align() struct_name = 'anon_' + xxhash.xxh64_hexdigest(node.type.spelling) for field in node.type.get_fields(): bn_field_type = bv.get_type_by_name(field.spelling) field_name = field.spelling if not bn_field_type: # Need to define the field type # if field.is_anonymous(): # field_name, bn_field_type = define_anonymous_type(field, bv) # else: field_name, bn_field_type = define_type(field.get_definition(), bv) bn.log.log_debug(f'define_anonymous_type: Appending field - {bn_field_type} {field_name}') struct.append(bn_field_type, field_name) # Check if the underlying struct is a union if node.type.kind == TypeKind.ELABORATED: if node.type.get_named_type().get_declaration().kind == CursorKind.UNION_DECL: # set type to union struct.type = bn.StructureType.UnionStructureType return struct_name, bn.Type.structure_type(struct)
def test_Struct(self): """Struct produced different result""" inttype = binja.Type.int(4) struct = binja.Structure() struct.a = 1 struct.insert(0, inttype) struct.append(inttype) struct.replace(0, inttype) struct.remove(1) retinfo = [str(i) for i in struct.members] retinfo += [struct.width] struct.width = 16 retinfo += [struct.width] retinfo += [struct.alignment] struct.alignment = 8 retinfo += [struct.alignment] retinfo += [struct.packed] struct.packed = 1 retinfo += [struct.packed] retinfo += [struct.type] retinfo = [str(i) for i in retinfo] return retinfo
def test_Struct(self): """Struct produced different result""" retinfo = [] inttype = binja.Type.int(4) struct = binja.Structure() struct.a = 1 struct.insert(0, inttype) struct.append(inttype) struct.replace(0, inttype) struct.remove(1) for i in struct.members: retinfo.append("Struct member: " + str(i)) retinfo.append("Struct width: " + str(struct.width)) struct.width = 16 retinfo.append("Struct width after adjustment: " + str(struct.width)) retinfo.append("Struct alignment: " + str(struct.alignment)) struct.alignment = 8 retinfo.append("Struct alignment after adjustment: " + str(struct.alignment)) retinfo.append("Struct packed: " + str(struct.packed)) struct.packed = 1 retinfo.append("Struct packed after adjustment: " + str(struct.packed)) retinfo.append("Struct type: " + str(struct.type)) return retinfo
def _construct_binja_type(self, ty: Type, as_specifier: bool = False) -> bn.Type: assert (not isinstance(ty, str)) if ty.uuid in self._s2b_types: if as_specifier and ty.name is not None: ntrc = bn.NamedTypeReferenceClass.UnknownNamedTypeClass if ty.composite_type is not None: if ty.composite_type == CompositeType.CLASS_TYPE: ntrc = bn.NamedTypeReferenceClass.ClassNamedTypeClass elif ty.composite_type == CompositeType.STRUCT_TYPE: ntrc = bn.NamedTypeReferenceClass.StructNamedTypeClass elif ty.composite_type == CompositeType.UNION_TYPE: ntrc = bn.NamedTypeReferenceClass.UnionNamedTypeClass elif ty.composite_type == CompositeType.ENUM_TYPE: ntrc = bn.NamedTypeReferenceClass.EnumNamedTypeClass binja_type = bn.Type.named_type( bn.NamedTypeReference(name=ty.name, type_id=self._generate_typeid( ty.name), type_class=ntrc)) else: return self._s2b_types[ty.uuid] bv = self._binary_view if ty.scalar_type: if ty.scalar_type == ScalarType.BASE_TYPE: if ty.name in self._base_types: binja_type = self._base_types[ty.name] else: try: # If this is a parseable type, do that. binja_type, _ = bv.parse_type_string(ty.name) self._base_types[ty.name] = binja_type self._builtin_types.add(ty.name) except: # Otherwise, create a named type reference. binja_type = bn.Type.named_type( bn.NamedTypeReference( name=ty.name, type_id=self._generate_typeid(ty.name))) self._base_types[ty.name] = binja_type elif ty.scalar_type == ScalarType.POINTER_TYPE: target_type = self._construct_binja_type( ty.element, as_specifier=as_specifier) binja_type = bn.Type.pointer( bv.arch, target_type, ref_type=bn.ReferenceType.PointerReferenceType) elif ty.scalar_type == ScalarType.REFERENCE_TYPE: target_type = self._construct_binja_type( ty.element, as_specifier=as_specifier) binja_type = bn.Type.pointer( bv.arch, target_type, ref_type=bn.ReferenceType.ReferenceReferenceType) elif ty.scalar_type == ScalarType.RVALUE_REFERENCE_TYPE: target_type = self._construct_binja_type( ty.element, as_specifier=as_specifier) binja_type = bn.Type.pointer( bv.arch, target_type, ref_type=bn.ReferenceType.RValueReferenceType) elif ty.scalar_type == ScalarType.ARRAY_TYPE: element_type = self._construct_binja_type( ty.element, as_specifier=as_specifier) count = 0 if ty.array_count is None else ty.array_count if count > 65535: count = 0 binja_type = bn.Type.array(element_type, count) elif ty.composite_type: if as_specifier and ty.name is not None: ntrc = bn.NamedTypeReferenceClass.UnknownNamedTypeClass if ty.composite_type == CompositeType.CLASS_TYPE: ntrc = bn.NamedTypeReferenceClass.ClassNamedTypeClass elif ty.composite_type == CompositeType.STRUCT_TYPE: ntrc = bn.NamedTypeReferenceClass.StructNamedTypeClass elif ty.composite_type == CompositeType.UNION_TYPE: ntrc = bn.NamedTypeReferenceClass.UnionNamedTypeClass elif ty.composite_type == CompositeType.ENUM_TYPE: ntrc = bn.NamedTypeReferenceClass.EnumNamedTypeClass binja_type = bn.Type.named_type( bn.NamedTypeReference(name=ty.name, type_id=self._generate_typeid( ty.name), type_class=ntrc)) else: if ty.composite_type in [ CompositeType.CLASS_TYPE, CompositeType.STRUCT_TYPE ]: struct = bn.Structure() struct.type = bn.StructureType.StructStructureType if ty.composite_type == CompositeType.STRUCT_TYPE else bn.StructureType.ClassStructureType if ty.byte_size is not None: struct.width = ty.byte_size for m in ty.members: member_type = self._construct_binja_type( m.element, as_specifier=True) member_name = m.name if m.name is not None else '' if m.offset is not None: struct.insert(m.offset, member_type, member_name) binja_type = bn.Type.structure_type(struct) elif ty.composite_type == CompositeType.UNION_TYPE: union = bn.Structure() union.type = bn.StructureType.UnionStructureType if ty.byte_size is not None: union.width = ty.byte_size for m in ty.members: member_type = self._construct_binja_type( m.element, as_specifier=as_specifier) member_name = m.name if m.name is not None else '' if m.offset is not None: union.insert(m.offset, member_type, member_name) binja_type = bn.Type.structure_type(union) elif ty.composite_type == CompositeType.ENUM_TYPE: e = bn.Enumeration() for m in ty.members: e.append(m.name, m.offset) binja_type = bn.Type.enumeration_type( bv.arch, e, ty.byte_size) elif ty.composite_type == CompositeType.FUNCTION_TYPE: has_variable_args = False ret = self._construct_binja_type(ty.element, as_specifier=True) params = [] for param in ty.members: if param.element == Type.variadic(): has_variable_args = True else: params.append( self._construct_binja_type(param.element, as_specifier=True)) binja_type = bn.Type.function( ret, params, variable_arguments=has_variable_args) elif ty.composite_type == CompositeType.PTR_TO_MEMBER_TYPE: binja_type = self._construct_binja_type(ty.members[1], as_specifier=True) elif ty.name is not None: ntrc = bn.NamedTypeReferenceClass.TypedefNamedTypeClass binja_type = bn.Type.named_type( bn.NamedTypeReference(name=ty.name, type_id=self._generate_typeid(ty.name), type_class=ntrc)) else: if ty.element is None: print(ty.__dict__) assert (ty.element is not None) binja_type = self._construct_binja_type( ty.element, as_specifier=as_specifier).mutable_copy() if ty.is_constant: binja_type.const = True if ty.is_volatile: binja_type.volatile = True return binja_type