diff options
| author | Xusheng <xusheng@vector35.com> | 2020-11-16 17:51:46 +0800 |
|---|---|---|
| committer | Xusheng <xusheng@vector35.com> | 2021-02-17 12:05:47 +0800 |
| commit | d9b1df165f9daad6a5229718ecd0ee50a5ef6bf1 (patch) | |
| tree | 6307b8c16c80f8203bdb96ebc3d54a8d9f10b3bf /python | |
| parent | b651141704a555cf0b6c53152ab0f70d011ec8af (diff) | |
add support for type xref and variable xref
Diffstat (limited to 'python')
| -rw-r--r-- | python/binaryview.py | 252 | ||||
| -rw-r--r-- | python/function.py | 459 | ||||
| -rw-r--r-- | python/types.py | 84 |
3 files changed, 788 insertions, 7 deletions
diff --git a/python/binaryview.py b/python/binaryview.py index 193cf8b4..cbfc47ef 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -3207,18 +3207,21 @@ class BinaryView(object): return None return DataVariable(var.address, types.Type(var.type, platform = self.platform, confidence = var.typeConfidence), var.autoDiscovered, self) - def get_functions_containing(self, addr): + def get_functions_containing(self, addr, plat=None): """ ``get_functions_containing`` returns a list of functions which contain the given address. :param int addr: virtual address to query. :rtype: list of Function objects """ - basic_blocks = self.get_basic_blocks_at(addr) - + count = ctypes.c_ulonglong(0) + funcs = core.BNGetAnalysisFunctionsContainingAddress(self.handle, addr, count) result = [] - for block in basic_blocks: - result.append(block.function) + for i in range(0, count.value): + result.append(binaryninja.function.Function(self, core.BNNewFunctionReference(funcs[i]))) + core.BNFreeFunctionList(funcs, count.value) + if not plat is None: + result = [func for func in result in func.platform == plat] return result def get_function_at(self, addr, plat=None): @@ -3359,6 +3362,7 @@ class BinaryView(object): :param int addr: virtual address to query for references :param int length: optional length of query + :param Architecture arch: optional architecture of query :return: list of integers :rtype: list(integer) """ @@ -3439,6 +3443,242 @@ class BinaryView(object): return result + def get_code_refs_for_type(self, name): + """ + ``get_code_refs_for_type`` returns a list of ReferenceSource objects (xrefs or cross-references) that reference the provided QualifiedName. + + :param QualifiedName name: name of type to query for references + :return: List of References for the given type + :rtype: list(ReferenceSource) + :Example: + + >>> bv.get_code_refs_for_type('A') + [<ref: x86@0x4165ff>] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetCodeReferencesForType(self.handle, name, count) + + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + addr = refs[i].addr + result.append(binaryninja.architecture.ReferenceSource(func, arch, addr)) + core.BNFreeCodeReferences(refs, count.value) + return result + + + def get_code_refs_for_type_field(self, name, offset): + """ + ``get_code_refs_for_type`` returns a list of ReferenceSource objects (xrefs or cross-references) that reference the provided type field. + + :param QualifiedName name: name of type to query for references + :param int offset: offset of the field, relative to the type + :return: List of References for the given type + :rtype: list(ReferenceSource) + :Example: + + >>> bv.get_code_refs_for_type_field('A', 0x8) + [<ref: x86@0x4165ff>] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetCodeReferencesForTypeField(self.handle, name, offset, count) + + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + addr = refs[i].addr + result.append(binaryninja.architecture.ReferenceSource(func, arch, addr)) + core.BNFreeCodeReferences(refs, count.value) + return result + + + def get_data_refs_for_type(self, name): + """ + ``get_data_refs_for_type`` returns a list of virtual addresses of data which references the type ``name``. + Note, the returned addresses are the actual start of the queried type. For example, suppose there is a DataVariable + at 0x1000 that has type A, and type A contians type B at offset 0x10. Then `get_data_refs_for_type('B')` will + return 0x1010 for it. + + :param QualifiedName name: name of type to query for references + :return: list of integers + :rtype: list(integer) + :Example: + + >>> bv.get_data_refs_for_type('A') + [4203812] + >>> + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetDataReferencesForType(self.handle, name, count) + + result = [] + for i in range(0, count.value): + result.append(refs[i]) + core.BNFreeDataReferences(refs, count.value) + return result + + + def get_data_refs_for_type_field(self, name, offset): + """ + ``get_data_refs_for_type_field`` returns a list of virtual addresses of data which references the type ``name``. + Note, the returned addresses are the actual start of the queried type field. For example, suppose there is a + DataVariable at 0x1000 that has type A, and type A contians type B at offset 0x10. + Then `get_data_refs_for_type_field('B', 0x8)` will return 0x1018 for it. + + :param QualifiedName name: name of type to query for references + :param int offset: offset of the field, relative to the type + :return: list of integers + :rtype: list(integer) + :Example: + + >>> bv.get_data_refs_for_type_field('A', 0x8) + [4203812] + >>> + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetDataReferencesForTypeField(self.handle, name, offset, count) + + result = [] + for i in range(0, count.value): + result.append(refs[i]) + core.BNFreeDataReferences(refs, count.value) + return result + + + def get_type_refs_for_type(self, name): + """ + ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided QualifiedName. + + :param QualifiedName name: name of type to query for references + :return: List of references for the given type + :rtype: list(TypeReferenceSource) + :Example: + + >>> bv.get_type_refs_for_type('A') + ['<type D, offset 0x8, direct>', '<type C, offset 0x10, indirect>'] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetTypeReferencesForType(self.handle, name, count) + + result = [] + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + + + def get_type_refs_for_type_field(self, name, offset): + """ + ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided type field. + + :param QualifiedName name: name of type to query for references + :param int offset: offset of the field, relative to the type + :return: List of references for the given type + :rtype: list(TypeReferenceSource) + :Example: + + >>> bv.get_type_refs_for_type_field('A', 0x8) + ['<type D, offset 0x8, direct>', '<type C, offset 0x10, indirect>'] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetTypeReferencesForTypeField(self.handle, name, offset, count) + + result = [] + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + + def get_code_refs_for_type_from(self, addr, func = None, arch = None, length = None): + """ + ``get_code_refs_for_type_from`` returns a list of types referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address to query for references + :param int length: optional length of query + :return: list of references + :rtype: list(TypeReferenceSource) + """ + result = [] + funcs = self.get_functions_containing(addr) if func is None else [func] + if not funcs: + return [] + for src_func in funcs: + src_arch = src_func.arch if arch is None else arch + ref_src = core.BNReferenceSource(src_func.handle, src_arch.handle, addr) + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetCodeReferencesForTypeFrom(self.handle, ref_src, count) + else: + refs = core.BNGetCodeReferencesForTypeFromInRange(self.handle, ref_src, length, count) + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + + def get_code_refs_for_type_fields_from(self, addr, func = None, arch = None, length = None): + """ + ``get_code_refs_for_type_fields_from`` returns a list of type fields referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address to query for references + :param int length: optional length of query + :return: list of references + :rtype: list(TypeReferenceSource) + """ + result = [] + funcs = self.get_functions_containing(addr) if func is None else [func] + if not funcs: + return [] + for src_func in funcs: + src_arch = src_func.arch if arch is None else arch + ref_src = core.BNReferenceSource(src_func.handle, src_arch.handle, addr) + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetCodeReferencesForTypeFieldsFrom(self.handle, ref_src, count) + else: + refs = core.BNGetCodeReferencesForTypeFieldsFromInRange(self.handle, ref_src, length, count) + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + def add_user_data_ref(self, from_addr, to_addr): """ ``add_user_data_ref`` adds a user-specified data cross-reference (xref) from the address ``from_addr`` to the address ``to_addr``. @@ -5467,7 +5707,7 @@ class BinaryView(object): For annotating code, it is recommended to use comments attached to functions rather than address comments attached to the BinaryView. On the other hand, BinaryView comments can be attached to data whereas function comments cannot. - To create a function-level comment, use :func:`~binaryninja.function.Function.add_user_code_ref`. + To create a function-level comment, use :func:`~binaryninja.function.Function.set_comment_at`. """ count = ctypes.c_ulonglong() addrs = core.BNGetGlobalCommentedAddresses(self.handle, count) diff --git a/python/function.py b/python/function.py index 15bbf251..da6d66e2 100644 --- a/python/function.py +++ b/python/function.py @@ -1054,6 +1054,226 @@ class ParameterVariables(object): self._confidence = value +class ILReferenceSource(object): + def __init__(self, func, arch, addr, il_type, expr_id): + self._function = func + self._arch = arch + self._address = addr + self._il_type = il_type + self._expr_id = expr_id + + def get_il_name(self, il_type): + if il_type == FunctionGraphType.NormalFunctionGraph: + return 'disasmbly' + if il_type == FunctionGraphType.LowLevelILFunctionGraph: + return 'llil' + if il_type == FunctionGraphType.LiftedILFunctionGraph: + return 'lifted_llil' + if il_type == FunctionGraphType.LowLevelILSSAFormFunctionGraph: + return 'llil_ssa' + if il_type == FunctionGraphType.MediumLevelILFunctionGraph: + return 'mlil' + if il_type == FunctionGraphType.MediumLevelILSSAFormFunctionGraph: + return 'mlil_ssa' + if il_type == FunctionGraphType.MappedMediumLevelILFunctionGraph: + return 'mapped_mlil' + if il_type == FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph: + return 'mapped_mlil_ssa' + if il_type == FunctionGraphType.HighLevelILFunctionGraph: + return 'hlil' + if il_type == FunctionGraphType.HighLevelILSSAFormFunctionGraph: + return 'hlil_ssa' + + def __repr__(self): + if self._arch: + return "<ref: %s@%#x, %s@%d>" %\ + (self._arch.name, self._address, self.get_il_name(self._il_type), self.expr_id) + else: + return "<ref: %#x, %s@%d>" %\ + (self._address, self.get_il_name(self._il_type), self.expr_id) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self.function, self.arch, self.address, self.il_type, self.expr_id) ==\ + (other.address, other.function, other.arch, other.il_type, other.expr_id) + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return not (self == other) + + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.function < other.function: + return True + if self.function > other.function: + return False + if self.arch < other.arch: + return True + if self.arch > other.arch: + return False + if self.address < other.address: + return True + if self.address > other.address: + return False + if self.il_type < other.il_type: + return True + if self.il_type > other.il_type: + return False + return self.expr_id < other.expr_id + + def __gt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.function > other.function: + return True + if self.function < other.function: + return False + if self.arch > other.arch: + return True + if self.arch < other.arch: + return False + if self.address > other.address: + return True + if self.address < other.address: + return False + if self.il_type > other.il_type: + return True + if self.il_type < other.il_type: + return False + return self.expr_id > other.expr_id + + def __ge__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self == other) or (self > other) + + def __le__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self == other) or (self < other) + + def __hash__(self): + return hash((self._function, self._arch, self._address, self._il_type, self._expr_id)) + + @property + def function(self): + """ """ + return self._function + + @function.setter + def function(self, value): + self._function = value + + @property + def arch(self): + """ """ + return self._arch + + @arch.setter + def arch(self, value): + self._arch = value + + @property + def address(self): + """ """ + return self._address + + @address.setter + def address(self, value): + self._address = value + + @property + def il_type(self): + """ """ + return self._il_type + + @il_type.setter + def il_type(self, value): + self._il_type = value + + @property + def expr_id(self): + """ """ + return self._expr_id + + @expr_id.setter + def expr_id(self, value): + self._expr_id = value + + +class VariableReferenceSource(object): + def __init__(self, var, src): + self._var = var + self._src = src + + def __repr__(self): + return "<var: %s, src: %s>" % (repr(self._var), repr(self._src)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self.var == other.var) and (self.src == other.src) + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return not (self == other) + + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var < other.var: + return True + if self.var > other.var: + return False + return self.src < other.src + + def __gt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var > other.var: + return True + if self.var < other.var: + return False + return self.src > other.src + + def __ge__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var >= other.var: + return True + if self.var < other.var: + return False + return self.src >= other.src + + def __le__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var <= other.var: + return True + if self.var > other.var: + return False + return self.src <= other.src + + @property + def var(self): + return self._var + @var.setter + def var(self, value): + self._var = value + + @property + def src(self): + return self._src + + @src.setter + def src(self, value): + self._src = value + + class _FunctionAssociatedDataStore(associateddatastore._AssociatedDataStore): _defaults = {} @@ -2033,6 +2253,98 @@ class Function(object): core.BNRemoveUserCodeReference(self.handle, from_arch.handle, from_addr, to_addr) + def add_user_type_ref(self, from_addr, name, from_arch=None): + """ + ``add_user_type_ref`` places a user-defined type cross-reference from the instruction at + the given address and architecture to the specified type. If the specified + source instruction is not contained within this function, no action is performed. + To remove the reference, use :func:`remove_user_type_ref`. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.add_user_code_ref(here, 'A') + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNAddUserTypeReference(self.handle, from_arch.handle, from_addr, name) + + def remove_user_type_ref(self, from_addr, name, from_arch=None): + """ + ``remove_user_type_ref`` removes a user-defined type cross-reference. + If the given address is not contained within this function, or if there is no + such user-defined cross-reference, no action is performed. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.remove_user_type_ref(here, 'A') + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNRemoveUserTypeReference(self.handle, from_arch.handle, from_addr, name) + + def add_user_type_field_ref(self, from_addr, name, offset, from_arch=None): + """ + ``add_user_type_field_ref`` places a user-defined type field cross-reference from the + instruction at the given address and architecture to the specified type. If the specified + source instruction is not contained within this function, no action is performed. + To remove the reference, use :func:`remove_user_type_field_ref`. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param int offset: offset of the field, relative to the type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.add_user_type_field_ref(here, 'A'. 0x8) + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNAddUserTypeFieldReference(self.handle, from_arch.handle, from_addr, name, offset) + + def remove_user_type_field_ref(self, from_addr, name, offset, from_arch=None): + """ + ``remove_user_type_field_ref`` removes a user-defined type field cross-reference. + If the given address is not contained within this function, or if there is no + such user-defined cross-reference, no action is performed. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param int offset: offset of the field, relative to the type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.remove_user_type_field_ref(here, 'A', 0x8) + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNRemoveUserTypeFieldReference(self.handle, from_arch.handle, from_addr, name, offset) + def get_low_level_il_at(self, addr, arch=None): """ ``get_low_level_il_at`` gets the LowLevelILInstruction corresponding to the given virtual address @@ -2974,6 +3286,153 @@ class Function(object): functions.append(ref.function) return functions + def get_mlil_var_refs(self, var): + """ + ``get_mlil_var_refs`` returns a list of ILReferenceSource objects (IL xrefs or cross-references) + that reference the given variable. The variable is a local variable that can be either on the stack, + in a register, or in a flag. + This function is related to get_hlil_var_refs(), which returns variable references collected + from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged + into a single variable in HLIL. + + :param Variable var: Variable for which to query the xref + :return: List of IL References for the given variable + :rtype: list(ILReferenceSource) + :Example: + + >>> var = current_mlil[0].operands[0] + >>> current_function.get_mlil_var_refs(var) + """ + count = ctypes.c_ulonglong(0) + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + refs = core.BNGetMediumLevelILVariableReferences(self.handle, var_data, count) + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + + result.append(binaryninja.ILReferenceSource( + func, arch, refs[i].addr, refs[i].type, refs[i].exprId)) + core.BNFreeILReferences(refs, count.value) + return result + + def get_mlil_var_refs_from(self, addr, length = None, arch = None): + """ + ``get_mlil_var_refs_from`` returns a list of variables referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + This function is related to get_hlil_var_refs_from(), which returns variable references collected + from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged + into a single variable in HLIL. + + :param int addr: virtual address to query for variable references + :param int length: optional length of query + :param Architecture arch: optional architecture of query + :return: list of variable reference sources + :rtype: list(VariableReferenceSource) + """ + result = [] + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetMediumLevelILVariableReferencesFrom(self.handle, self.arch.handle, addr, count) + else: + refs = core.BNGetMediumLevelILVariableReferencesInRange(self.handle, self.arch.handle, addr, length, count) + for i in range(0, count.value): + var = Variable(self, refs[i].var.type, refs[i].var.index, refs[i].var.storage) + if refs[i].source.func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].source.func)) + else: + func = None + if refs[i].source.arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].source.arch) + else: + arch = None + + src = ILReferenceSource(func, arch, refs[i].source.addr, refs[i].source.type, refs[i].source.exprId) + result.append(VariableReferenceSource(var, src)) + core.BNFreeVariableReferenceSourceList(refs, count.value) + return result + + def get_hlil_var_refs(self, var): + """ + ``get_hlil_var_refs`` returns a list of ILReferenceSource objects (IL xrefs or cross-references) + that reference the given variable. The variable is a local variable that can be either on the stack, + in a register, or in a flag. + + :param Variable var: Variable for which to query the xref + :return: List of IL References for the given variable + :rtype: list(ILReferenceSource) + :Example: + + >>> var = current_hlil[0].operands[0] + >>> current_function.get_hlil_var_refs(var) + """ + count = ctypes.c_ulonglong(0) + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + refs = core.BNGetHighLevelILVariableReferences(self.handle, var_data, count) + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + result.append(binaryninja.ILReferenceSource( + func, arch, refs[i].addr, refs[i].type, refs[i].exprId)) + core.BNFreeILReferences(refs, count.value) + return result + + def get_hlil_var_refs_from(self, addr, length = None, arch = None): + """ + ``get_hlil_var_refs_from`` returns a list of variables referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address to query for variable references + :param int length: optional length of query + :param Architecture arch: optional architecture of query + :return: list of variables reference sources + :rtype: list(VariableReferenceSource) + """ + result = [] + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetHighLevelILVariableReferencesFrom(self.handle, self.arch.handle, addr, count) + else: + refs = core.BNGetHighLevelILVariableReferencesInRange(self.handle, self.arch.handle, addr, length, count) + for i in range(0, count.value): + var = Variable(self, refs[i].var.type, refs[i].var.index, refs[i].var.storage) + if refs[i].source.func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].source.func)) + else: + func = None + if refs[i].source.arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].source.arch) + else: + arch = None + + src = ILReferenceSource(func, arch, refs[i].source.addr, refs[i].source.type, refs[i].source.exprId) + result.append(VariableReferenceSource(var, src)) + core.BNFreeVariableReferenceSourceList(refs, count.value) + return result + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): diff --git a/python/types.py b/python/types.py index 7d59261d..e6ab5c2b 100644 --- a/python/types.py +++ b/python/types.py @@ -26,7 +26,7 @@ import ctypes # Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core -from binaryninja.enums import SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType +from binaryninja.enums import SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType, TypeReferenceType # 2-3 compatibility from binaryninja import range @@ -146,6 +146,88 @@ class QualifiedName(object): self._byte_name = value +class TypeReferenceSource(object): + def __init__(self, name, offset, ref_type): + self._name = name + self._offset = offset + self._ref_type = ref_type + + def __str__(self): + if self.ref_type == TypeReferenceType.DirectTypeReferenceType: + s = 'direct' + elif self.ref_type == TypeReferenceType.IndirectTypeReferenceType: + s = 'indirect' + else: + s = 'unknown' + return '<type %s, offset 0x%x, %s>' % (self.name, self.offset, s) + + def __repr__(self): + return repr(str(self)) + + @property + def name(self): + """ """ + return self._name + + @property + def offset(self): + """ """ + return self._offset + + @property + def ref_type(self): + """ """ + return self._ref_type + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.name == other.name and self.offset == other.offset and self.ref_type == other.ref_type + return NotImplemented + + def __ne__(self, other): + if isinstance(other, self.__class__): + return not self.__eq__(other) + return NotImplemented + + def __lt__(self, other): + if isinstance(other, self.__class__): + if self.name < other.name: + return True + elif self.name > other.name: + return False + elif self.offset < other.offset: + return True + elif self.offset > other.offset: + return False + return self.ref_type < other.ref_type + return NotImplemented + + def __gt__(self, other): + if isinstance(other, self.__class__): + if self.name > other.name: + return True + elif self.name < other.name: + return False + elif self.offset > other.offset: + return True + elif self.offset < other.offset: + return False + return self.ref_type > other.ref_type + return NotImplemented + + def __cmp__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + + if self == other: + return 0 + elif self < other: + return -1 + return 1 + + def __hash__(self): + return hash(str(self)) + class NameSpace(QualifiedName): def __str__(self): return ":".join(self.name) |
