diff options
| -rw-r--r-- | binaryninjaapi.h | 5 | ||||
| -rw-r--r-- | binaryninjacore.h | 5 | ||||
| -rw-r--r-- | binaryview.cpp | 36 | ||||
| -rw-r--r-- | function.cpp | 21 | ||||
| -rw-r--r-- | python/binaryview.py | 69 | ||||
| -rw-r--r-- | python/function.py | 49 |
6 files changed, 167 insertions, 18 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 1e5ab511..25c32b1c 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1436,6 +1436,9 @@ namespace BinaryNinja void AddUserDataReference(uint64_t fromAddr, uint64_t toAddr); void RemoveUserDataReference(uint64_t fromAddr, uint64_t toAddr); + std::vector<uint64_t> GetCallees(ReferenceSource addr); + std::vector<ReferenceSource> GetCallers(uint64_t addr); + Ref<Symbol> GetSymbolByAddress(uint64_t addr, const NameSpace& nameSpace=NameSpace()); Ref<Symbol> GetSymbolByRawName(const std::string& name, const NameSpace& nameSpace=NameSpace()); std::vector<Ref<Symbol>> GetSymbolsByName(const std::string& name, const NameSpace& nameSpace=NameSpace()); @@ -2618,6 +2621,8 @@ namespace BinaryNinja void SetComment(const std::string& comment); void SetCommentForAddress(uint64_t addr, const std::string& comment); + std::vector<ReferenceSource> GetCallSites() const; + void AddUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr); void RemoveUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr); diff --git a/binaryninjacore.h b/binaryninjacore.h index 0481c5f4..903e6a45 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2725,7 +2725,6 @@ extern "C" BINARYNINJACOREAPI void BNFreeCodeReferences(BNReferenceSource* refs, size_t count); BINARYNINJACOREAPI uint64_t* BNGetCodeReferencesFrom(BNBinaryView* view, BNReferenceSource* src, size_t* count); BINARYNINJACOREAPI uint64_t* BNGetCodeReferencesFromInRange(BNBinaryView* view, BNReferenceSource* src, uint64_t len, size_t* count); - BINARYNINJACOREAPI void BNFreeCodeReferencesFrom(uint64_t* refs); BINARYNINJACOREAPI uint64_t* BNGetDataReferences(BNBinaryView* view, uint64_t addr, size_t* count); BINARYNINJACOREAPI uint64_t* BNGetDataReferencesInRange(BNBinaryView* view, uint64_t addr, uint64_t len, size_t* count); @@ -2766,6 +2765,10 @@ extern "C" BINARYNINJACOREAPI uint64_t BNToVariableIdentifier(const BNVariable* var); BINARYNINJACOREAPI BNVariable BNFromVariableIdentifier(uint64_t id); + BINARYNINJACOREAPI BNReferenceSource* BNGetFunctionCallSites(BNFunction* func, size_t* count); + BINARYNINJACOREAPI uint64_t* BNGetCallees(BNBinaryView* view, BNReferenceSource* callSite, size_t* count); + BINARYNINJACOREAPI BNReferenceSource* BNGetCallers(BNBinaryView* view, uint64_t callee, size_t* count); + BINARYNINJACOREAPI void BNSetAutoIndirectBranches(BNFunction* func, BNArchitecture* sourceArch, uint64_t source, BNArchitectureAndAddress* branches, size_t count); BINARYNINJACOREAPI void BNSetUserIndirectBranches(BNFunction* func, BNArchitecture* sourceArch, uint64_t source, diff --git a/binaryview.cpp b/binaryview.cpp index 7806c656..fd93b340 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1513,7 +1513,7 @@ vector<uint64_t> BinaryView::GetCodeReferencesFrom(ReferenceSource src) BNReferenceSource _src{ src.func->m_object, src.arch->m_object, src.addr }; uint64_t* refs = BNGetCodeReferencesFrom(m_object, &_src, &count); vector<uint64_t> result(refs, &refs[count]); - BNFreeCodeReferencesFrom(refs); + BNFreeAddressList(refs); return result; } @@ -1524,7 +1524,7 @@ vector<uint64_t> BinaryView::GetCodeReferencesFrom(ReferenceSource src, uint64_t BNReferenceSource _src{ src.func->m_object, src.arch->m_object, src.addr }; uint64_t* refs = BNGetCodeReferencesFromInRange(m_object, &_src, len, &count); vector<uint64_t> result(refs, &refs[count]); - BNFreeCodeReferencesFrom(refs); + BNFreeAddressList(refs); return result; } @@ -1581,6 +1581,38 @@ void BinaryView::RemoveUserDataReference(uint64_t fromAddr, uint64_t toAddr) } +vector<uint64_t> BinaryView::GetCallees(ReferenceSource callSite) +{ + size_t count; + BNReferenceSource src { callSite.func->m_object, callSite.arch->m_object, callSite.addr }; + uint64_t* refs = BNGetCallees(m_object, &src, &count); + vector<uint64_t> result(refs, &refs[count]); + BNFreeAddressList(refs); + return result; +} + + +vector<ReferenceSource> BinaryView::GetCallers(uint64_t addr) +{ + size_t count; + BNReferenceSource* refs = BNGetCallers(m_object, addr, &count); + + vector<ReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + ReferenceSource src; + src.func = new Function(BNNewFunctionReference(refs[i].func)); + src.arch = new CoreArchitecture(refs[i].arch); + src.addr = refs[i].addr; + result.push_back(src); + } + + BNFreeCodeReferences(refs, count); + return result; +} + + Ref<Symbol> BinaryView::GetSymbolByAddress(uint64_t addr, const NameSpace& nameSpace) { BNNameSpace ns = nameSpace.GetAPIObject(); diff --git a/function.cpp b/function.cpp index 66fd870c..752d0bd1 100644 --- a/function.cpp +++ b/function.cpp @@ -246,6 +246,27 @@ void Function::SetCommentForAddress(uint64_t addr, const string& comment) } +vector<ReferenceSource> Function::GetCallSites() const +{ + size_t count; + BNReferenceSource* refs = BNGetFunctionCallSites(m_object, &count); + + vector<ReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + ReferenceSource src; + src.func = new Function(BNNewFunctionReference(refs[i].func)); + src.arch = new CoreArchitecture(refs[i].arch); + src.addr = refs[i].addr; + result.push_back(src); + } + + BNFreeCodeReferences(refs, count); + return result; +} + + void Function::AddUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr) { BNAddUserCodeReference(m_object, fromArch->GetObject(), fromAddr, toAddr); diff --git a/python/binaryview.py b/python/binaryview.py index a88d1dd1..c197e585 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -2811,6 +2811,7 @@ class BinaryView(object): To add a user-specified reference, see :func:`~binaryninja.function.Function.add_user_code_ref`. :param int addr: virtual address to query for references + :param int length: optional length of query :return: List of References for the given virtual address :rtype: list(ReferenceSource) :Example: @@ -2848,6 +2849,11 @@ class BinaryView(object): architecture of the function will be used. This function returns both autoanalysis ("auto") and user-specified ("user") xrefs. To add a user-specified reference, see :func:`~binaryninja.function.Function.add_user_code_ref`. + + :param int addr: virtual address to query for references + :param int length: optional length of query + :return: list of integers + :rtype: list(integer) """ result = [] @@ -2864,7 +2870,7 @@ class BinaryView(object): refs = core.BNGetCodeReferencesFromInRange(self.handle, ref_src, length, count) for i in range(0, count.value): result.append(refs[i]) - core.BNFreeCodeReferencesFrom(refs, count.value) + core.BNFreeAddressList(refs) return result def get_data_refs(self, addr, length=None): @@ -2951,6 +2957,67 @@ class BinaryView(object): core.BNRemoveUserDataReference(self.handle, from_addr, to_addr) + def get_callers(self, addr): + """ + ``get_callers`` returns a list of ReferenceSource objects (xrefs or cross-references) that call the provided virtual address. + In this case, tail calls, jumps, and ordinary calls are considered. + + :param int addr: virtual address of callee to query for callers + :return: List of References that call the given virtual address + :rtype: list(ReferenceSource) + :Example: + + >>> bv.get_callers(here) + [<ref: x86@0x4165ff>] + >>> + + """ + count = ctypes.c_ulonglong(0) + refs = core.BNGetCallers(self.handle, addr, 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_callees(self, addr, func=None, arch=None): + """ + ``get_callees`` returns a list of virtual addresses called by the call site in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, call sites from + all functions and containing the address will be considered. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address of the call site to query for callees + :param Function func: (optional) the function that the call site belongs to + :param Architecture func: (optional) the architecture of the call site + :return: list of integers + :rtype: list(integer) + """ + + 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) + refs = core.BNGetCallees(self.handle, ref_src, count) + for i in range(0, count.value): + result.append(refs[i]) + core.BNFreeAddressList(refs) + return result + + def get_symbol_at(self, addr, namespace=None): """ ``get_symbol_at`` returns the Symbol at the provided virtual address. diff --git a/python/function.py b/python/function.py index 8fbc1811..d7b03cf8 100644 --- a/python/function.py +++ b/python/function.py @@ -2009,26 +2009,47 @@ class Function(object): self.view.update_analysis() @property + def call_sites(self): + """ + ``call_sites`` returns a list of possible call sites. + This includes ordinary calls, tail calls, and indirect jumps. Not all of the returned call sites + may be true call sites; some may simply be unresolved indirect jumps. + + :return: List of References that represent the sources of possible calls in this function + :rtype: list(ReferenceSource) + """ + count = ctypes.c_ulonglong(0) + refs = core.BNGetFunctionCallSites(self.handle, 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 + + @property def callees(self): called = [] - for bb in self.medium_level_il: - for i in bb: - if i.operation in (MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_CALL_UNTYPED): - if i.dest.value.type == RegisterValueType.ConstantPointerValue: - func = self.view.get_function_at(i.dest.value.value, self.platform) - if func is not None: - called.append(func) + for callee_addr in self.callee_addresses: + func = self.view.get_function_at(callee_addr, self.platform) + if func is not None: + called.append(func) return called @property def callee_addresses(self): - called = [] - for bb in self.medium_level_il: - for i in bb: - if i.operation in (MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_CALL_UNTYPED): - if i.dest.value.type == RegisterValueType.ConstantPointerValue: - called.append(i.dest.value.value) - return called + result = [] + for ref in self.call_sites: + result.extend(self.view.get_callees(ref.address, ref.function, ref.arch)) + return result @property def callers(self): |
