summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h5
-rw-r--r--binaryninjacore.h5
-rw-r--r--binaryview.cpp36
-rw-r--r--function.cpp21
-rw-r--r--python/binaryview.py69
-rw-r--r--python/function.py49
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):