From 3d403cfae9d5a366f112c8a5936a371a01cfd230 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 10 Jul 2017 21:40:51 -0400 Subject: Add confidence levels to type objects --- python/types.py | 165 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 134 insertions(+), 31 deletions(-) (limited to 'python/types.py') diff --git a/python/types.py b/python/types.py index f8e416f4..c3d7156e 100644 --- a/python/types.py +++ b/python/types.py @@ -22,7 +22,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core -from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType +from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType import callingconvention import function @@ -198,8 +198,11 @@ class Symbol(object): class Type(object): - def __init__(self, handle): + max_confidence = 255 + + def __init__(self, handle, confidence = max_confidence): self.handle = handle + self.confidence = confidence def __del__(self): core.BNFreeType(self.handle) @@ -232,12 +235,14 @@ class Type(object): @property def signed(self): """Wether type is signed (read-only)""" - return core.BNIsTypeSigned(self.handle) + result = core.BNIsTypeSigned(self.handle) + return BoolWithConfidence(result.value, confidence = result.confidence) @property def const(self): """Whether type is const (read-only)""" - return core.BNIsTypeConst(self.handle) + result = core.BNIsTypeConst(self.handle) + return BoolWithConfidence(result.value, confidence = result.confidence) @property def modified(self): @@ -248,33 +253,33 @@ class Type(object): def target(self): """Target (read-only)""" result = core.BNGetChildType(self.handle) - if result is None: + if not result.type: return None - return Type(result) + return Type(result.type, confidence = result.confidence) @property def element_type(self): """Target (read-only)""" result = core.BNGetChildType(self.handle) - if result is None: + if not result.type: return None - return Type(result) + return Type(result.type, confidence = result.confidence) @property def return_value(self): """Return value (read-only)""" result = core.BNGetChildType(self.handle) - if result is None: + if not result.type: return None - return Type(result) + return Type(result.type, confidence = result.confidence) @property def calling_convention(self): """Calling convention (read-only)""" result = core.BNGetTypeCallingConvention(self.handle) - if result is None: + if not result.convention: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(None, result, confidence = result.confidence) @property def parameters(self): @@ -283,7 +288,7 @@ class Type(object): params = core.BNGetTypeParameters(self.handle, count) result = [] for i in xrange(0, count.value): - result.append((Type(core.BNNewTypeReference(params[i].type)), params[i].name)) + result.append((Type(core.BNNewTypeReference(params[i].type), confidence = params[i].typeConfidence), params[i].name)) core.BNFreeTypeParameterList(params, count.value) return result @@ -295,7 +300,8 @@ class Type(object): @property def can_return(self): """Whether type can return (read-only)""" - return core.BNFunctionTypeCanReturn(self.handle) + result = core.BNFunctionTypeCanReturn(self.handle) + return BoolWithConfidence(result.value, confidence = result.confidence) @property def structure(self): @@ -330,6 +336,8 @@ class Type(object): return core.BNGetTypeString(self.handle) def __repr__(self): + if self.confidence < Type.max_confidence: + return "" % (str(self), (self.confidence * 100) / Type.max_confidence) return "" % str(self) def get_string_before_name(self): @@ -351,8 +359,9 @@ class Type(object): size = tokens[i].size operand = tokens[i].operand context = tokens[i].context + confidence = tokens[i].confidence address = tokens[i].address - result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) core.BNFreeTokenList(tokens, count.value) return result @@ -367,8 +376,9 @@ class Type(object): size = tokens[i].size operand = tokens[i].operand context = tokens[i].context + confidence = tokens[i].confidence address = tokens[i].address - result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) core.BNFreeTokenList(tokens, count.value) return result @@ -383,8 +393,9 @@ class Type(object): size = tokens[i].size operand = tokens[i].operand context = tokens[i].context + confidence = tokens[i].confidence address = tokens[i].address - result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) core.BNFreeTokenList(tokens, count.value) return result @@ -397,14 +408,23 @@ class Type(object): return Type(core.BNCreateBoolType()) @classmethod - def int(self, width, sign = True, altname=""): + def int(self, width, sign = None, altname=""): """ ``int`` class method for creating an int Type. :param int width: width of the integer in bytes :param bool sign: optional variable representing signedness """ - return Type(core.BNCreateIntegerType(width, sign, altname)) + if sign is None: + sign = BoolWithConfidence(True, confidence = 0) + elif not isinstance(sign, BoolWithConfidence): + sign = BoolWithConfidence(sign) + + sign_conf = core.BNBoolWithConfidence() + sign_conf.value = sign.value + sign_conf.confidence = sign.confidence + + return Type(core.BNCreateIntegerType(width, sign_conf, altname)) @classmethod def float(self, width): @@ -444,12 +464,40 @@ class Type(object): return Type(core.BNCreateEnumerationType(e.handle, width)) @classmethod - def pointer(self, arch, t, const=False): - return Type(core.BNCreatePointerType(arch.handle, t.handle, const)) + def pointer(self, arch, t, const=None, volatile=None, ref_type=None): + if const is None: + const = BoolWithConfidence(False, confidence = 0) + elif not isinstance(const, BoolWithConfidence): + const = BoolWithConfidence(const) + + if volatile is None: + volatile = BoolWithConfidence(False, confidence = 0) + elif not isinstance(volatile, BoolWithConfidence): + volatile = BoolWithConfidence(volatile) + + if ref_type is None: + ref_type = ReferenceType.PointerReferenceType + + type_conf = core.BNTypeWithConfidence() + type_conf.type = t.handle + type_conf.confidence = t.confidence + + const_conf = core.BNBoolWithConfidence() + const_conf.value = const.value + const_conf.confidence = const.confidence + + volatile_conf = core.BNBoolWithConfidence() + volatile_conf.value = volatile.value + volatile_conf.confidence = volatile.confidence + + return Type(core.BNCreatePointerType(arch.handle, type_conf, const_conf, volatile_conf, ref_type)) @classmethod def array(self, t, count): - return Type(core.BNCreateArrayType(t.handle, count)) + type_conf = core.BNTypeWithConfidence() + type_conf.type = t.handle + type_conf.confidence = t.confidence + return Type(core.BNCreateArrayType(type_conf, count)) @classmethod def function(self, ret, params, calling_convention=None, variable_arguments=False): @@ -466,13 +514,26 @@ class Type(object): if isinstance(params[i], Type): param_buf[i].name = "" param_buf[i].type = params[i].handle + param_buf[i].typeConfidence = params[i].confidence else: param_buf[i].name = params[i][1] - param_buf[i].type = params[i][0] - if calling_convention is not None: - calling_convention = calling_convention.handle - return Type(core.BNCreateFunctionType(ret.handle, calling_convention, param_buf, len(params), - variable_arguments)) + param_buf[i].type = params[i][0].handle + param_buf[i].typeConfidence = params[i][0].confidence + + ret_conf = core.BNTypeWithConfidence() + ret_conf.type = ret.handle + ret_conf.confidence = ret.confidence + + conv_conf = core.BNCallingConventionWithConfidence() + if calling_convention is None: + conv_conf.convention = None + conv_conf.confidence = 0 + else: + conv_conf.convention = calling_convention.handle + conv_conf.confidence = calling_convention.confidence + + return Type(core.BNCreateFunctionType(ret_conf, conv_conf, param_buf, len(params), + variable_arguments)) @classmethod def generate_auto_type_id(self, source, name): @@ -488,6 +549,9 @@ class Type(object): def get_auto_demanged_type_id_source(self): return core.BNGetAutoDemangledTypeIdSource() + def with_confidence(self, confidence): + return Type(handle = core.BNNewTypeReference(self.handle), confidence = confidence) + def __setattr__(self, name, value): try: object.__setattr__(self, name, value) @@ -495,6 +559,36 @@ class Type(object): raise AttributeError("attribute '%s' is read only" % name) +class BoolWithConfidence(object): + def __init__(self, value, confidence = Type.max_confidence): + self.value = value + self.confidence = confidence + + def __str__(self): + return str(self.value) + + def __repr__(self): + return repr(self.value) + + def __bool__(self): + return self.value + + def __nonzero__(self): + return self.value + + +class ReferenceTypeWithConfidence(object): + def __init__(self, value, confidence = Type.max_confidence): + self.value = value + self.confidence = confidence + + def __str__(self): + return str(self.value) + + def __repr__(self): + return repr(self.value) + + class NamedTypeReference(object): def __init__(self, type_class = NamedTypeReferenceClass.UnknownNamedTypeClass, type_id = None, name = None, handle = None): if handle is None: @@ -611,7 +705,7 @@ class Structure(object): members = core.BNGetStructureMembers(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(StructureMember(Type(core.BNNewTypeReference(members[i].type)), + result.append(StructureMember(Type(core.BNNewTypeReference(members[i].type), confidence = members[i].typeConfidence), members[i].name, members[i].offset)) core.BNFreeStructureMemberList(members, count.value) return result @@ -664,16 +758,25 @@ class Structure(object): return "" % self.width def append(self, t, name = ""): - core.BNAddStructureMember(self.handle, t.handle, name) + tc = core.BNTypeWithConfidence() + tc.type = t.handle + tc.confidence = t.confidence + core.BNAddStructureMember(self.handle, tc, name) def insert(self, offset, t, name = ""): - core.BNAddStructureMemberAtOffset(self.handle, t.handle, name, offset) + tc = core.BNTypeWithConfidence() + tc.type = t.handle + tc.confidence = t.confidence + core.BNAddStructureMemberAtOffset(self.handle, tc, name, offset) def remove(self, i): core.BNRemoveStructureMember(self.handle, i) def replace(self, i, t, name = ""): - core.BNReplaceStructureMember(self.handle, i, t.handle, name) + tc = core.BNTypeWithConfidence() + tc.type = t.handle + tc.confidence = t.confidence + core.BNReplaceStructureMember(self.handle, i, tc, name) class EnumerationMember(object): -- cgit v1.3.1 From 35c65d909d1ec36a4a1bad7404c9f986e259f662 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Fri, 14 Jul 2017 01:05:18 -0400 Subject: Adding API to get type of MLIL expression --- binaryninjaapi.h | 2 ++ binaryninjacore.h | 2 ++ mediumlevelil.cpp | 9 +++++++++ python/callingconvention.py | 2 +- python/function.py | 4 ++-- python/mediumlevelil.py | 9 +++++++++ python/types.py | 12 ++++++------ 7 files changed, 31 insertions(+), 9 deletions(-) (limited to 'python/types.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 2341e39f..f079e7c0 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2550,6 +2550,8 @@ namespace BinaryNinja Ref GetLowLevelIL() const; size_t GetLowLevelILInstructionIndex(size_t instr) const; size_t GetLowLevelILExprIndex(size_t expr) const; + + Confidence> GetExprType(size_t expr); }; class FunctionRecognizer diff --git a/binaryninjacore.h b/binaryninjacore.h index f5b89437..0414b512 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2488,6 +2488,8 @@ extern "C" BINARYNINJACOREAPI size_t BNGetLowLevelILInstructionIndex(BNMediumLevelILFunction* func, size_t instr); BINARYNINJACOREAPI size_t BNGetLowLevelILExprIndex(BNMediumLevelILFunction* func, size_t expr); + BINARYNINJACOREAPI BNTypeWithConfidence BNGetMediumLevelILExprType(BNMediumLevelILFunction* func, size_t expr); + // Types BINARYNINJACOREAPI BNType* BNCreateVoidType(void); BINARYNINJACOREAPI BNType* BNCreateBoolType(void); diff --git a/mediumlevelil.cpp b/mediumlevelil.cpp index 8bbb2746..df78de2d 100644 --- a/mediumlevelil.cpp +++ b/mediumlevelil.cpp @@ -494,3 +494,12 @@ size_t MediumLevelILFunction::GetLowLevelILExprIndex(size_t expr) const { return BNGetLowLevelILExprIndex(m_object, expr); } + + +Confidence> MediumLevelILFunction::GetExprType(size_t expr) +{ + BNTypeWithConfidence result = BNGetMediumLevelILExprType(m_object, expr); + if (!result.type) + return nullptr; + return Confidence>(new Type(result.type), result.confidence); +} diff --git a/python/callingconvention.py b/python/callingconvention.py index e6aa323c..db473c53 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -41,7 +41,7 @@ class CallingConvention(object): _registered_calling_conventions = [] - def __init__(self, arch, handle = None, confidence = types.Type.max_confidence): + def __init__(self, arch, handle = None, confidence = types.max_confidence): if handle is None: self.arch = arch self._pending_reg_lists = {} diff --git a/python/function.py b/python/function.py index 3cd5396f..aa0d05eb 100644 --- a/python/function.py +++ b/python/function.py @@ -185,7 +185,7 @@ class Variable(object): if var_type is None: var_type_conf = core.BNGetVariableType(func.handle, var) if var_type_conf.type: - var_type = types.Type(var_type, confidence = var_type_conf.confidence) + var_type = types.Type(var_type_conf.type, confidence = var_type_conf.confidence) else: var_type = None @@ -1401,7 +1401,7 @@ class InstructionTextToken(object): """ def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff, - context = InstructionTextTokenContext.NoTokenContext, address = 0, confidence = types.Type.max_confidence): + context = InstructionTextTokenContext.NoTokenContext, address = 0, confidence = types.max_confidence): self.type = InstructionTextTokenType(token_type) self.text = text self.value = value diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 275746cc..76a85a86 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -26,6 +26,7 @@ from .enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDep import function import basicblock import lowlevelil +import types class SSAVariable(object): @@ -397,6 +398,14 @@ class MediumLevelILInstruction(object): result += operand.vars_read return result + @property + def expr_type(self): + """Type of expression""" + result = core.BNGetMediumLevelILExprType(self.function.handle, self.expr_index) + if result.type: + return types.Type(result.type, confidence = result.confidence) + return None + def get_ssa_var_possible_values(self, ssa_var): var_data = core.BNVariable() var_data.type = ssa_var.var.source_type diff --git a/python/types.py b/python/types.py index c3d7156e..5933661a 100644 --- a/python/types.py +++ b/python/types.py @@ -18,6 +18,8 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. +max_confidence = 255 + import ctypes # Binary Ninja components @@ -198,8 +200,6 @@ class Symbol(object): class Type(object): - max_confidence = 255 - def __init__(self, handle, confidence = max_confidence): self.handle = handle self.confidence = confidence @@ -336,8 +336,8 @@ class Type(object): return core.BNGetTypeString(self.handle) def __repr__(self): - if self.confidence < Type.max_confidence: - return "" % (str(self), (self.confidence * 100) / Type.max_confidence) + if self.confidence < max_confidence: + return "" % (str(self), (self.confidence * 100) / max_confidence) return "" % str(self) def get_string_before_name(self): @@ -560,7 +560,7 @@ class Type(object): class BoolWithConfidence(object): - def __init__(self, value, confidence = Type.max_confidence): + def __init__(self, value, confidence = max_confidence): self.value = value self.confidence = confidence @@ -578,7 +578,7 @@ class BoolWithConfidence(object): class ReferenceTypeWithConfidence(object): - def __init__(self, value, confidence = Type.max_confidence): + def __init__(self, value, confidence = max_confidence): self.value = value self.confidence = confidence -- cgit v1.3.1 From b7c5486f26386c7c165b9b05cc2d6800db082b6f Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 17 Jul 2017 14:01:48 -0400 Subject: Fix referenced to old calling convention api, Fixes #739 --- python/architecture.py | 2 +- python/callingconvention.py | 4 +++- python/platform.py | 12 ++++++------ python/types.py | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'python/types.py') diff --git a/python/architecture.py b/python/architecture.py index 9af85934..416fa362 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -361,7 +361,7 @@ class Architecture(object): cc = core.BNGetArchitectureCallingConventions(self.handle, count) result = {} for i in xrange(0, count.value): - obj = callingconvention.CallingConvention(None, core.BNNewCallingConventionReference(cc[i])) + obj = callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i])) result[obj.name] = obj core.BNFreeCallingConventionList(cc, count) return result diff --git a/python/callingconvention.py b/python/callingconvention.py index e029a6aa..e9825642 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -40,8 +40,10 @@ class CallingConvention(object): _registered_calling_conventions = [] - def __init__(self, arch, name, handle = None): + def __init__(self, arch=None, name=None, handle=None): if handle is None: + if arch is None or name is None: + raise ValueError("Must specify either handle or architecture and name") self.arch = arch self._pending_reg_lists = {} self._cb = core.BNCustomCallingConvention() diff --git a/python/platform.py b/python/platform.py index 9ba7625f..1c2fdcd3 100644 --- a/python/platform.py +++ b/python/platform.py @@ -132,7 +132,7 @@ class Platform(object): result = core.BNGetPlatformDefaultCallingConvention(self.handle) if result is None: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(handle=result) @default_calling_convention.setter def default_calling_convention(self, value): @@ -150,7 +150,7 @@ class Platform(object): result = core.BNGetPlatformCdeclCallingConvention(self.handle) if result is None: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(handle=result) @cdecl_calling_convention.setter def cdecl_calling_convention(self, value): @@ -168,7 +168,7 @@ class Platform(object): result = core.BNGetPlatformStdcallCallingConvention(self.handle) if result is None: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(handle=result) @stdcall_calling_convention.setter def stdcall_calling_convention(self, value): @@ -186,7 +186,7 @@ class Platform(object): result = core.BNGetPlatformFastcallCallingConvention(self.handle) if result is None: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(handle=result) @fastcall_calling_convention.setter def fastcall_calling_convention(self, value): @@ -204,7 +204,7 @@ class Platform(object): result = core.BNGetPlatformSystemCallConvention(self.handle) if result is None: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(handle=result) @system_call_convention.setter def system_call_convention(self, value): @@ -222,7 +222,7 @@ class Platform(object): cc = core.BNGetPlatformCallingConventions(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(callingconvention.CallingConvention(None, core.BNNewCallingConventionReference(cc[i]))) + result.append(callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i]))) core.BNFreeCallingConventionList(cc, count.value) return result diff --git a/python/types.py b/python/types.py index f8e416f4..84f38c91 100644 --- a/python/types.py +++ b/python/types.py @@ -274,7 +274,7 @@ class Type(object): result = core.BNGetTypeCallingConvention(self.handle) if result is None: return None - return callingconvention.CallingConvention(None, result) + return callingconvention.CallingConvention(handle=result) @property def parameters(self): @@ -746,7 +746,7 @@ class TypeParserResult(object): self.functions = functions def __repr__(self): - return "{types: %s, variables: %s, functions: %s}" % (self.types, self.variables, self.functions) + return "" % (self.types, self.variables, self.functions) def preprocess_source(source, filename=None, include_dirs=[]): -- cgit v1.3.1 From bf9d72bbae638a42f0b93a9053dffcb1f5e79ff3 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 18 Jul 2017 00:20:01 -0400 Subject: Add instruction for indirect structure access --- binaryninjaapi.h | 1 + binaryninjacore.h | 5 +++++ python/mediumlevelil.py | 4 ++++ python/types.py | 5 +++++ type.cpp | 6 ++++++ 5 files changed, 21 insertions(+) (limited to 'python/types.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 20752370..4f46cd44 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1842,6 +1842,7 @@ namespace BinaryNinja void SetTypeName(const QualifiedName& name); uint64_t GetElementCount() const; + uint64_t GetOffset() const; void SetFunctionCanReturn(const Confidence& canReturn); diff --git a/binaryninjacore.h b/binaryninjacore.h index e601cd1c..2b758a94 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -726,7 +726,9 @@ extern "C" MLIL_SET_VAR_FIELD, // Not valid in SSA form (see MLIL_SET_VAR_FIELD) MLIL_SET_VAR_SPLIT, // Not valid in SSA form (see MLIL_SET_VAR_SPLIT_SSA) MLIL_LOAD, // Not valid in SSA form (see MLIL_LOAD_SSA) + MLIL_LOAD_STRUCT, // Not valid in SSA form (see MLIL_LOAD_STRUCT_SSA) MLIL_STORE, // Not valid in SSA form (see MLIL_STORE_SSA) + MLIL_STORE_STRUCT, // Not valid in SSA form (see MLIL_STORE_STRUCT_SSA) MLIL_VAR, // Not valid in SSA form (see MLIL_VAR_SSA) MLIL_VAR_FIELD, // Not valid in SSA form (see MLIL_VAR_SSA_FIELD) MLIL_ADDRESS_OF, @@ -811,7 +813,9 @@ extern "C" MLIL_CALL_PARAM_SSA, // Only valid within the MLIL_CALL_SSA, MLIL_SYSCALL_SSA family instructions MLIL_CALL_OUTPUT_SSA, // Only valid within the MLIL_CALL_SSA or MLIL_SYSCALL_SSA family instructions MLIL_LOAD_SSA, + MLIL_LOAD_STRUCT_SSA, MLIL_STORE_SSA, + MLIL_STORE_STRUCT_SSA, MLIL_VAR_PHI, MLIL_MEM_PHI }; @@ -2534,6 +2538,7 @@ extern "C" BINARYNINJACOREAPI BNEnumeration* BNGetTypeEnumeration(BNType* type); BINARYNINJACOREAPI BNNamedTypeReference* BNGetTypeNamedTypeReference(BNType* type); BINARYNINJACOREAPI uint64_t BNGetTypeElementCount(BNType* type); + BINARYNINJACOREAPI uint64_t BNGetTypeOffset(BNType* type); BINARYNINJACOREAPI void BNSetFunctionCanReturn(BNType* type, BNBoolWithConfidence* canReturn); BINARYNINJACOREAPI BNMemberScopeWithConfidence BNTypeGetMemberScope(BNType* type); BINARYNINJACOREAPI void BNTypeSetMemberScope(BNType* type, BNMemberScopeWithConfidence* scope); diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 8a8d8d0b..ba83f7aa 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -71,7 +71,9 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_SET_VAR_FIELD: [("dest", "var"), ("offset", "int"), ("src", "expr")], MediumLevelILOperation.MLIL_SET_VAR_SPLIT: [("high", "var"), ("low", "var"), ("src", "expr")], MediumLevelILOperation.MLIL_LOAD: [("src", "expr")], + MediumLevelILOperation.MLIL_LOAD_STRUCT: [("src", "expr"), ("offset", "int")], MediumLevelILOperation.MLIL_STORE: [("dest", "expr"), ("src", "expr")], + MediumLevelILOperation.MLIL_STORE_STRUCT: [("dest", "expr"), ("offset", "int"), ("src", "expr")], MediumLevelILOperation.MLIL_VAR: [("src", "var")], MediumLevelILOperation.MLIL_VAR_FIELD: [("src", "var"), ("offset", "int")], MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], @@ -154,7 +156,9 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "var_ssa_list")], MediumLevelILOperation.MLIL_CALL_PARAM_SSA: [("src_memory", "int"), ("src", "var_ssa_list")], MediumLevelILOperation.MLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")], + MediumLevelILOperation.MLIL_LOAD_STRUCT_SSA: [("src", "expr"), ("offset", "int"), ("src_memory", "int")], MediumLevelILOperation.MLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], + MediumLevelILOperation.MLIL_STORE_STRUCT_SSA: [("dest", "expr"), ("offset", "int"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], MediumLevelILOperation.MLIL_VAR_PHI: [("dest", "var_ssa"), ("src", "var_ssa_list")], MediumLevelILOperation.MLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")] } diff --git a/python/types.py b/python/types.py index 5933661a..ab3fb337 100644 --- a/python/types.py +++ b/python/types.py @@ -332,6 +332,11 @@ class Type(object): """Type count (read-only)""" return core.BNGetTypeElementCount(self.handle) + @property + def offset(self): + """Offset into structure (read-only)""" + return core.BNGetTypeOffset(self.handle) + def __str__(self): return core.BNGetTypeString(self.handle) diff --git a/type.cpp b/type.cpp index 837b212d..19624cdd 100644 --- a/type.cpp +++ b/type.cpp @@ -414,6 +414,12 @@ uint64_t Type::GetElementCount() const } +uint64_t Type::GetOffset() const +{ + return BNGetTypeOffset(m_object); +} + + string Type::GetString() const { char* str = BNGetTypeString(m_object); -- cgit v1.3.1 From ec2d882e1a165b703e8fedaa81246dcdd91f50f3 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 15 Aug 2017 00:24:03 -0400 Subject: Add APIs to access and update portions of the function type, and added new APIs for global registers and implicit incoming state in calling conventions --- architecture.cpp | 40 +++++++ binaryninjaapi.h | 66 ++++++++++-- binaryninjacore.h | 57 ++++++++-- callingconvention.cpp | 97 +++++++++++++++++ function.cpp | 202 +++++++++++++++++++++++++++++++++++- mediumlevelilinstruction.h | 3 + python/architecture.py | 25 +++++ python/callingconvention.py | 87 ++++++++++++++++ python/function.py | 247 ++++++++++++++++++++++++++++++++++++++++++-- python/types.py | 18 +++- type.cpp | 15 ++- 11 files changed, 822 insertions(+), 35 deletions(-) (limited to 'python/types.py') diff --git a/architecture.cpp b/architecture.cpp index 3e82ffd3..8fd38de2 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -346,6 +346,19 @@ uint32_t Architecture::GetLinkRegisterCallback(void* ctxt) } +uint32_t* Architecture::GetGlobalRegistersCallback(void* ctxt, size_t* count) +{ + Architecture* arch = (Architecture*)ctxt; + vector regs = arch->GetGlobalRegisters(); + *count = regs.size(); + + uint32_t* result = new uint32_t[regs.size()]; + for (size_t i = 0; i < regs.size(); i++) + result[i] = regs[i]; + return result; +} + + bool Architecture::AssembleCallback(void* ctxt, const char* code, uint64_t addr, BNDataBuffer* result, char** errors) { Architecture* arch = (Architecture*)ctxt; @@ -453,6 +466,7 @@ void Architecture::Register(Architecture* arch) callbacks.getRegisterInfo = GetRegisterInfoCallback; callbacks.getStackPointerRegister = GetStackPointerRegisterCallback; callbacks.getLinkRegister = GetLinkRegisterCallback; + callbacks.getGlobalRegisters = GetGlobalRegistersCallback; callbacks.assemble = AssembleCallback; callbacks.isNeverBranchPatchAvailable = IsNeverBranchPatchAvailableCallback; callbacks.isAlwaysBranchPatchAvailable = IsAlwaysBranchPatchAvailableCallback; @@ -656,6 +670,18 @@ uint32_t Architecture::GetLinkRegister() } +vector Architecture::GetGlobalRegisters() +{ + return vector(); +} + + +bool Architecture::IsGlobalRegister(uint32_t reg) +{ + return BNIsArchitectureGlobalRegister(m_object, reg); +} + + vector Architecture::GetModifiedRegistersOnWrite(uint32_t reg) { size_t count; @@ -1161,6 +1187,20 @@ uint32_t CoreArchitecture::GetLinkRegister() } +vector CoreArchitecture::GetGlobalRegisters() +{ + size_t count; + uint32_t* regs = BNGetArchitectureGlobalRegisters(m_object, &count); + + vector result; + for (size_t i = 0; i < count; i++) + result.push_back(regs[i]); + + BNFreeRegisterList(regs); + return result; +} + + bool CoreArchitecture::Assemble(const string& code, uint64_t addr, DataBuffer& result, string& errors) { char* errorStr = nullptr; diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 9a61a9cb..63cab888 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -300,7 +300,17 @@ namespace BinaryNinja { } + static uint8_t Combine(uint8_t a, uint8_t b) + { + uint8_t result = (uint8_t)(((uint32_t)a * (uint32_t)b) / BN_FULL_CONFIDENCE); + if ((a >= BN_MINIMUM_CONFIDENCE) && (b >= BN_MINIMUM_CONFIDENCE) && + (result < BN_MINIMUM_CONFIDENCE)) + result = BN_MINIMUM_CONFIDENCE; + return result; + } + uint8_t GetConfidence() const { return m_confidence; } + uint8_t GetCombinedConfidence(uint8_t base) const { return Combine(m_confidence, base); } void SetConfidence(uint8_t conf) { m_confidence = conf; } bool IsUnknown() const { return m_confidence == 0; } }; @@ -331,8 +341,12 @@ namespace BinaryNinja T* operator->() { return &m_value; } const T* operator->() const { return &m_value; } - T& GetValue() { return m_value; } - const T& GetValue() const { return m_value; } + // This MUST be a copy. There are subtle compiler scoping bugs that will cause nondeterministic failures + // when using one of these objects as a temporary if a reference is returned here. Unfortunately, this has + // negative performance implications. Make a local copy first if the template argument is a complex + // object and it is needed repeatedly. + T GetValue() const { return m_value; } + void SetValue(const T& value) { m_value = value; } Confidence& operator=(const Confidence& v) @@ -1584,6 +1598,7 @@ namespace BinaryNinja static void GetRegisterInfoCallback(void* ctxt, uint32_t reg, BNRegisterInfo* result); static uint32_t GetStackPointerRegisterCallback(void* ctxt); static uint32_t GetLinkRegisterCallback(void* ctxt); + static uint32_t* GetGlobalRegistersCallback(void* ctxt, size_t* count); static bool AssembleCallback(void* ctxt, const char* code, uint64_t addr, BNDataBuffer* result, char** errors); static bool IsNeverBranchPatchAvailableCallback(void* ctxt, const uint8_t* data, uint64_t addr, size_t len); @@ -1646,6 +1661,8 @@ namespace BinaryNinja virtual BNRegisterInfo GetRegisterInfo(uint32_t reg); virtual uint32_t GetStackPointerRegister(); virtual uint32_t GetLinkRegister(); + virtual std::vector GetGlobalRegisters(); + bool IsGlobalRegister(uint32_t reg); std::vector GetModifiedRegistersOnWrite(uint32_t reg); uint32_t GetRegisterByName(const std::string& name); @@ -1784,6 +1801,7 @@ namespace BinaryNinja virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override; virtual uint32_t GetStackPointerRegister() override; virtual uint32_t GetLinkRegister() override; + virtual std::vector GetGlobalRegisters() override; virtual bool Assemble(const std::string& code, uint64_t addr, DataBuffer& result, std::string& errors) override; @@ -1831,7 +1849,7 @@ namespace BinaryNinja Confidence> GetChildType() const; Confidence> GetCallingConvention() const; std::vector GetParameters() const; - bool HasVariableArguments() const; + Confidence HasVariableArguments() const; Confidence CanReturn() const; Ref GetStructure() const; Ref GetEnumeration() const; @@ -1879,7 +1897,7 @@ namespace BinaryNinja static Ref ArrayType(const Confidence>& type, uint64_t elem); static Ref FunctionType(const Confidence>& returnValue, const Confidence>& callingConvention, - const std::vector& params, bool varArg = false); + const std::vector& params, const Confidence& varArg = Confidence(false, 0)); static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name); static std::string GenerateAutoDemangledTypeId(const QualifiedName& name); @@ -2097,7 +2115,9 @@ namespace BinaryNinja BNRegisterValueType state; int64_t value; - static RegisterValue FromAPIObject(BNRegisterValue& value); + RegisterValue(); + static RegisterValue FromAPIObject(const BNRegisterValue& value); + BNRegisterValue ToAPIObject(); }; struct PossibleValueSet @@ -2127,7 +2147,7 @@ namespace BinaryNinja uint64_t GetStart() const; Ref GetSymbol() const; bool WasAutomaticallyDiscovered() const; - bool CanReturn() const; + Confidence CanReturn() const; bool HasExplicitlyDefinedType() const; bool NeedsUpdate() const; @@ -2163,8 +2183,25 @@ namespace BinaryNinja Ref GetMediumLevelIL() const; Ref GetType() const; + Confidence> GetReturnType() const; + Confidence> GetCallingConvention() const; + Confidence> GetParameterVariables() const; + Confidence HasVariableArguments() const; + void SetAutoType(Type* type); + void SetAutoReturnType(const Confidence>& type); + void SetAutoCallingConvention(const Confidence>& convention); + void SetAutoParameterVariables(const Confidence>& vars); + void SetAutoHasVariableArguments(const Confidence& varArgs); + void SetAutoCanReturn(const Confidence& returns); + void SetUserType(Type* type); + void SetReturnType(const Confidence>& type); + void SetCallingConvention(const Confidence>& convention); + void SetParameterVariables(const Confidence>& vars); + void SetHasVariableArguments(const Confidence& varArgs); + void SetCanReturn(const Confidence& returns); + void ApplyImportedTypes(Symbol* sym); void ApplyAutoDiscoveredType(Type* type); @@ -2223,6 +2260,8 @@ namespace BinaryNinja void ReleaseAdvancedAnalysisData(size_t count); std::map GetAnalysisPerformanceInfo(); + + std::vector GetTypeTokens(DisassemblySettings* settings = nullptr); }; class AdvancedFunctionAnalysisDataRequestor @@ -3036,6 +3075,11 @@ namespace BinaryNinja static uint32_t GetIntegerReturnValueRegisterCallback(void* ctxt); static uint32_t GetHighIntegerReturnValueRegisterCallback(void* ctxt); static uint32_t GetFloatReturnValueRegisterCallback(void* ctxt); + static uint32_t GetGlobalPointerRegisterCallback(void* ctxt); + + static uint32_t* GetImplicitlyDefinedRegistersCallback(void* ctxt, size_t* count); + static BNRegisterValue GetIncomingRegisterValueCallback(void* ctxt, uint32_t reg, BNFunction* func); + static BNRegisterValue GetIncomingFlagValueCallback(void* ctxt, uint32_t reg, BNFunction* func); public: Ref GetArchitecture() const; @@ -3051,6 +3095,11 @@ namespace BinaryNinja virtual uint32_t GetIntegerReturnValueRegister() = 0; virtual uint32_t GetHighIntegerReturnValueRegister(); virtual uint32_t GetFloatReturnValueRegister(); + virtual uint32_t GetGlobalPointerRegister(); + + virtual std::vector GetImplicitlyDefinedRegisters(); + virtual RegisterValue GetIncomingRegisterValue(uint32_t reg, Function* func); + virtual RegisterValue GetIncomingFlagValue(uint32_t flag, Function* func); }; class CoreCallingConvention: public CallingConvention @@ -3068,6 +3117,11 @@ namespace BinaryNinja virtual uint32_t GetIntegerReturnValueRegister() override; virtual uint32_t GetHighIntegerReturnValueRegister() override; virtual uint32_t GetFloatReturnValueRegister() override; + virtual uint32_t GetGlobalPointerRegister() override; + + virtual std::vector GetImplicitlyDefinedRegisters() override; + virtual RegisterValue GetIncomingRegisterValue(uint32_t reg, Function* func) override; + virtual RegisterValue GetIncomingFlagValue(uint32_t flag, Function* func) override; }; /*! diff --git a/binaryninjacore.h b/binaryninjacore.h index 22980067..6b5d5acc 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -92,7 +92,9 @@ #define BN_MAX_VARIABLE_OFFSET 0x7fffffffffLL #define BN_MAX_VARIABLE_INDEX 0xfffff -#define BN_FULL_CONFIDENCE 255 +#define BN_FULL_CONFIDENCE 255 +#define BN_MINIMUM_CONFIDENCE 1 +#define BN_HEURISTIC_CONFIDENCE 192 #ifdef __cplusplus extern "C" @@ -230,8 +232,7 @@ extern "C" NoTokenContext = 0, LocalVariableTokenContext = 1, DataVariableTokenContext = 2, - FunctionReturnTokenContext = 3, - ArgumentTokenContext = 4 + FunctionReturnTokenContext = 3 }; enum BNLinearDisassemblyLineType @@ -419,6 +420,7 @@ extern "C" ShowVariablesAtTopOfGraph = 3, ShowVariableTypesWhenAssigned = 4, ShowDefaultRegisterTypes = 5, + ShowCallParameterNames = 6, // Linear disassembly options GroupLinearDisassemblyFunctions = 64, @@ -1015,6 +1017,7 @@ extern "C" void (*getRegisterInfo)(void* ctxt, uint32_t reg, BNRegisterInfo* result); uint32_t (*getStackPointerRegister)(void* ctxt); uint32_t (*getLinkRegister)(void* ctxt); + uint32_t* (*getGlobalRegisters)(void* ctxt, size_t* count); bool (*assemble)(void* ctxt, const char* code, uint64_t addr, BNDataBuffer* result, char** errors); @@ -1122,6 +1125,13 @@ extern "C" uint8_t confidence; }; + struct BNParameterVariablesWithConfidence + { + BNVariable* vars; + size_t count; + uint8_t confidence; + }; + struct BNNameAndType { char* name; @@ -1235,6 +1245,11 @@ extern "C" uint32_t (*getIntegerReturnValueRegister)(void* ctxt); uint32_t (*getHighIntegerReturnValueRegister)(void* ctxt); uint32_t (*getFloatReturnValueRegister)(void* ctxt); + uint32_t (*getGlobalPointerRegister)(void* ctxt); + + uint32_t* (*getImplicitlyDefinedRegisters)(void* ctxt, size_t* count); + BNRegisterValue (*getIncomingRegisterValue)(void* ctxt, uint32_t reg, BNFunction* func); + BNRegisterValue (*getIncomingFlagValue)(void* ctxt, uint32_t flag, BNFunction* func); }; struct BNVariableNameAndType @@ -1922,6 +1937,8 @@ extern "C" BINARYNINJACOREAPI BNRegisterInfo BNGetArchitectureRegisterInfo(BNArchitecture* arch, uint32_t reg); BINARYNINJACOREAPI uint32_t BNGetArchitectureStackPointerRegister(BNArchitecture* arch); BINARYNINJACOREAPI uint32_t BNGetArchitectureLinkRegister(BNArchitecture* arch); + BINARYNINJACOREAPI uint32_t* BNGetArchitectureGlobalRegisters(BNArchitecture* arch, size_t* count); + BINARYNINJACOREAPI bool BNIsArchitectureGlobalRegister(BNArchitecture* arch, uint32_t reg); BINARYNINJACOREAPI uint32_t BNGetArchitectureRegisterByName(BNArchitecture* arch, const char* name); BINARYNINJACOREAPI bool BNAssemble(BNArchitecture* arch, const char* code, uint64_t addr, BNDataBuffer* result, char** errors); @@ -1982,7 +1999,7 @@ extern "C" BINARYNINJACOREAPI uint64_t BNGetFunctionStart(BNFunction* func); BINARYNINJACOREAPI BNSymbol* BNGetFunctionSymbol(BNFunction* func); BINARYNINJACOREAPI bool BNWasFunctionAutomaticallyDiscovered(BNFunction* func); - BINARYNINJACOREAPI bool BNCanFunctionReturn(BNFunction* func); + BINARYNINJACOREAPI BNBoolWithConfidence BNCanFunctionReturn(BNFunction* func); BINARYNINJACOREAPI void BNSetFunctionAutoType(BNFunction* func, BNType* type); BINARYNINJACOREAPI void BNSetFunctionUserType(BNFunction* func, BNType* type); @@ -2038,10 +2055,31 @@ extern "C" BINARYNINJACOREAPI uint32_t* BNGetFlagsWrittenByLiftedILInstruction(BNFunction* func, size_t i, size_t* count); BINARYNINJACOREAPI BNType* BNGetFunctionType(BNFunction* func); + BINARYNINJACOREAPI BNTypeWithConfidence BNGetFunctionReturnType(BNFunction* func); + BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetFunctionCallingConvention(BNFunction* func); + BINARYNINJACOREAPI BNParameterVariablesWithConfidence BNGetFunctionParameterVariables(BNFunction* func); + BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars); + BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionHasVariableArguments(BNFunction* func); + + BINARYNINJACOREAPI void BNSetAutoFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); + BINARYNINJACOREAPI void BNSetAutoFunctionCallingConvention(BNFunction* func, BNCallingConventionWithConfidence* convention); + BINARYNINJACOREAPI void BNSetAutoFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); + BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); + BINARYNINJACOREAPI void BNSetAutoFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); + + BINARYNINJACOREAPI void BNSetUserFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); + BINARYNINJACOREAPI void BNSetUserFunctionCallingConvention(BNFunction* func, BNCallingConventionWithConfidence* convention); + BINARYNINJACOREAPI void BNSetUserFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); + BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); + BINARYNINJACOREAPI void BNSetUserFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); + BINARYNINJACOREAPI void BNApplyImportedTypes(BNFunction* func, BNSymbol* sym); BINARYNINJACOREAPI void BNApplyAutoDiscoveredFunctionType(BNFunction* func, BNType* type); BINARYNINJACOREAPI bool BNFunctionHasExplicitlyDefinedType(BNFunction* func); + BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFunctionTypeTokens(BNFunction* func, + BNDisassemblySettings* settings, size_t* count); + BINARYNINJACOREAPI BNFunction* BNGetBasicBlockFunction(BNBasicBlock* block); BINARYNINJACOREAPI BNArchitecture* BNGetBasicBlockArchitecture(BNBasicBlock* block); BINARYNINJACOREAPI uint64_t BNGetBasicBlockStart(BNBasicBlock* block); @@ -2565,7 +2603,7 @@ extern "C" BINARYNINJACOREAPI BNType* BNCreateArrayType(BNTypeWithConfidence* type, uint64_t elem); BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNTypeWithConfidence* returnValue, BNCallingConventionWithConfidence* callingConvention, BNNameAndType* params, - size_t paramCount, bool varArg); + size_t paramCount, BNBoolWithConfidence* varArg); BINARYNINJACOREAPI BNType* BNNewTypeReference(BNType* type); BINARYNINJACOREAPI BNType* BNDuplicateType(BNType* type); BINARYNINJACOREAPI char* BNGetTypeAndName(BNType* type, BNQualifiedName* name); @@ -2584,14 +2622,14 @@ extern "C" BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetTypeCallingConvention(BNType* type); BINARYNINJACOREAPI BNNameAndType* BNGetTypeParameters(BNType* type, size_t* count); BINARYNINJACOREAPI void BNFreeTypeParameterList(BNNameAndType* types, size_t count); - BINARYNINJACOREAPI bool BNTypeHasVariableArguments(BNType* type); + BINARYNINJACOREAPI BNBoolWithConfidence BNTypeHasVariableArguments(BNType* type); BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionTypeCanReturn(BNType* type); BINARYNINJACOREAPI BNStructure* BNGetTypeStructure(BNType* type); BINARYNINJACOREAPI BNEnumeration* BNGetTypeEnumeration(BNType* type); BINARYNINJACOREAPI BNNamedTypeReference* BNGetTypeNamedTypeReference(BNType* type); BINARYNINJACOREAPI uint64_t BNGetTypeElementCount(BNType* type); BINARYNINJACOREAPI uint64_t BNGetTypeOffset(BNType* type); - BINARYNINJACOREAPI void BNSetFunctionCanReturn(BNType* type, BNBoolWithConfidence* canReturn); + BINARYNINJACOREAPI void BNSetFunctionTypeCanReturn(BNType* type, BNBoolWithConfidence* canReturn); BINARYNINJACOREAPI BNMemberScopeWithConfidence BNTypeGetMemberScope(BNType* type); BINARYNINJACOREAPI void BNTypeSetMemberScope(BNType* type, BNMemberScopeWithConfidence* scope); BINARYNINJACOREAPI BNMemberAccessWithConfidence BNTypeGetMemberAccess(BNType* type); @@ -2745,6 +2783,11 @@ extern "C" BINARYNINJACOREAPI uint32_t BNGetIntegerReturnValueRegister(BNCallingConvention* cc); BINARYNINJACOREAPI uint32_t BNGetHighIntegerReturnValueRegister(BNCallingConvention* cc); BINARYNINJACOREAPI uint32_t BNGetFloatReturnValueRegister(BNCallingConvention* cc); + BINARYNINJACOREAPI uint32_t BNGetGlobalPointerRegister(BNCallingConvention* cc); + + BINARYNINJACOREAPI uint32_t* BNGetImplicitlyDefinedRegisters(BNCallingConvention* cc, size_t* count); + BINARYNINJACOREAPI BNRegisterValue BNGetIncomingRegisterValue(BNCallingConvention* cc, uint32_t reg, BNFunction* func); + BINARYNINJACOREAPI BNRegisterValue BNGetIncomingFlagValue(BNCallingConvention* cc, uint32_t reg, BNFunction* func); BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureDefaultCallingConvention(BNArchitecture* arch); BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureCdeclCallingConvention(BNArchitecture* arch); diff --git a/callingconvention.cpp b/callingconvention.cpp index fb5ed73f..b0783ad6 100644 --- a/callingconvention.cpp +++ b/callingconvention.cpp @@ -44,6 +44,10 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name) cc.getIntegerReturnValueRegister = GetIntegerReturnValueRegisterCallback; cc.getHighIntegerReturnValueRegister = GetHighIntegerReturnValueRegisterCallback; cc.getFloatReturnValueRegister = GetFloatReturnValueRegisterCallback; + cc.getGlobalPointerRegister = GetGlobalPointerRegisterCallback; + cc.getImplicitlyDefinedRegisters = GetImplicitlyDefinedRegistersCallback; + cc.getIncomingRegisterValue = GetIncomingRegisterValueCallback; + cc.getIncomingFlagValue = GetIncomingFlagValueCallback; AddRefForRegistration(); m_object = BNCreateCallingConvention(arch->GetObject(), name.c_str(), &cc); @@ -137,6 +141,46 @@ uint32_t CallingConvention::GetFloatReturnValueRegisterCallback(void* ctxt) } +uint32_t CallingConvention::GetGlobalPointerRegisterCallback(void* ctxt) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + return cc->GetGlobalPointerRegister(); +} + + +uint32_t* CallingConvention::GetImplicitlyDefinedRegistersCallback(void* ctxt, size_t* count) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + vector regs = cc->GetImplicitlyDefinedRegisters(); + *count = regs.size(); + + uint32_t* result = new uint32_t[regs.size()]; + for (size_t i = 0; i < regs.size(); i++) + result[i] = regs[i]; + return result; +} + + +BNRegisterValue CallingConvention::GetIncomingRegisterValueCallback(void* ctxt, uint32_t reg, BNFunction* func) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + Ref funcObj; + if (func) + funcObj = new Function(BNNewFunctionReference(func)); + return cc->GetIncomingRegisterValue(reg, funcObj).ToAPIObject(); +} + + +BNRegisterValue CallingConvention::GetIncomingFlagValueCallback(void* ctxt, uint32_t reg, BNFunction* func) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + Ref funcObj; + if (func) + funcObj = new Function(BNNewFunctionReference(func)); + return cc->GetIncomingFlagValue(reg, funcObj).ToAPIObject(); +} + + Ref CallingConvention::GetArchitecture() const { return new CoreArchitecture(BNGetCallingConventionArchitecture(m_object)); @@ -194,6 +238,30 @@ uint32_t CallingConvention::GetFloatReturnValueRegister() } +uint32_t CallingConvention::GetGlobalPointerRegister() +{ + return BN_INVALID_REGISTER; +} + + +vector CallingConvention::GetImplicitlyDefinedRegisters() +{ + return vector(); +} + + +RegisterValue CallingConvention::GetIncomingRegisterValue(uint32_t, Function*) +{ + return RegisterValue(); +} + + +RegisterValue CallingConvention::GetIncomingFlagValue(uint32_t, Function*) +{ + return RegisterValue(); +} + + CoreCallingConvention::CoreCallingConvention(BNCallingConvention* cc): CallingConvention(cc) { } @@ -260,3 +328,32 @@ uint32_t CoreCallingConvention::GetFloatReturnValueRegister() { return BNGetFloatReturnValueRegister(m_object); } + + +uint32_t CoreCallingConvention::GetGlobalPointerRegister() +{ + return BNGetGlobalPointerRegister(m_object); +} + + +vector CoreCallingConvention::GetImplicitlyDefinedRegisters() +{ + size_t count; + uint32_t* regs = BNGetImplicitlyDefinedRegisters(m_object, &count); + vector result; + result.insert(result.end(), regs, ®s[count]); + BNFreeRegisterList(regs); + return result; +} + + +RegisterValue CoreCallingConvention::GetIncomingRegisterValue(uint32_t reg, Function* func) +{ + return RegisterValue::FromAPIObject(BNGetIncomingRegisterValue(m_object, reg, func ? func->GetObject() : nullptr)); +} + + +RegisterValue CoreCallingConvention::GetIncomingFlagValue(uint32_t flag, Function* func) +{ + return RegisterValue::FromAPIObject(BNGetIncomingFlagValue(m_object, flag, func ? func->GetObject() : nullptr)); +} diff --git a/function.cpp b/function.cpp index 66b2aade..976d73d2 100644 --- a/function.cpp +++ b/function.cpp @@ -91,6 +91,20 @@ Variable Variable::FromIdentifier(uint64_t id) } +RegisterValue::RegisterValue(): state(UndeterminedValue), value(0) +{ +} + + +BNRegisterValue RegisterValue::ToAPIObject() +{ + BNRegisterValue result; + result.state = state; + result.value = value; + return result; +} + + Function::Function(BNFunction* func) { m_object = func; @@ -135,9 +149,10 @@ bool Function::WasAutomaticallyDiscovered() const } -bool Function::CanReturn() const +Confidence Function::CanReturn() const { - return BNCanFunctionReturn(m_object); + BNBoolWithConfidence bc = BNCanFunctionReturn(m_object); + return Confidence(bc.value, bc.confidence); } @@ -233,7 +248,7 @@ vector Function::GetLowLevelILExitsForInstruction(Architecture* arch, ui } -RegisterValue RegisterValue::FromAPIObject(BNRegisterValue& value) +RegisterValue RegisterValue::FromAPIObject(const BNRegisterValue& value) { RegisterValue result; result.state = value.state; @@ -452,18 +467,167 @@ Ref Function::GetType() const } +Confidence> Function::GetReturnType() const +{ + BNTypeWithConfidence tc = BNGetFunctionReturnType(m_object); + Ref type = tc.type ? new Type(tc.type) : nullptr; + return Confidence>(type, tc.confidence); +} + + +Confidence> Function::GetCallingConvention() const +{ + BNCallingConventionWithConfidence cc = BNGetFunctionCallingConvention(m_object); + Ref convention = cc.convention ? new CoreCallingConvention(cc.convention) : nullptr; + return Confidence>(convention, cc.confidence); +} + + +Confidence> Function::GetParameterVariables() const +{ + BNParameterVariablesWithConfidence vars = BNGetFunctionParameterVariables(m_object); + vector varList; + for (size_t i = 0; i < vars.count; i++) + { + Variable var; + var.type = vars.vars[i].type; + var.index = vars.vars[i].index; + var.storage = vars.vars[i].storage; + varList.push_back(var); + } + Confidence> result(varList, vars.confidence); + BNFreeParameterVariables(&vars); + return result; +} + + +Confidence Function::HasVariableArguments() const +{ + BNBoolWithConfidence bc = BNFunctionHasVariableArguments(m_object); + return Confidence(bc.value, bc.confidence); +} + + void Function::SetAutoType(Type* type) { BNSetFunctionAutoType(m_object, type->GetObject()); } +void Function::SetAutoReturnType(const Confidence>& type) +{ + BNTypeWithConfidence tc; + tc.type = type ? type->GetObject() : nullptr; + tc.confidence = type.GetConfidence(); + BNSetAutoFunctionReturnType(m_object, &tc); +} + + +void Function::SetAutoCallingConvention(const Confidence>& convention) +{ + BNCallingConventionWithConfidence cc; + cc.convention = convention ? convention->GetObject() : nullptr; + cc.confidence = convention.GetConfidence(); + BNSetAutoFunctionCallingConvention(m_object, &cc); +} + + +void Function::SetAutoParameterVariables(const Confidence>& vars) +{ + BNParameterVariablesWithConfidence varConf; + varConf.vars = new BNVariable[vars.GetValue().size()]; + varConf.count = vars.GetValue().size(); + for (size_t i = 0; i < vars.GetValue().size(); i++) + { + varConf.vars[i].type = vars.GetValue()[i].type; + varConf.vars[i].index = vars.GetValue()[i].index; + varConf.vars[i].storage = vars.GetValue()[i].storage; + } + varConf.confidence = vars.GetConfidence(); + + BNSetAutoFunctionParameterVariables(m_object, &varConf); + delete[] varConf.vars; +} + + +void Function::SetAutoHasVariableArguments(const Confidence& varArgs) +{ + BNBoolWithConfidence bc; + bc.value = varArgs.GetValue(); + bc.confidence = varArgs.GetConfidence(); + BNSetAutoFunctionHasVariableArguments(m_object, &bc); +} + + +void Function::SetAutoCanReturn(const Confidence& returns) +{ + BNBoolWithConfidence bc; + bc.value = returns.GetValue(); + bc.confidence = returns.GetConfidence(); + BNSetAutoFunctionCanReturn(m_object, &bc); +} + + void Function::SetUserType(Type* type) { BNSetFunctionUserType(m_object, type->GetObject()); } +void Function::SetReturnType(const Confidence>& type) +{ + BNTypeWithConfidence tc; + tc.type = type ? type->GetObject() : nullptr; + tc.confidence = type.GetConfidence(); + BNSetUserFunctionReturnType(m_object, &tc); +} + + +void Function::SetCallingConvention(const Confidence>& convention) +{ + BNCallingConventionWithConfidence cc; + cc.convention = convention ? convention->GetObject() : nullptr; + cc.confidence = convention.GetConfidence(); + BNSetUserFunctionCallingConvention(m_object, &cc); +} + + +void Function::SetParameterVariables(const Confidence>& vars) +{ + BNParameterVariablesWithConfidence varConf; + varConf.vars = new BNVariable[vars.GetValue().size()]; + varConf.count = vars.GetValue().size(); + for (size_t i = 0; i < vars.GetValue().size(); i++) + { + varConf.vars[i].type = vars.GetValue()[i].type; + varConf.vars[i].index = vars.GetValue()[i].index; + varConf.vars[i].storage = vars.GetValue()[i].storage; + } + varConf.confidence = vars.GetConfidence(); + + BNSetUserFunctionParameterVariables(m_object, &varConf); + delete[] varConf.vars; +} + + +void Function::SetHasVariableArguments(const Confidence& varArgs) +{ + BNBoolWithConfidence bc; + bc.value = varArgs.GetValue(); + bc.confidence = varArgs.GetConfidence(); + BNSetUserFunctionHasVariableArguments(m_object, &bc); +} + + +void Function::SetCanReturn(const Confidence& returns) +{ + BNBoolWithConfidence bc; + bc.value = returns.GetValue(); + bc.confidence = returns.GetConfidence(); + BNSetUserFunctionCanReturn(m_object, &bc); +} + + void Function::ApplyImportedTypes(Symbol* sym) { BNApplyImportedTypes(m_object, sym->GetObject()); @@ -891,6 +1055,38 @@ map Function::GetAnalysisPerformanceInfo() } +vector Function::GetTypeTokens(DisassemblySettings* settings) +{ + size_t count; + BNDisassemblyTextLine* lines = BNGetFunctionTypeTokens(m_object, + settings ? settings->GetObject() : nullptr, &count); + + vector result; + for (size_t i = 0; i < count; i++) + { + DisassemblyTextLine line; + line.addr = lines[i].addr; + for (size_t j = 0; j < lines[i].count; j++) + { + InstructionTextToken token; + token.type = lines[i].tokens[j].type; + token.text = lines[i].tokens[j].text; + token.value = lines[i].tokens[j].value; + token.size = lines[i].tokens[j].size; + token.operand = lines[i].tokens[j].operand; + token.context = lines[i].tokens[j].context; + token.confidence = lines[i].tokens[j].confidence; + token.address = lines[i].tokens[j].address; + line.tokens.push_back(token); + } + result.push_back(line); + } + + BNFreeDisassemblyTextLines(lines, count); + return result; +} + + AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func) { if (m_func) diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h index ef5e7567..066259eb 100644 --- a/mediumlevelilinstruction.h +++ b/mediumlevelilinstruction.h @@ -521,6 +521,8 @@ namespace BinaryNinja template void SetParameterSSAVariables(const std::vector& vars) { As().SetParameterSSAVariables(vars); } template void SetParameterExprs(const std::vector& params) { As().SetParameterExprs(params); } template void SetParameterExprs(const std::vector& params) { As().SetParameterExprs(params); } + template void SetSourceExprs(const std::vector& params) { As().SetSourceExprs(params); } + template void SetSourceExprs(const std::vector& params) { As().SetSourceExprs(params); } bool GetOperandIndexForUsage(MediumLevelILOperandUsage usage, size_t& operandIndex) const; @@ -894,6 +896,7 @@ namespace BinaryNinja template <> struct MediumLevelILInstructionAccessor: public MediumLevelILInstructionBase { MediumLevelILInstructionList GetSourceExprs() const { return GetRawOperandAsExprList(0); } + void SetSourceExprs(const std::vector& exprs) { UpdateRawOperandAsExprList(0, exprs); } }; template <> struct MediumLevelILInstructionAccessor: public MediumLevelILInstructionBase diff --git a/python/architecture.py b/python/architecture.py index b5f56767..61559934 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -116,6 +116,7 @@ class Architecture(object): regs = {} stack_pointer = None link_reg = None + global_regs = [] flags = [] flag_write_types = [] flag_roles = {} @@ -208,6 +209,13 @@ class Architecture(object): core.BNFreeRegisterList(flags) self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flag_indexes self.__dict__["flags_written_by_flag_write_type"][write_type] = flag_names + + count = ctypes.c_ulonglong() + regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) + self.__dict__["global_regs"] = [] + for i in xrange(0, count.value): + self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) + core.BNFreeRegisterList(regs) else: startup._init_plugins() @@ -250,6 +258,7 @@ class Architecture(object): self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__( self._get_stack_pointer_register) self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register) + self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_registers) self._cb.assemble = self._cb.assemble.__class__(self._assemble) self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( self._is_never_branch_patch_available) @@ -330,6 +339,8 @@ class Architecture(object): flags.append(self._flags[flag]) self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flags + self.__dict__["global_regs"] = self.__class__.global_regs + self._pending_reg_lists = {} self._pending_token_lists = {} @@ -719,6 +730,20 @@ class Architecture(object): log.log_error(traceback.format_exc()) return 0 + def _get_global_registers(self, ctxt, count): + try: + count[0] = len(self.__class__.global_regs) + reg_buf = (ctypes.c_uint * len(self.__class__.global_regs))() + for i in xrange(0, len(self.__class__.global_regs)): + reg_buf[i] = self._all_regs[self.__class__.global_regs[i]] + result = ctypes.cast(reg_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, reg_buf) + return result.value + except KeyError: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + def _assemble(self, ctxt, code, addr, result, errors): try: data, error_str = self.perform_assemble(code, addr) diff --git a/python/callingconvention.py b/python/callingconvention.py index 21c8c95a..609c71b0 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -26,6 +26,8 @@ import _binaryninjacore as core import architecture import log import types +import function +import binaryview class CallingConvention(object): @@ -38,6 +40,8 @@ class CallingConvention(object): int_return_reg = None high_int_return_reg = None float_return_reg = None + global_pointer_reg = None + implicitly_defined_regs = [] _registered_calling_conventions = [] @@ -58,6 +62,10 @@ class CallingConvention(object): self._cb.getIntegerReturnValueRegister = self._cb.getIntegerReturnValueRegister.__class__(self._get_int_return_reg) self._cb.getHighIntegerReturnValueRegister = self._cb.getHighIntegerReturnValueRegister.__class__(self._get_high_int_return_reg) self._cb.getFloatReturnValueRegister = self._cb.getFloatReturnValueRegister.__class__(self._get_float_return_reg) + self._cb.getGlobalPointerRegister = self._cb.getGlobalPointerRegister.__class__(self._get_global_pointer_reg) + self._cb.getImplicitlyDefinedRegisters = self._cb.getImplicitlyDefinedRegisters.__class__(self._get_implicitly_defined_regs) + self._cb.getIncomingRegisterValue = self._cb.getIncomingRegisterValue.__class__(self._get_incoming_reg_value) + self._cb.getIncomingFlagValue = self._cb.getIncomingFlagValue.__class__(self._get_incoming_flag_value) self.handle = core.BNCreateCallingConvention(arch.handle, name, self._cb) self.__class__._registered_calling_conventions.append(self) else: @@ -112,6 +120,21 @@ class CallingConvention(object): else: self.__dict__["float_return_reg"] = self.arch.get_reg_name(reg) + reg = core.BNGetGlobalPointerRegister(self.handle) + if reg == 0xffffffff: + self.__dict__["global_pointer_reg"] = None + else: + self.__dict__["global_pointer_reg"] = self.arch.get_reg_name(reg) + + count = ctypes.c_ulonglong() + regs = core.BNGetImplicitlyDefinedRegisters(self.handle, count) + result = [] + arch = self.arch + for i in xrange(0, count.value): + result.append(arch.get_reg_name(regs[i])) + core.BNFreeRegisterList(regs, count.value) + self.__dict__["implicitly_defined_regs"] = result + self.confidence = confidence def __del__(self): @@ -220,12 +243,76 @@ class CallingConvention(object): log.log_error(traceback.format_exc()) return False + def _get_global_pointer_reg(self, ctxt): + try: + if self.__class__.global_pointer_reg is None: + return 0xffffffff + return self.arch.regs[self.__class__.global_pointer_reg].index + except: + log.log_error(traceback.format_exc()) + return False + + def _get_implicitly_defined_regs(self, ctxt, count): + try: + regs = self.__class__.implicitly_defined_regs + count[0] = len(regs) + reg_buf = (ctypes.c_uint * len(regs))() + for i in xrange(0, len(regs)): + reg_buf[i] = self.arch.regs[regs[i]].index + result = ctypes.cast(reg_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, reg_buf) + return result.value + except: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _get_incoming_reg_value(self, ctxt, reg, func): + try: + func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), + core.BNNewFunctionReference(func)) + reg_name = self.arch.get_reg_name(reg) + return self.perform_get_incoming_reg_value(reg_name, func_obj)._to_api_object() + except: + log.log_error(traceback.format_exc()) + return function.RegisterValue()._to_api_object() + + def _get_incoming_flag_value(self, ctxt, reg, func): + try: + func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), + core.BNNewFunctionReference(func)) + reg_name = self.arch.get_reg_name(reg) + return self.perform_get_incoming_flag_value(reg_name, func_obj)._to_api_object() + except: + log.log_error(traceback.format_exc()) + return function.RegisterValue()._to_api_object() + def __repr__(self): return "" % (self.arch.name, self.name) def __str__(self): return self.name + def perform_get_incoming_reg_value(self, reg, func): + return function.RegisterValue() + + def perform_get_incoming_flag_value(self, reg, func): + return function.RegisterValue() + def with_confidence(self, confidence): return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle), confidence = confidence) + + def get_incoming_reg_value(self, reg, func): + reg_num = self.arch.get_reg_index(reg) + func_handle = None + if func is not None: + func_handle = func.handle + return function.RegisterValue(self.arch, core.BNGetIncomingRegisterValue(self.handle, reg_num, func_handle)) + + def get_incoming_flag_value(self, flag, func): + reg_num = self.arch.get_flag_index(flag) + func_handle = None + if func is not None: + func_handle = func.handle + return function.RegisterValue(self.arch, core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle)) diff --git a/python/function.py b/python/function.py index b14ba53e..cf9bd759 100644 --- a/python/function.py +++ b/python/function.py @@ -37,6 +37,7 @@ import lowlevelil import mediumlevelil import binaryview import log +import callingconvention class LookupTableEntry(object): @@ -49,26 +50,50 @@ class LookupTableEntry(object): class RegisterValue(object): - def __init__(self, arch, value): - self.type = RegisterValueType(value.state) - if value.state == RegisterValueType.EntryValue: - self.reg = arch.get_reg_name(value.value) - elif value.state == RegisterValueType.ConstantValue: - self.value = value.value - elif value.state == RegisterValueType.StackFrameOffset: - self.offset = value.value + def __init__(self, arch = None, value = None): + if value is None: + self.type = RegisterValueType.UndeterminedValue + else: + self.type = RegisterValueType(value.state) + if value.state == RegisterValueType.EntryValue: + self.arch = arch + if arch is not None: + self.reg = arch.get_reg_name(value.value) + else: + self.reg = value.value + elif (value.state == RegisterValueType.ConstantValue) or (value.state == RegisterValueType.ConstantPointerValue): + self.value = value.value + elif value.state == RegisterValueType.StackFrameOffset: + self.offset = value.value def __repr__(self): if self.type == RegisterValueType.EntryValue: return "" % self.reg if self.type == RegisterValueType.ConstantValue: return "" % self.value + if self.type == RegisterValueType.ConstantPointerValue: + return "" % self.value if self.type == RegisterValueType.StackFrameOffset: return "" % self.offset if self.type == RegisterValueType.ReturnAddressValue: return "" return "" + def _to_api_object(self): + result = core.BNRegisterValue() + result.state = self.type + result.value = 0 + if self.type == RegisterValueType.EntryValue: + if self.arch is not None: + result.value = self.arch.get_reg_index(self.reg) + else: + result.value = self.reg + elif (self.type == RegisterValueType.ConstantValue) or (self.type == RegisterValueType.ConstantPointerValue): + result.value = self.value + elif self.type == RegisterValueType.StackFrameOffset: + result.value = self.offset + return result + class ValueRange(object): def __init__(self, start, end, step): @@ -240,6 +265,25 @@ class IndirectBranchInfo(object): return " %s:%#x>" % (self.source_arch.name, self.source_addr, self.dest_arch.name, self.dest_addr) +class ParameterVariables(object): + def __init__(self, var_list, confidence = types.max_confidence): + self.vars = var_list + self.confidence = confidence + + def __repr__(self): + return repr(self.vars) + + def __iter__(self): + for var in self.vars: + yield var + + def __getitem__(self, idx): + return self.vars[idx] + + def with_confidence(self, confidence): + return ParameterVariables(list(self.vars), confidence = confidence) + + class _FunctionAssociatedDataStore(associateddatastore._AssociatedDataStore): _defaults = {} @@ -335,8 +379,19 @@ class Function(object): @property def can_return(self): - """Whether function can return (read-only)""" - return core.BNCanFunctionReturn(self.handle) + """Whether function can return""" + result = core.BNCanFunctionReturn(self.handle) + return types.BoolWithConfidence(result.value, confidence = result.confidence) + + @can_return.setter + def can_return(self, value): + bc = core.BNBoolWithConfidence() + bc.value = bool(value) + if hasattr(value, 'confidence'): + bc.confidence = value.confidence + else: + bc.confidence = types.max_confidence + core.BNSetUserFunctionCanReturn(self.handle, bc) @property def explicitly_defined_type(self): @@ -452,6 +507,97 @@ class Function(object): core.BNFreeAnalysisPerformanceInfo(info, count.value) return result + @property + def type_tokens(self): + """Text tokens for this function's prototype""" + return self.get_type_tokens()[0].tokens + + @property + def return_type(self): + """Return type of the function""" + result = core.BNGetFunctionReturnType(self.handle) + if not result.type: + return None + return types.Type(result.type, confidence = result.confidence) + + @return_type.setter + def return_type(self, value): + type_conf = core.BNTypeWithConfidence() + if value is None: + type_conf.type = None + type_conf.confidence = 0 + else: + type_conf.type = value.handle + type_conf.confidence = value.confidence + core.BNSetUserFunctionReturnType(self.handle, type_conf) + + @property + def calling_convention(self): + """Calling convention used by the function""" + result = core.BNGetFunctionCallingConvention(self.handle) + if not result.convention: + return None + return callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence) + + @calling_convention.setter + def calling_convention(self, value): + conv_conf = core.BNCallingConventionWithConfidence() + if value is None: + conv_conf.convention = None + conv_conf.confidence = 0 + else: + conv_conf.convention = value.handle + conv_conf.confidence = value.confidence + core.BNSetUserFunctionCallingConvention(self.handle, conv_conf) + + @property + def parameter_vars(self): + """List of variables for the incoming function parameters""" + result = core.BNGetFunctionParameterVariables(self.handle) + var_list = [] + for i in xrange(0, result.count): + var_list.append(Variable(self, result.vars[i].type, result.vars[i].index, result.vars[i].storage)) + confidence = result.confidence + core.BNFreeParameterVariables(result) + return ParameterVariables(var_list, confidence = confidence) + + @parameter_vars.setter + def parameter_vars(self, value): + if value is None: + var_list = [] + else: + var_list = list(value) + var_conf = core.BNParameterVariablesWithConfidence() + var_conf.vars = (core.BNVariable * len(var_list))() + var_conf.count = len(var_list) + for i in xrange(0, len(var_list)): + var_conf.vars[i].type = var_list[i].source_type + var_conf.vars[i].index = var_list[i].index + var_conf.vars[i].storage = var_list[i].storage + if value is None: + var_conf.confidence = 0 + elif hasattr(value, 'confidence'): + var_conf.confidence = value.confidence + else: + var_conf.confidence = types.max_confidence + core.BNSetUserFunctionParameterVariables(self.handle, var_conf) + + @property + def has_variable_arguments(self): + """Whether the function takes a variable number of arguments""" + result = core.BNFunctionHasVariableArguments(self.handle) + return types.BoolWithConfidence(result.value, confidence = result.confidence) + + @has_variable_arguments.setter + def has_variable_arguments(self, value): + bc = core.BNBoolWithConfidence() + bc.value = bool(value) + if hasattr(value, 'confidence'): + bc.confidence = value.confidence + else: + bc.confidence = types.max_confidence + core.BNSetUserFunctionHasVariableArguments(self.handle, bc) + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) @@ -759,6 +905,64 @@ class Function(object): def set_user_type(self, value): core.BNSetFunctionUserType(self.handle, value.handle) + def set_auto_return_type(self, value): + type_conf = core.BNTypeWithConfidence() + if value is None: + type_conf.type = None + type_conf.confidence = 0 + else: + type_conf.type = value.handle + type_conf.confidence = value.confidence + core.BNSetAutoFunctionReturnType(self.handle, type_conf) + + def set_auto_calling_convention(self, value): + conv_conf = core.BNCallingConventionWithConfidence() + if value is None: + conv_conf.convention = None + conv_conf.confidence = 0 + else: + conv_conf.convention = value.handle + conv_conf.confidence = value.confidence + core.BNSetAutoFunctionCallingConvention(self.handle, conv_conf) + + def set_auto_parameter_vars(self, value): + if value is None: + var_list = [] + else: + var_list = list(value) + var_conf = core.BNParameterVariablesWithConfidence() + var_conf.vars = (core.BNVariable * len(var_list))() + var_conf.count = len(var_list) + for i in xrange(0, len(var_list)): + var_conf.vars[i].type = var_list[i].source_type + var_conf.vars[i].index = var_list[i].index + var_conf.vars[i].storage = var_list[i].storage + if value is None: + var_conf.confidence = 0 + elif hasattr(value, 'confidence'): + var_conf.confidence = value.confidence + else: + var_conf.confidence = types.max_confidence + core.BNSetAutoFunctionParameterVariables(self.handle, var_conf) + + def set_auto_has_variable_arguments(self, value): + bc = core.BNBoolWithConfidence() + bc.value = bool(value) + if hasattr(value, 'confidence'): + bc.confidence = value.confidence + else: + bc.confidence = types.max_confidence + core.BNSetAutoFunctionHasVariableArguments(self.handle, bc) + + def set_auto_can_return(self, value): + bc = core.BNBoolWithConfidence() + bc.value = bool(value) + if hasattr(value, 'confidence'): + bc.confidence = value.confidence + else: + bc.confidence = types.max_confidence + core.BNSetAutoFunctionCanReturn(self.handle, bc) + def get_int_display_type(self, instr_addr, value, operand, arch=None): if arch is None: arch = self.arch @@ -932,6 +1136,29 @@ class Function(object): core.BNFreeVariableNameAndType(found_var) return result + def get_type_tokens(self, settings=None): + if settings is not None: + settings = settings.handle + count = ctypes.c_ulonglong() + lines = core.BNGetFunctionTypeTokens(self.handle, settings, count) + result = [] + for i in xrange(0, count.value): + addr = lines[i].addr + tokens = [] + for j in xrange(0, lines[i].count): + token_type = InstructionTextTokenType(lines[i].tokens[j].type) + text = lines[i].tokens[j].text + value = lines[i].tokens[j].value + size = lines[i].tokens[j].size + operand = lines[i].tokens[j].operand + context = lines[i].tokens[j].context + confidence = lines[i].tokens[j].confidence + address = lines[i].tokens[j].address + tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) + result.append(DisassemblyTextLine(addr, tokens)) + core.BNFreeDisassemblyTextLines(lines, count.value) + return result + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): diff --git a/python/types.py b/python/types.py index 47d99bee..e297ddd2 100644 --- a/python/types.py +++ b/python/types.py @@ -279,7 +279,7 @@ class Type(object): result = core.BNGetTypeCallingConvention(self.handle) if not result.convention: return None - return callingconvention.CallingConvention(None, handle = result, confidence = result.confidence) + return callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence) @property def parameters(self): @@ -295,7 +295,8 @@ class Type(object): @property def has_variable_arguments(self): """Whether type has variable arguments (read-only)""" - return core.BNTypeHasVariableArguments(self.handle) + result = core.BNTypeHasVariableArguments(self.handle) + return BoolWithConfidence(result.value, confidence = result.confidence) @property def can_return(self): @@ -505,7 +506,7 @@ class Type(object): return Type(core.BNCreateArrayType(type_conf, count)) @classmethod - def function(self, ret, params, calling_convention=None, variable_arguments=False): + def function(self, ret, params, calling_convention=None, variable_arguments=None): """ ``function`` class method for creating an function Type. @@ -537,8 +538,17 @@ class Type(object): conv_conf.convention = calling_convention.handle conv_conf.confidence = calling_convention.confidence + if variable_arguments is None: + variable_arguments = BoolWithConfidence(False, confidence = 0) + elif not isinstance(variable_arguments, BoolWithConfidence): + variable_arguments = BoolWithConfidence(variable_arguments) + + vararg_conf = core.BNBoolWithConfidence() + vararg_conf.value = variable_arguments.value + vararg_conf.confidence = variable_arguments.confidence + return Type(core.BNCreateFunctionType(ret_conf, conv_conf, param_buf, len(params), - variable_arguments)) + vararg_conf)) @classmethod def generate_auto_type_id(self, source, name): diff --git a/type.cpp b/type.cpp index 19624cdd..398a7216 100644 --- a/type.cpp +++ b/type.cpp @@ -368,9 +368,10 @@ vector Type::GetParameters() const } -bool Type::HasVariableArguments() const +Confidence Type::HasVariableArguments() const { - return BNTypeHasVariableArguments(m_object); + BNBoolWithConfidence result = BNTypeHasVariableArguments(m_object); + return Confidence(result.value, result.confidence); } @@ -655,7 +656,7 @@ Ref Type::ArrayType(const Confidence>& type, uint64_t elem) Ref Type::FunctionType(const Confidence>& returnValue, const Confidence>& callingConvention, - const std::vector& params, bool varArg) + const std::vector& params, const Confidence& varArg) { BNTypeWithConfidence returnValueConf; returnValueConf.type = returnValue->GetObject(); @@ -673,8 +674,12 @@ Ref Type::FunctionType(const Confidence>& returnValue, paramArray[i].typeConfidence = params[i].type.GetConfidence(); } + BNBoolWithConfidence varArgConf; + varArgConf.value = varArg.GetValue(); + varArgConf.confidence = varArg.GetConfidence(); + Type* type = new Type(BNCreateFunctionType(&returnValueConf, &callingConventionConf, - paramArray, params.size(), varArg)); + paramArray, params.size(), &varArgConf)); delete[] paramArray; return type; } @@ -685,7 +690,7 @@ void Type::SetFunctionCanReturn(const Confidence& canReturn) BNBoolWithConfidence bc; bc.value = canReturn.GetValue(); bc.confidence = canReturn.GetConfidence(); - BNSetFunctionCanReturn(m_object, &bc); + BNSetFunctionTypeCanReturn(m_object, &bc); } -- cgit v1.3.1 From 5e25409d02479285d1f16d6cc55df1b267e9ba06 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 17 Aug 2017 02:04:50 -0400 Subject: Support custom calling conventions in the type parser and type objects --- architecture.cpp | 85 ------------------------------------- binaryninjaapi.h | 81 ++++++++++++++++++----------------- binaryninjacore.h | 30 +++++++------ platform.cpp | 85 +++++++++++++++++++++++++++++++++++++ python/architecture.py | 93 ----------------------------------------- python/binaryview.py | 22 +++++----- python/function.py | 15 +++---- python/generator.cpp | 63 ++++++++++++++++++++++------ python/mediumlevelil.py | 5 ++- python/platform.py | 109 ++++++++++++++++++++++++++++++++++++++++++++---- python/types.py | 90 ++++++++++++++++++++++++++++++++------- type.cpp | 47 +++++++++++++-------- 12 files changed, 423 insertions(+), 302 deletions(-) (limited to 'python/types.py') diff --git a/architecture.cpp b/architecture.cpp index 8fd38de2..eb588394 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -787,91 +787,6 @@ void Architecture::SetBinaryViewTypeConstant(const string& type, const string& n } -bool Architecture::ParseTypesFromSource(const string& source, const string& fileName, - map>& types, map>& variables, - map>& functions, string& errors, const vector& includeDirs, - const string& autoTypeSource) -{ - BNTypeParserResult result; - char* errorStr; - const char** includeDirList = new const char*[includeDirs.size()]; - - for (size_t i = 0; i < includeDirs.size(); i++) - includeDirList[i] = includeDirs[i].c_str(); - - types.clear(); - variables.clear(); - functions.clear(); - - bool ok = BNParseTypesFromSource(m_object, source.c_str(), fileName.c_str(), &result, - &errorStr, includeDirList, includeDirs.size(), autoTypeSource.c_str()); - errors = errorStr; - BNFreeString(errorStr); - if (!ok) - return false; - - for (size_t i = 0; i < result.typeCount; i++) - { - QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name); - types[name] = new Type(BNNewTypeReference(result.types[i].type)); - } - for (size_t i = 0; i < result.variableCount; i++) - { - QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name); - types[name] = new Type(BNNewTypeReference(result.variables[i].type)); - } - for (size_t i = 0; i < result.functionCount; i++) - { - QualifiedName name = QualifiedName::FromAPIObject(&result.functions[i].name); - types[name] = new Type(BNNewTypeReference(result.functions[i].type)); - } - BNFreeTypeParserResult(&result); - return true; -} - - -bool Architecture::ParseTypesFromSourceFile(const string& fileName, map>& types, - map>& variables, map>& functions, - string& errors, const vector& includeDirs, const string& autoTypeSource) -{ - BNTypeParserResult result; - char* errorStr; - const char** includeDirList = new const char*[includeDirs.size()]; - - for (size_t i = 0; i < includeDirs.size(); i++) - includeDirList[i] = includeDirs[i].c_str(); - - types.clear(); - variables.clear(); - functions.clear(); - - bool ok = BNParseTypesFromSourceFile(m_object, fileName.c_str(), &result, &errorStr, - includeDirList, includeDirs.size(), autoTypeSource.c_str()); - errors = errorStr; - BNFreeString(errorStr); - if (!ok) - return false; - - for (size_t i = 0; i < result.typeCount; i++) - { - QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name); - types[name] = new Type(BNNewTypeReference(result.types[i].type)); - } - for (size_t i = 0; i < result.variableCount; i++) - { - QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name); - variables[name] = new Type(BNNewTypeReference(result.variables[i].type)); - } - for (size_t i = 0; i < result.functionCount; i++) - { - QualifiedName name = QualifiedName::FromAPIObject(&result.functions[i].name); - functions[name] = new Type(BNNewTypeReference(result.functions[i].type)); - } - BNFreeTypeParserResult(&result); - return true; -} - - void Architecture::RegisterCallingConvention(CallingConvention* cc) { BNRegisterCallingConvention(m_object, cc->GetObject()); diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 63cab888..8213675d 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1743,19 +1743,6 @@ namespace BinaryNinja uint64_t defaultValue = 0); void SetBinaryViewTypeConstant(const std::string& type, const std::string& name, uint64_t value); - bool ParseTypesFromSource(const std::string& source, const std::string& fileName, - std::map>& types, - std::map>& variables, - std::map>& functions, std::string& errors, - const std::vector& includeDirs = std::vector(), - const std::string& autoTypeSource = ""); - bool ParseTypesFromSourceFile(const std::string& fileName, - std::map>& types, - std::map>& variables, - std::map>& functions, std::string& errors, - const std::vector& includeDirs = std::vector(), - const std::string& autoTypeSource = ""); - void RegisterCallingConvention(CallingConvention* cc); std::vector> GetCallingConventions(); Ref GetCallingConventionByName(const std::string& name); @@ -1821,10 +1808,28 @@ namespace BinaryNinja class NamedTypeReference; class Enumeration; - struct NameAndType + struct Variable: public BNVariable + { + Variable(); + Variable(BNVariableSourceType type, uint32_t index, uint64_t storage); + Variable(const BNVariable& var); + + Variable& operator=(const Variable& var); + + bool operator==(const Variable& var) const; + bool operator!=(const Variable& var) const; + bool operator<(const Variable& var) const; + + uint64_t ToIdentifier() const; + static Variable FromIdentifier(uint64_t id); + }; + + struct FunctionParameter { std::string name; Confidence> type; + bool defaultLocation; + Variable location; }; struct QualifiedNameAndType @@ -1848,7 +1853,7 @@ namespace BinaryNinja bool IsFloat() const; Confidence> GetChildType() const; Confidence> GetCallingConvention() const; - std::vector GetParameters() const; + std::vector GetParameters() const; Confidence HasVariableArguments() const; Confidence CanReturn() const; Ref GetStructure() const; @@ -1867,14 +1872,17 @@ namespace BinaryNinja void SetFunctionCanReturn(const Confidence& canReturn); - std::string GetString() const; + std::string GetString(Platform* platform = nullptr) const; std::string GetTypeAndName(const QualifiedName& name) const; - std::string GetStringBeforeName() const; - std::string GetStringAfterName() const; + std::string GetStringBeforeName(Platform* platform = nullptr) const; + std::string GetStringAfterName(Platform* platform = nullptr) const; - std::vector GetTokens() const; - std::vector GetTokensBeforeName() const; - std::vector GetTokensAfterName() const; + std::vector GetTokens(Platform* platform = nullptr, + uint8_t baseConfidence = BN_FULL_CONFIDENCE) const; + std::vector GetTokensBeforeName(Platform* platform = nullptr, + uint8_t baseConfidence = BN_FULL_CONFIDENCE) const; + std::vector GetTokensAfterName(Platform* platform = nullptr, + uint8_t baseConfidence = BN_FULL_CONFIDENCE) const; Ref Duplicate() const; @@ -1897,7 +1905,7 @@ namespace BinaryNinja static Ref ArrayType(const Confidence>& type, uint64_t elem); static Ref FunctionType(const Confidence>& returnValue, const Confidence>& callingConvention, - const std::vector& params, const Confidence& varArg = Confidence(false, 0)); + const std::vector& params, const Confidence& varArg = Confidence(false, 0)); static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name); static std::string GenerateAutoDemangledTypeId(const QualifiedName& name); @@ -2052,22 +2060,6 @@ namespace BinaryNinja static bool IsBackEdge(BasicBlock* source, BasicBlock* target); }; - struct Variable: public BNVariable - { - Variable(); - Variable(BNVariableSourceType type, uint32_t index, uint64_t storage); - Variable(const BNVariable& var); - - Variable& operator=(const Variable& var); - - bool operator==(const Variable& var) const; - bool operator!=(const Variable& var) const; - bool operator<(const Variable& var) const; - - uint64_t ToIdentifier() const; - static Variable FromIdentifier(uint64_t id); - }; - struct VariableNameAndType { Variable var; @@ -3178,6 +3170,19 @@ namespace BinaryNinja Ref GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, const QualifiedName& name); std::string GetAutoPlatformTypeIdSource(); + + bool ParseTypesFromSource(const std::string& source, const std::string& fileName, + std::map>& types, + std::map>& variables, + std::map>& functions, std::string& errors, + const std::vector& includeDirs = std::vector(), + const std::string& autoTypeSource = ""); + bool ParseTypesFromSourceFile(const std::string& fileName, + std::map>& types, + std::map>& variables, + std::map>& functions, std::string& errors, + const std::vector& includeDirs = std::vector(), + const std::string& autoTypeSource = ""); }; class ScriptingOutputListener diff --git a/binaryninjacore.h b/binaryninjacore.h index 6b5d5acc..3c8757ed 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1132,11 +1132,13 @@ extern "C" uint8_t confidence; }; - struct BNNameAndType + struct BNFunctionParameter { char* name; BNType* type; uint8_t typeConfidence; + bool defaultLocation; + BNVariable location; }; struct BNQualifiedNameAndType @@ -2197,7 +2199,6 @@ extern "C" BINARYNINJACOREAPI bool BNParseTypeString(BNBinaryView* view, const char* text, BNQualifiedNameAndType* result, char** errors); - BINARYNINJACOREAPI void BNFreeNameAndType(BNNameAndType* obj); BINARYNINJACOREAPI void BNFreeQualifiedNameAndType(BNQualifiedNameAndType* obj); BINARYNINJACOREAPI BNQualifiedNameAndType* BNGetAnalysisTypeList(BNBinaryView* view, size_t* count); @@ -2602,7 +2603,7 @@ extern "C" BNBoolWithConfidence* cnst, BNBoolWithConfidence* vltl, BNReferenceType refType); BINARYNINJACOREAPI BNType* BNCreateArrayType(BNTypeWithConfidence* type, uint64_t elem); BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNTypeWithConfidence* returnValue, - BNCallingConventionWithConfidence* callingConvention, BNNameAndType* params, + BNCallingConventionWithConfidence* callingConvention, BNFunctionParameter* params, size_t paramCount, BNBoolWithConfidence* varArg); BINARYNINJACOREAPI BNType* BNNewTypeReference(BNType* type); BINARYNINJACOREAPI BNType* BNDuplicateType(BNType* type); @@ -2620,8 +2621,8 @@ extern "C" BINARYNINJACOREAPI bool BNIsTypeFloatingPoint(BNType* type); BINARYNINJACOREAPI BNTypeWithConfidence BNGetChildType(BNType* type); BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetTypeCallingConvention(BNType* type); - BINARYNINJACOREAPI BNNameAndType* BNGetTypeParameters(BNType* type, size_t* count); - BINARYNINJACOREAPI void BNFreeTypeParameterList(BNNameAndType* types, size_t count); + BINARYNINJACOREAPI BNFunctionParameter* BNGetTypeParameters(BNType* type, size_t* count); + BINARYNINJACOREAPI void BNFreeTypeParameterList(BNFunctionParameter* types, size_t count); BINARYNINJACOREAPI BNBoolWithConfidence BNTypeHasVariableArguments(BNType* type); BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionTypeCanReturn(BNType* type); BINARYNINJACOREAPI BNStructure* BNGetTypeStructure(BNType* type); @@ -2637,12 +2638,15 @@ extern "C" BINARYNINJACOREAPI void BNTypeSetConst(BNType* type, BNBoolWithConfidence* cnst); BINARYNINJACOREAPI void BNTypeSetVolatile(BNType* type, BNBoolWithConfidence* vltl); - BINARYNINJACOREAPI char* BNGetTypeString(BNType* type); - BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type); - BINARYNINJACOREAPI char* BNGetTypeStringAfterName(BNType* type); - BINARYNINJACOREAPI BNInstructionTextToken* BNGetTypeTokens(BNType* type, size_t* count); - BINARYNINJACOREAPI BNInstructionTextToken* BNGetTypeTokensBeforeName(BNType* type, size_t* count); - BINARYNINJACOREAPI BNInstructionTextToken* BNGetTypeTokensAfterName(BNType* type, size_t* count); + BINARYNINJACOREAPI char* BNGetTypeString(BNType* type, BNPlatform* platform); + BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type, BNPlatform* platform); + BINARYNINJACOREAPI char* BNGetTypeStringAfterName(BNType* type, BNPlatform* platform); + BINARYNINJACOREAPI BNInstructionTextToken* BNGetTypeTokens(BNType* type, BNPlatform* platform, + uint8_t baseConfidence, size_t* count); + BINARYNINJACOREAPI BNInstructionTextToken* BNGetTypeTokensBeforeName(BNType* type, BNPlatform* platform, + uint8_t baseConfidence, size_t* count); + BINARYNINJACOREAPI BNInstructionTextToken* BNGetTypeTokensAfterName(BNType* type, BNPlatform* platform, + uint8_t baseConfidence, size_t* count); BINARYNINJACOREAPI void BNFreeTokenList(BNInstructionTextToken* tokens, size_t count); BINARYNINJACOREAPI BNType* BNCreateNamedTypeReference(BNNamedTypeReference* nt, size_t width, size_t align); @@ -2698,10 +2702,10 @@ extern "C" // Source code processing BINARYNINJACOREAPI bool BNPreprocessSource(const char* source, const char* fileName, char** output, char** errors, const char** includeDirs, size_t includeDirCount); - BINARYNINJACOREAPI bool BNParseTypesFromSource(BNArchitecture* arch, const char* source, const char* fileName, + BINARYNINJACOREAPI bool BNParseTypesFromSource(BNPlatform* platform, const char* source, const char* fileName, BNTypeParserResult* result, char** errors, const char** includeDirs, size_t includeDirCount, const char* autoTypeSource); - BINARYNINJACOREAPI bool BNParseTypesFromSourceFile(BNArchitecture* arch, const char* fileName, + BINARYNINJACOREAPI bool BNParseTypesFromSourceFile(BNPlatform* platform, const char* fileName, BNTypeParserResult* result, char** errors, const char** includeDirs, size_t includeDirCount, const char* autoTypeSource); BINARYNINJACOREAPI void BNFreeTypeParserResult(BNTypeParserResult* result); diff --git a/platform.cpp b/platform.cpp index 2a095da2..a9ab888f 100644 --- a/platform.cpp +++ b/platform.cpp @@ -402,3 +402,88 @@ string Platform::GetAutoPlatformTypeIdSource() BNFreeString(str); return result; } + + +bool Platform::ParseTypesFromSource(const string& source, const string& fileName, + map>& types, map>& variables, + map>& functions, string& errors, const vector& includeDirs, + const string& autoTypeSource) +{ + BNTypeParserResult result; + char* errorStr; + const char** includeDirList = new const char*[includeDirs.size()]; + + for (size_t i = 0; i < includeDirs.size(); i++) + includeDirList[i] = includeDirs[i].c_str(); + + types.clear(); + variables.clear(); + functions.clear(); + + bool ok = BNParseTypesFromSource(m_object, source.c_str(), fileName.c_str(), &result, + &errorStr, includeDirList, includeDirs.size(), autoTypeSource.c_str()); + errors = errorStr; + BNFreeString(errorStr); + if (!ok) + return false; + + for (size_t i = 0; i < result.typeCount; i++) + { + QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name); + types[name] = new Type(BNNewTypeReference(result.types[i].type)); + } + for (size_t i = 0; i < result.variableCount; i++) + { + QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name); + types[name] = new Type(BNNewTypeReference(result.variables[i].type)); + } + for (size_t i = 0; i < result.functionCount; i++) + { + QualifiedName name = QualifiedName::FromAPIObject(&result.functions[i].name); + types[name] = new Type(BNNewTypeReference(result.functions[i].type)); + } + BNFreeTypeParserResult(&result); + return true; +} + + +bool Platform::ParseTypesFromSourceFile(const string& fileName, map>& types, + map>& variables, map>& functions, + string& errors, const vector& includeDirs, const string& autoTypeSource) +{ + BNTypeParserResult result; + char* errorStr; + const char** includeDirList = new const char*[includeDirs.size()]; + + for (size_t i = 0; i < includeDirs.size(); i++) + includeDirList[i] = includeDirs[i].c_str(); + + types.clear(); + variables.clear(); + functions.clear(); + + bool ok = BNParseTypesFromSourceFile(m_object, fileName.c_str(), &result, &errorStr, + includeDirList, includeDirs.size(), autoTypeSource.c_str()); + errors = errorStr; + BNFreeString(errorStr); + if (!ok) + return false; + + for (size_t i = 0; i < result.typeCount; i++) + { + QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name); + types[name] = new Type(BNNewTypeReference(result.types[i].type)); + } + for (size_t i = 0; i < result.variableCount; i++) + { + QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name); + variables[name] = new Type(BNNewTypeReference(result.variables[i].type)); + } + for (size_t i = 0; i < result.functionCount; i++) + { + QualifiedName name = QualifiedName::FromAPIObject(&result.functions[i].name); + functions[name] = new Type(BNNewTypeReference(result.functions[i].type)); + } + BNFreeTypeParserResult(&result); + return true; +} diff --git a/python/architecture.py b/python/architecture.py index 61559934..72403fec 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1674,99 +1674,6 @@ class Architecture(object): """ core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value) - def parse_types_from_source(self, source, filename=None, include_dirs=[], auto_type_source=None): - """ - ``parse_types_from_source`` parses the source string and any needed headers searching for them in - the optional list of directories provided in ``include_dirs``. - - :param str source: source string to be parsed - :param str filename: optional source filename - :param list(str) include_dirs: optional list of string filename include directories - :param str auto_type_source: optional source of types if used for automatically generated types - :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) - :rtype: TypeParserResult - :Example: - - >>> arch.parse_types_from_source('int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n') - ({types: {'bas': }, variables: {'foo': }, functions:{'bar': - }}, '') - >>> - """ - - if filename is None: - filename = "input" - dir_buf = (ctypes.c_char_p * len(include_dirs))() - for i in xrange(0, len(include_dirs)): - dir_buf[i] = str(include_dirs[i]) - parse = core.BNTypeParserResult() - errors = ctypes.c_char_p() - result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, - len(include_dirs), auto_type_source) - error_str = errors.value - core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) - if not result: - raise SyntaxError(error_str) - type_dict = {} - variables = {} - functions = {} - for i in xrange(0, parse.typeCount): - name = types.QualifiedName._from_core_struct(parse.types[i].name) - type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type)) - for i in xrange(0, parse.variableCount): - name = types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type)) - for i in xrange(0, parse.functionCount): - name = types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type)) - core.BNFreeTypeParserResult(parse) - return types.TypeParserResult(type_dict, variables, functions) - - def parse_types_from_source_file(self, filename, include_dirs=[], auto_type_source=None): - """ - ``parse_types_from_source_file`` parses the source file ``filename`` and any needed headers searching for them in - the optional list of directories provided in ``include_dirs``. - - :param str filename: filename of file to be parsed - :param list(str) include_dirs: optional list of string filename include directories - :param str auto_type_source: optional source of types if used for automatically generated types - :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) - :rtype: TypeParserResult - :Example: - - >>> file = "/Users/binja/tmp.c" - >>> open(file).read() - 'int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n' - >>> arch.parse_types_from_source_file(file) - ({types: {'bas': }, variables: {'foo': }, functions: - {'bar': }}, '') - >>> - """ - dir_buf = (ctypes.c_char_p * len(include_dirs))() - for i in xrange(0, len(include_dirs)): - dir_buf[i] = str(include_dirs[i]) - parse = core.BNTypeParserResult() - errors = ctypes.c_char_p() - result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf, - len(include_dirs), auto_type_source) - error_str = errors.value - core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) - if not result: - raise SyntaxError(error_str) - type_dict = {} - variables = {} - functions = {} - for i in xrange(0, parse.typeCount): - name = types.QualifiedName._from_core_struct(parse.types[i].name) - type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type)) - for i in xrange(0, parse.variableCount): - name = types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type)) - for i in xrange(0, parse.functionCount): - name = types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type)) - core.BNFreeTypeParserResult(parse) - return types.TypeParserResult(type_dict, variables, functions) - def register_calling_convention(self, cc): """ ``register_calling_convention`` registers a new calling convention for the Architecture. diff --git a/python/binaryview.py b/python/binaryview.py index a43bd5b5..bdba11af 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -217,7 +217,7 @@ class BinaryDataNotificationCallbacks(object): def _data_var_added(self, ctxt, view, var): try: address = var[0].address - var_type = types.Type(core.BNNewTypeReference(var[0].type), confidence = var[0].typeConfidence) + var_type = types.Type(core.BNNewTypeReference(var[0].type), platform = self.view.platform, confidence = var[0].typeConfidence) auto_discovered = var[0].autoDiscovered self.notify.data_var_added(self.view, DataVariable(address, var_type, auto_discovered)) except: @@ -226,7 +226,7 @@ class BinaryDataNotificationCallbacks(object): def _data_var_removed(self, ctxt, view, var): try: address = var[0].address - var_type = types.Type(core.BNNewTypeReference(var[0].type), confidence = var[0].typeConfidence) + var_type = types.Type(core.BNNewTypeReference(var[0].type), platform = self.view.platform, confidence = var[0].typeConfidence) auto_discovered = var[0].autoDiscovered self.notify.data_var_removed(self.view, DataVariable(address, var_type, auto_discovered)) except: @@ -235,7 +235,7 @@ class BinaryDataNotificationCallbacks(object): def _data_var_updated(self, ctxt, view, var): try: address = var[0].address - var_type = types.Type(core.BNNewTypeReference(var[0].type), confidence = var[0].typeConfidence) + var_type = types.Type(core.BNNewTypeReference(var[0].type), platform = self.view.platform, confidence = var[0].typeConfidence) auto_discovered = var[0].autoDiscovered self.notify.data_var_updated(self.view, DataVariable(address, var_type, auto_discovered)) except: @@ -256,14 +256,14 @@ class BinaryDataNotificationCallbacks(object): def _type_defined(self, ctxt, view, name, type_obj): try: qualified_name = types.QualifiedName._from_core_struct(name[0]) - self.notify.type_defined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj))) + self.notify.type_defined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj), platform = self.view.platform)) except: log.log_error(traceback.format_exc()) def _type_undefined(self, ctxt, view, name, type_obj): try: qualified_name = types.QualifiedName._from_core_struct(name[0]) - self.notify.type_undefined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj))) + self.notify.type_undefined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj), platform = self.view.platform)) except: log.log_error(traceback.format_exc()) @@ -860,7 +860,7 @@ class BinaryView(object): result = {} for i in xrange(0, count.value): addr = var_list[i].address - var_type = types.Type(core.BNNewTypeReference(var_list[i].type), confidence = var_list[i].typeConfidence) + var_type = types.Type(core.BNNewTypeReference(var_list[i].type), platform = self.platform, confidence = var_list[i].typeConfidence) auto_discovered = var_list[i].autoDiscovered result[addr] = DataVariable(addr, var_type, auto_discovered) core.BNFreeDataVariables(var_list, count.value) @@ -874,7 +874,7 @@ class BinaryView(object): result = {} for i in xrange(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type)) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self.platform) core.BNFreeTypeList(type_list, count.value) return result @@ -1915,7 +1915,7 @@ class BinaryView(object): var = core.BNDataVariable() if not core.BNGetDataVariableAtAddress(self.handle, addr, var): return None - return DataVariable(var.address, types.Type(var.type, confidence = var.typeConfidence), var.autoDiscovered) + return DataVariable(var.address, types.Type(var.type, platform = self.platform, confidence = var.typeConfidence), var.autoDiscovered) def get_functions_containing(self, addr): """ @@ -2918,7 +2918,7 @@ class BinaryView(object): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) raise SyntaxError(error_str) - type_obj = types.Type(core.BNNewTypeReference(result.type)) + type_obj = types.Type(core.BNNewTypeReference(result.type), platform = self.platform) name = types.QualifiedName._from_core_struct(result.name) core.BNFreeQualifiedNameAndType(result) return type_obj, name @@ -2942,7 +2942,7 @@ class BinaryView(object): obj = core.BNGetAnalysisTypeByName(self.handle, name) if not obj: return None - return types.Type(obj) + return types.Type(obj, platform = self.platform) def get_type_by_id(self, id): """ @@ -2963,7 +2963,7 @@ class BinaryView(object): obj = core.BNGetAnalysisTypeById(self.handle, id) if not obj: return None - return types.Type(obj) + return types.Type(obj, platform = self.platform) def get_type_name_by_id(self, id): """ diff --git a/python/function.py b/python/function.py index cf9bd759..55151e16 100644 --- a/python/function.py +++ b/python/function.py @@ -211,7 +211,7 @@ class Variable(object): if var_type is None: var_type_conf = core.BNGetVariableType(func.handle, var) if var_type_conf.type: - var_type = types.Type(var_type_conf.type, confidence = var_type_conf.confidence) + var_type = types.Type(var_type_conf.type, platform = func.platform, confidence = var_type_conf.confidence) else: var_type = None @@ -443,7 +443,7 @@ class Function(object): @property def function_type(self): """Function type object""" - return types.Type(core.BNGetFunctionType(self.handle)) + return types.Type(core.BNGetFunctionType(self.handle), platform = self.platform) @function_type.setter def function_type(self, value): @@ -457,7 +457,7 @@ class Function(object): result = [] for i in xrange(0, count.value): result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name, - types.Type(handle = core.BNNewTypeReference(v[i].type), confidence = v[i].typeConfidence))) + types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))) result.sort(key = lambda x: x.identifier) core.BNFreeVariableList(v, count.value) return result @@ -470,7 +470,7 @@ class Function(object): result = [] for i in xrange(0, count.value): result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name, - types.Type(handle = core.BNNewTypeReference(v[i].type), confidence = v[i].typeConfidence))) + types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))) result.sort(key = lambda x: x.identifier) core.BNFreeVariableList(v, count.value) return result @@ -518,7 +518,7 @@ class Function(object): result = core.BNGetFunctionReturnType(self.handle) if not result.type: return None - return types.Type(result.type, confidence = result.confidence) + return types.Type(result.type, platform = self.platform, confidence = result.confidence) @return_type.setter def return_type(self, value): @@ -778,7 +778,7 @@ class Function(object): refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - var_type = types.Type(core.BNNewTypeReference(refs[i].type), confidence = refs[i].typeConfidence) + var_type = types.Type(core.BNNewTypeReference(refs[i].type), platform = self.platform, confidence = refs[i].typeConfidence) result.append(StackVariableReference(refs[i].sourceOperand, var_type, refs[i].name, Variable.from_identifier(self, refs[i].varIdentifier, refs[i].name, var_type), refs[i].referencedOffset, refs[i].size)) @@ -1132,7 +1132,8 @@ class Function(object): if not core.BNGetStackVariableAtFrameOffset(self.handle, arch.handle, addr, offset, found_var): return None result = Variable(self, found_var.var.type, found_var.var.index, found_var.var.storage, - found_var.name, types.Type(handle = core.BNNewTypeReference(found_var.type), confidence = found_var.typeConfidence)) + found_var.name, types.Type(handle = core.BNNewTypeReference(found_var.type), platform = self.platform, + confidence = found_var.typeConfidence)) core.BNFreeVariableNameAndType(found_var) return result diff --git a/python/generator.cpp b/python/generator.cpp index 554f82cd..f838b36d 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -172,7 +172,7 @@ int main(int argc, char* argv[]) return 1; } - bool ok = arch->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors); + bool ok = arch->GetStandalonePlatform()->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors); fprintf(stderr, "Errors: %s", errors.c_str()); if (!ok) return 1; @@ -237,22 +237,61 @@ int main(int argc, char* argv[]) fprintf(out, "\n# Structure definitions\n"); + set structsToProcess; + set finishedStructs; for (auto& i : types) + structsToProcess.insert(i.first); + while (structsToProcess.size() != 0) { - string name; - if (i.first.size() != 1) - continue; - name = i.first[0]; - if ((i.second->GetClass() == StructureTypeClass) && (i.second->GetStructure()->GetMembers().size() != 0)) + set currentStructList = structsToProcess; + structsToProcess.clear(); + bool processedSome = false; + for (auto& i : currentStructList) { - fprintf(out, "%s._fields_ = [\n", name.c_str()); - for (auto& j : i.second->GetStructure()->GetMembers()) + string name; + if (i.size() != 1) + continue; + Ref type = types[i]; + name = i[0]; + if ((type->GetClass() == StructureTypeClass) && (type->GetStructure()->GetMembers().size() != 0)) { - fprintf(out, "\t\t(\"%s\", ", j.name.c_str()); - OutputType(out, j.type); - fprintf(out, "),\n"); + bool requiresDependency = false; + for (auto& j : type->GetStructure()->GetMembers()) + { + if ((j.type->GetClass() == NamedTypeReferenceClass) && + (types[j.type->GetNamedTypeReference()->GetName()]->GetClass() == StructureTypeClass) && + (finishedStructs.count(j.type->GetNamedTypeReference()->GetName()) == 0)) + { + // This structure needs another structure that isn't fully defined yet, need to wait + // for the dependencies to be defined + structsToProcess.insert(i); + requiresDependency = true; + break; + } + } + + if (requiresDependency) + continue; + + fprintf(out, "%s._fields_ = [\n", name.c_str()); + for (auto& j : type->GetStructure()->GetMembers()) + { + fprintf(out, "\t\t(\"%s\", ", j.name.c_str()); + OutputType(out, j.type); + fprintf(out, "),\n"); + } + fprintf(out, "\t]\n"); + finishedStructs.insert(i); + processedSome = true; } - fprintf(out, "\t]\n"); + } + + if (!processedSome) + { + fprintf(stderr, "Detected dependency cycle in structures\n"); + for (auto& i : structsToProcess) + fprintf(stderr, "%s\n", i.GetString().c_str()); + return 1; } } diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index c837aa42..3e7a6997 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -417,7 +417,10 @@ class MediumLevelILInstruction(object): """Type of expression""" result = core.BNGetMediumLevelILExprType(self.function.handle, self.expr_index) if result.type: - return types.Type(result.type, confidence = result.confidence) + platform = None + if self.function.source_function: + platform = self.function.source_function.platform + return types.Type(result.type, platform = platform, confidence = result.confidence) return None def get_ssa_var_possible_values(self, ssa_var): diff --git a/python/platform.py b/python/platform.py index 1c2fdcd3..5e63d836 100644 --- a/python/platform.py +++ b/python/platform.py @@ -234,7 +234,7 @@ class Platform(object): result = {} for i in xrange(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type)) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -246,7 +246,7 @@ class Platform(object): result = {} for i in xrange(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type)) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -258,7 +258,7 @@ class Platform(object): result = {} for i in xrange(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type)) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -270,7 +270,7 @@ class Platform(object): result = {} for i in xrange(0, count.value): name = types.QualifiedName._from_core_struct(call_list[i].name) - t = types.Type(core.BNNewTypeReference(call_list[i].type)) + t = types.Type(core.BNNewTypeReference(call_list[i].type), platform = self) result[call_list[i].number] = (name, t) core.BNFreeSystemCallList(call_list, count.value) return result @@ -325,21 +325,21 @@ class Platform(object): obj = core.BNGetPlatformTypeByName(self.handle, name) if not obj: return None - return types.Type(obj) + return types.Type(obj, platform = self) def get_variable_by_name(self, name): name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformVariableByName(self.handle, name) if not obj: return None - return types.Type(obj) + return types.Type(obj, platform = self) def get_function_by_name(self, name): name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformFunctionByName(self.handle, name) if not obj: return None - return types.Type(obj) + return types.Type(obj, platform = self) def get_system_call_name(self, number): return core.BNGetPlatformSystemCallName(self.handle, number) @@ -348,7 +348,7 @@ class Platform(object): obj = core.BNGetPlatformSystemCallType(self.handle, number) if not obj: return None - return types.Type(obj) + return types.Type(obj, platform = self) def generate_auto_platform_type_id(self, name): name = types.QualifiedName(name)._get_core_struct() @@ -360,3 +360,96 @@ class Platform(object): def get_auto_platform_type_id_source(self): return core.BNGetAutoPlatformTypeIdSource(self.handle) + + def parse_types_from_source(self, source, filename=None, include_dirs=[], auto_type_source=None): + """ + ``parse_types_from_source`` parses the source string and any needed headers searching for them in + the optional list of directories provided in ``include_dirs``. + + :param str source: source string to be parsed + :param str filename: optional source filename + :param list(str) include_dirs: optional list of string filename include directories + :param str auto_type_source: optional source of types if used for automatically generated types + :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) + :rtype: TypeParserResult + :Example: + + >>> platform.parse_types_from_source('int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n') + ({types: {'bas': }, variables: {'foo': }, functions:{'bar': + }}, '') + >>> + """ + + if filename is None: + filename = "input" + dir_buf = (ctypes.c_char_p * len(include_dirs))() + for i in xrange(0, len(include_dirs)): + dir_buf[i] = str(include_dirs[i]) + parse = core.BNTypeParserResult() + errors = ctypes.c_char_p() + result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, + len(include_dirs), auto_type_source) + error_str = errors.value + core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) + if not result: + raise SyntaxError(error_str) + type_dict = {} + variables = {} + functions = {} + for i in xrange(0, parse.typeCount): + name = types.QualifiedName._from_core_struct(parse.types[i].name) + type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) + for i in xrange(0, parse.variableCount): + name = types.QualifiedName._from_core_struct(parse.variables[i].name) + variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) + for i in xrange(0, parse.functionCount): + name = types.QualifiedName._from_core_struct(parse.functions[i].name) + functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) + core.BNFreeTypeParserResult(parse) + return types.TypeParserResult(type_dict, variables, functions) + + def parse_types_from_source_file(self, filename, include_dirs=[], auto_type_source=None): + """ + ``parse_types_from_source_file`` parses the source file ``filename`` and any needed headers searching for them in + the optional list of directories provided in ``include_dirs``. + + :param str filename: filename of file to be parsed + :param list(str) include_dirs: optional list of string filename include directories + :param str auto_type_source: optional source of types if used for automatically generated types + :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) + :rtype: TypeParserResult + :Example: + + >>> file = "/Users/binja/tmp.c" + >>> open(file).read() + 'int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n' + >>> platform.parse_types_from_source_file(file) + ({types: {'bas': }, variables: {'foo': }, functions: + {'bar': }}, '') + >>> + """ + dir_buf = (ctypes.c_char_p * len(include_dirs))() + for i in xrange(0, len(include_dirs)): + dir_buf[i] = str(include_dirs[i]) + parse = core.BNTypeParserResult() + errors = ctypes.c_char_p() + result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf, + len(include_dirs), auto_type_source) + error_str = errors.value + core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) + if not result: + raise SyntaxError(error_str) + type_dict = {} + variables = {} + functions = {} + for i in xrange(0, parse.typeCount): + name = types.QualifiedName._from_core_struct(parse.types[i].name) + type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) + for i in xrange(0, parse.variableCount): + name = types.QualifiedName._from_core_struct(parse.variables[i].name) + variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) + for i in xrange(0, parse.functionCount): + name = types.QualifiedName._from_core_struct(parse.functions[i].name) + functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) + core.BNFreeTypeParserResult(parse) + return types.TypeParserResult(type_dict, variables, functions) diff --git a/python/types.py b/python/types.py index e297ddd2..fd2ee27e 100644 --- a/python/types.py +++ b/python/types.py @@ -24,7 +24,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core -from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType +from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType import callingconvention import function @@ -199,10 +199,23 @@ class Symbol(object): raise AttributeError("attribute '%s' is read only" % name) +class FunctionParameter(object): + def __init__(self, param_type, name = "", location = None): + self.type = param_type + self.name = name + self.location = location + + def __repr__(self): + if (self.location is not None) and (self.location.name != self.name): + return "%s %s%s @ %s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name(), self.location.name) + return "%s %s%s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name()) + + class Type(object): - def __init__(self, handle, confidence = max_confidence): + def __init__(self, handle, platform = None, confidence = max_confidence): self.handle = handle self.confidence = confidence + self.platform = platform def __del__(self): core.BNFreeType(self.handle) @@ -255,7 +268,7 @@ class Type(object): result = core.BNGetChildType(self.handle) if not result.type: return None - return Type(result.type, confidence = result.confidence) + return Type(result.type, platform = self.platform, confidence = result.confidence) @property def element_type(self): @@ -263,7 +276,7 @@ class Type(object): result = core.BNGetChildType(self.handle) if not result.type: return None - return Type(result.type, confidence = result.confidence) + return Type(result.type, platform = self.platform, confidence = result.confidence) @property def return_value(self): @@ -271,7 +284,7 @@ class Type(object): result = core.BNGetChildType(self.handle) if not result.type: return None - return Type(result.type, confidence = result.confidence) + return Type(result.type, platform = self.platform, confidence = result.confidence) @property def calling_convention(self): @@ -288,7 +301,18 @@ class Type(object): params = core.BNGetTypeParameters(self.handle, count) result = [] for i in xrange(0, count.value): - result.append((Type(core.BNNewTypeReference(params[i].type), confidence = params[i].typeConfidence), params[i].name)) + param_type = Type(core.BNNewTypeReference(params[i].type), platform = self.platform, confidence = params[i].typeConfidence) + if params[i].defaultLocation: + param_location = None + else: + name = params[i].name + if (params[i].location.type == VariableSourceType.RegisterVariableSourceType) and (self.platform is not None): + name = self.platform.arch.get_reg_name(params[i].location.storage) + elif params[i].location.type == VariableSourceType.StackVariableSourceType: + name = "arg_%x" % params[i].location.storage + param_location = function.Variable(None, params[i].location.type, params[i].location.index, + params[i].location.storage, name, param_type) + result.append(FunctionParameter(param_type, params[i].name, param_location)) core.BNFreeTypeParameterList(params, count.value) return result @@ -339,7 +363,10 @@ class Type(object): return core.BNGetTypeOffset(self.handle) def __str__(self): - return core.BNGetTypeString(self.handle) + platform = None + if self.platform is not None: + platform = self.platform.handle + return core.BNGetTypeString(self.handle, platform) def __repr__(self): if self.confidence < max_confidence: @@ -347,16 +374,28 @@ class Type(object): return "" % str(self) def get_string_before_name(self): - return core.BNGetTypeStringBeforeName(self.handle) + platform = None + if self.platform is not None: + platform = self.platform.handle + return core.BNGetTypeStringBeforeName(self.handle, platform) def get_string_after_name(self): - return core.BNGetTypeStringAfterName(self.handle) + platform = None + if self.platform is not None: + platform = self.platform.handle + return core.BNGetTypeStringAfterName(self.handle, platform) @property def tokens(self): """Type string as a list of tokens (read-only)""" + return self.get_tokens() + + def get_tokens(self, base_confidence = max_confidence): count = ctypes.c_ulonglong() - tokens = core.BNGetTypeTokens(self.handle, count) + platform = None + if self.platform is not None: + platform = self.platform.handle + tokens = core.BNGetTypeTokens(self.handle, platform, base_confidence, count) result = [] for i in xrange(0, count.value): token_type = InstructionTextTokenType(tokens[i].type) @@ -371,9 +410,12 @@ class Type(object): core.BNFreeTokenList(tokens, count.value) return result - def get_tokens_before_name(self): + def get_tokens_before_name(self, base_confidence = max_confidence): count = ctypes.c_ulonglong() - tokens = core.BNGetTypeTokensBeforeName(self.handle, count) + platform = None + if self.platform is not None: + platform = self.platform.handle + tokens = core.BNGetTypeTokensBeforeName(self.handle, platform, base_confidence, count) result = [] for i in xrange(0, count.value): token_type = InstructionTextTokenType(tokens[i].type) @@ -388,9 +430,12 @@ class Type(object): core.BNFreeTokenList(tokens, count.value) return result - def get_tokens_after_name(self): + def get_tokens_after_name(self, base_confidence = max_confidence): count = ctypes.c_ulonglong() - tokens = core.BNGetTypeTokensAfterName(self.handle, count) + platform = None + if self.platform is not None: + platform = self.platform.handle + tokens = core.BNGetTypeTokensAfterName(self.handle, platform, base_confidence, count) result = [] for i in xrange(0, count.value): token_type = InstructionTextTokenType(tokens[i].type) @@ -515,16 +560,29 @@ class Type(object): :param CallingConvention calling_convention: optional argument for function calling convention :param bool variable_arguments: optional argument for functions that have a variable number of arguments """ - param_buf = (core.BNNameAndType * len(params))() + param_buf = (core.BNFunctionParameter * len(params))() for i in xrange(0, len(params)): if isinstance(params[i], Type): param_buf[i].name = "" param_buf[i].type = params[i].handle param_buf[i].typeConfidence = params[i].confidence + param_buf[i].defaultLocation = True + elif isinstance(params[i], FunctionParameter): + param_buf[i].name = params[i].name + param_buf[i].type = params[i].type.handle + param_buf[i].typeConfidence = params[i].type.confidence + if params[i].location is None: + param_buf[i].defaultLocation = True + else: + param_buf[i].defaultLocation = False + param_buf[i].location.type = params[i].location.type + param_buf[i].location.index = params[i].location.index + param_buf[i].location.storage = params[i].location.storage else: param_buf[i].name = params[i][1] param_buf[i].type = params[i][0].handle param_buf[i].typeConfidence = params[i][0].confidence + param_buf[i].defaultLocation = True ret_conf = core.BNTypeWithConfidence() ret_conf.type = ret.handle @@ -565,7 +623,7 @@ class Type(object): return core.BNGetAutoDemangledTypeIdSource() def with_confidence(self, confidence): - return Type(handle = core.BNNewTypeReference(self.handle), confidence = confidence) + return Type(handle = core.BNNewTypeReference(self.handle), platform = self.platform, confidence = confidence) def __setattr__(self, name, value): try: diff --git a/type.cpp b/type.cpp index 398a7216..aa891557 100644 --- a/type.cpp +++ b/type.cpp @@ -349,17 +349,21 @@ Confidence> Type::GetCallingConvention() const } -vector Type::GetParameters() const +vector Type::GetParameters() const { size_t count; - BNNameAndType* types = BNGetTypeParameters(m_object, &count); + BNFunctionParameter* types = BNGetTypeParameters(m_object, &count); - vector result; + vector result; for (size_t i = 0; i < count; i++) { - NameAndType param; + FunctionParameter param; param.name = types[i].name; param.type = Confidence>(new Type(BNNewTypeReference(types[i].type)), types[i].typeConfidence); + param.defaultLocation = types[i].defaultLocation; + param.location.type = types[i].location.type; + param.location.index = types[i].location.index; + param.location.storage = types[i].location.storage; result.push_back(param); } @@ -421,9 +425,9 @@ uint64_t Type::GetOffset() const } -string Type::GetString() const +string Type::GetString(Platform* platform) const { - char* str = BNGetTypeString(m_object); + char* str = BNGetTypeString(m_object, platform ? platform->GetObject() : nullptr); string result = str; BNFreeString(str); return result; @@ -438,28 +442,29 @@ string Type::GetTypeAndName(const QualifiedName& nameList) const return outName; } -string Type::GetStringBeforeName() const +string Type::GetStringBeforeName(Platform* platform) const { - char* str = BNGetTypeStringBeforeName(m_object); + char* str = BNGetTypeStringBeforeName(m_object, platform ? platform->GetObject() : nullptr); string result = str; BNFreeString(str); return result; } -string Type::GetStringAfterName() const +string Type::GetStringAfterName(Platform* platform) const { - char* str = BNGetTypeStringAfterName(m_object); + char* str = BNGetTypeStringAfterName(m_object, platform ? platform->GetObject() : nullptr); string result = str; BNFreeString(str); return result; } -vector Type::GetTokens() const +vector Type::GetTokens(Platform* platform, uint8_t baseConfidence) const { size_t count; - BNInstructionTextToken* tokens = BNGetTypeTokens(m_object, &count); + BNInstructionTextToken* tokens = BNGetTypeTokens(m_object, + platform ? platform->GetObject() : nullptr, baseConfidence, &count); vector result; for (size_t i = 0; i < count; i++) @@ -481,10 +486,11 @@ vector Type::GetTokens() const } -vector Type::GetTokensBeforeName() const +vector Type::GetTokensBeforeName(Platform* platform, uint8_t baseConfidence) const { size_t count; - BNInstructionTextToken* tokens = BNGetTypeTokensBeforeName(m_object, &count); + BNInstructionTextToken* tokens = BNGetTypeTokensBeforeName(m_object, + platform ? platform->GetObject() : nullptr, baseConfidence, &count); vector result; for (size_t i = 0; i < count; i++) @@ -506,10 +512,11 @@ vector Type::GetTokensBeforeName() const } -vector Type::GetTokensAfterName() const +vector Type::GetTokensAfterName(Platform* platform, uint8_t baseConfidence) const { size_t count; - BNInstructionTextToken* tokens = BNGetTypeTokensAfterName(m_object, &count); + BNInstructionTextToken* tokens = BNGetTypeTokensAfterName(m_object, + platform ? platform->GetObject() : nullptr, baseConfidence, &count); vector result; for (size_t i = 0; i < count; i++) @@ -656,7 +663,7 @@ Ref Type::ArrayType(const Confidence>& type, uint64_t elem) Ref Type::FunctionType(const Confidence>& returnValue, const Confidence>& callingConvention, - const std::vector& params, const Confidence& varArg) + const std::vector& params, const Confidence& varArg) { BNTypeWithConfidence returnValueConf; returnValueConf.type = returnValue->GetObject(); @@ -666,12 +673,16 @@ Ref Type::FunctionType(const Confidence>& returnValue, callingConventionConf.convention = callingConvention ? callingConvention->GetObject() : nullptr; callingConventionConf.confidence = callingConvention.GetConfidence(); - BNNameAndType* paramArray = new BNNameAndType[params.size()]; + BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()]; for (size_t i = 0; i < params.size(); i++) { paramArray[i].name = (char*)params[i].name.c_str(); paramArray[i].type = params[i].type->GetObject(); paramArray[i].typeConfidence = params[i].type.GetConfidence(); + paramArray[i].defaultLocation = params[i].defaultLocation; + paramArray[i].location.type = params[i].location.type; + paramArray[i].location.index = params[i].location.index; + paramArray[i].location.storage = params[i].location.storage; } BNBoolWithConfidence varArgConf; -- cgit v1.3.1 From 0d88336e22cf85a917729fe0f814c1e63736fca0 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 23 Aug 2017 01:04:47 -0400 Subject: Added APIs for clobbered registers, global pointers, and function exit data flow info --- binaryninjaapi.h | 13 ++++++++ binaryninjacore.h | 36 ++++++++++++++++++++- callingconvention.cpp | 20 ++++++++++++ function.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++ mediumlevelil.cpp | 26 +++++++++++---- python/binaryview.py | 6 ++++ python/callingconvention.py | 10 ++++++ python/function.py | 79 ++++++++++++++++++++++++++++++++++++++++++++- python/types.py | 37 +++++++++++++++++++++ 9 files changed, 297 insertions(+), 9 deletions(-) (limited to 'python/types.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index e16679cc..f5f51908 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2185,6 +2185,8 @@ namespace BinaryNinja Confidence> GetCallingConvention() const; Confidence> GetParameterVariables() const; Confidence HasVariableArguments() const; + Confidence GetStackAdjustment() const; + Confidence> GetClobberedRegisters() const; void SetAutoType(Type* type); void SetAutoReturnType(const Confidence>& type); @@ -2192,6 +2194,8 @@ namespace BinaryNinja void SetAutoParameterVariables(const Confidence>& vars); void SetAutoHasVariableArguments(const Confidence& varArgs); void SetAutoCanReturn(const Confidence& returns); + void SetAutoStackAdjustment(const Confidence& stackAdjust); + void SetAutoClobberedRegisters(const Confidence>& clobbered); void SetUserType(Type* type); void SetReturnType(const Confidence>& type); @@ -2199,6 +2203,8 @@ namespace BinaryNinja void SetParameterVariables(const Confidence>& vars); void SetHasVariableArguments(const Confidence& varArgs); void SetCanReturn(const Confidence& returns); + void SetStackAdjustment(const Confidence& stackAdjust); + void SetClobberedRegisters(const Confidence>& clobbered); void ApplyImportedTypes(Symbol* sym); void ApplyAutoDiscoveredType(Type* type); @@ -2260,6 +2266,9 @@ namespace BinaryNinja std::map GetAnalysisPerformanceInfo(); std::vector GetTypeTokens(DisassemblySettings* settings = nullptr); + + Confidence GetGlobalPointerValue() const; + Confidence GetRegisterValueAtExit(uint32_t reg) const; }; class AdvancedFunctionAnalysisDataRequestor @@ -2856,6 +2865,7 @@ namespace BinaryNinja void Finalize(); void GenerateSSAForm(bool analyzeConditionals = true, bool handleAliases = true, + const std::set& knownNotAliases = std::set(), const std::set& knownAliases = std::set()); bool GetExprText(Architecture* arch, ExprId expr, std::vector& tokens); @@ -3069,6 +3079,7 @@ namespace BinaryNinja static bool AreArgumentRegistersSharedIndexCallback(void* ctxt); static bool IsStackReservedForArgumentRegistersCallback(void* ctxt); + static bool IsStackAdjustedOnReturnCallback(void* ctxt); static uint32_t GetIntegerReturnValueRegisterCallback(void* ctxt); static uint32_t GetHighIntegerReturnValueRegisterCallback(void* ctxt); @@ -3089,6 +3100,7 @@ namespace BinaryNinja virtual std::vector GetFloatArgumentRegisters(); virtual bool AreArgumentRegistersSharedIndex(); virtual bool IsStackReservedForArgumentRegisters(); + virtual bool IsStackAdjustedOnReturn(); virtual uint32_t GetIntegerReturnValueRegister() = 0; virtual uint32_t GetHighIntegerReturnValueRegister(); @@ -3111,6 +3123,7 @@ namespace BinaryNinja virtual std::vector GetFloatArgumentRegisters() override; virtual bool AreArgumentRegistersSharedIndex() override; virtual bool IsStackReservedForArgumentRegisters() override; + virtual bool IsStackAdjustedOnReturn() override; virtual uint32_t GetIntegerReturnValueRegister() override; virtual uint32_t GetHighIntegerReturnValueRegister() override; diff --git a/binaryninjacore.h b/binaryninjacore.h index 0ee5c4d7..6ba7fda4 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -694,6 +694,12 @@ extern "C" int64_t value; }; + struct BNRegisterValueWithConfidence + { + BNRegisterValue value; + uint8_t confidence; + }; + struct BNValueRange { uint64_t start, end, step; @@ -1113,6 +1119,12 @@ extern "C" uint8_t confidence; }; + struct BNSizeWithConfidence + { + size_t value; + uint8_t confidence; + }; + struct BNMemberScopeWithConfidence { BNMemberScope value; @@ -1132,6 +1144,13 @@ extern "C" uint8_t confidence; }; + struct BNRegisterSetWithConfidence + { + uint32_t* regs; + size_t count; + uint8_t confidence; + }; + struct BNFunctionParameter { char* name; @@ -1243,6 +1262,7 @@ extern "C" bool (*areArgumentRegistersSharedIndex)(void* ctxt); bool (*isStackReservedForArgumentRegisters)(void* ctxt); + bool (*isStackAdjustedOnReturn)(void* ctxt); uint32_t (*getIntegerReturnValueRegister)(void* ctxt); uint32_t (*getHighIntegerReturnValueRegister)(void* ctxt); @@ -1806,6 +1826,8 @@ extern "C" BINARYNINJACOREAPI BNAddressRange* BNGetAllocatedRanges(BNBinaryView* view, size_t* count); BINARYNINJACOREAPI void BNFreeAddressRanges(BNAddressRange* ranges); + BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetGlobalPointerValue(BNBinaryView* view); + // Raw binary data view BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryDataView(BNFileMetadata* file); BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryDataViewFromBuffer(BNFileMetadata* file, BNDataBuffer* buf); @@ -2073,18 +2095,25 @@ extern "C" BINARYNINJACOREAPI BNParameterVariablesWithConfidence BNGetFunctionParameterVariables(BNFunction* func); BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionHasVariableArguments(BNFunction* func); + BINARYNINJACOREAPI BNSizeWithConfidence BNGetFunctionStackAdjustment(BNFunction* func); + BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionClobberedRegisters(BNFunction* func); + BINARYNINJACOREAPI void BNFreeClobberedRegisters(BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetAutoFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); BINARYNINJACOREAPI void BNSetAutoFunctionCallingConvention(BNFunction* func, BNCallingConventionWithConfidence* convention); BINARYNINJACOREAPI void BNSetAutoFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); BINARYNINJACOREAPI void BNSetAutoFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); + BINARYNINJACOREAPI void BNSetAutoFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust); + BINARYNINJACOREAPI void BNSetAutoFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetUserFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); BINARYNINJACOREAPI void BNSetUserFunctionCallingConvention(BNFunction* func, BNCallingConventionWithConfidence* convention); BINARYNINJACOREAPI void BNSetUserFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); BINARYNINJACOREAPI void BNSetUserFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); + BINARYNINJACOREAPI void BNSetUserFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust); + BINARYNINJACOREAPI void BNSetUserFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNApplyImportedTypes(BNFunction* func, BNSymbol* sym); BINARYNINJACOREAPI void BNApplyAutoDiscoveredFunctionType(BNFunction* func, BNType* type); @@ -2093,6 +2122,9 @@ extern "C" BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFunctionTypeTokens(BNFunction* func, BNDisassemblySettings* settings, size_t* count); + BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionGlobalPointerValue(BNFunction* func); + BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionRegisterValueAtExit(BNFunction* func, uint32_t reg); + BINARYNINJACOREAPI BNFunction* BNGetBasicBlockFunction(BNBasicBlock* block); BINARYNINJACOREAPI BNArchitecture* BNGetBasicBlockArchitecture(BNBasicBlock* block); BINARYNINJACOREAPI uint64_t BNGetBasicBlockStart(BNBasicBlock* block); @@ -2492,7 +2524,8 @@ extern "C" BINARYNINJACOREAPI void BNMediumLevelILMarkLabel(BNMediumLevelILFunction* func, BNMediumLevelILLabel* label); BINARYNINJACOREAPI void BNFinalizeMediumLevelILFunction(BNMediumLevelILFunction* func); BINARYNINJACOREAPI void BNGenerateMediumLevelILSSAForm(BNMediumLevelILFunction* func, - bool analyzeConditionals, bool handleAliases, BNVariable* knownAliases, size_t knownAliasCount); + bool analyzeConditionals, bool handleAliases, BNVariable* knownNotAliases, size_t knownNotAliasCount, + BNVariable* knownAliases, size_t knownAliasCount); BINARYNINJACOREAPI void BNPrepareToCopyMediumLevelILFunction(BNMediumLevelILFunction* func, BNMediumLevelILFunction* src); @@ -2795,6 +2828,7 @@ extern "C" BINARYNINJACOREAPI uint32_t* BNGetFloatArgumentRegisters(BNCallingConvention* cc, size_t* count); BINARYNINJACOREAPI bool BNAreArgumentRegistersSharedIndex(BNCallingConvention* cc); BINARYNINJACOREAPI bool BNIsStackReservedForArgumentRegisters(BNCallingConvention* cc); + BINARYNINJACOREAPI bool BNIsStackAdjustedOnReturn(BNCallingConvention* cc); BINARYNINJACOREAPI uint32_t BNGetIntegerReturnValueRegister(BNCallingConvention* cc); BINARYNINJACOREAPI uint32_t BNGetHighIntegerReturnValueRegister(BNCallingConvention* cc); diff --git a/callingconvention.cpp b/callingconvention.cpp index 0a7d349c..945ba25f 100644 --- a/callingconvention.cpp +++ b/callingconvention.cpp @@ -41,6 +41,7 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name) cc.freeRegisterList = FreeRegisterListCallback; cc.areArgumentRegistersSharedIndex = AreArgumentRegistersSharedIndexCallback; cc.isStackReservedForArgumentRegisters = IsStackReservedForArgumentRegistersCallback; + cc.isStackAdjustedOnReturn = IsStackAdjustedOnReturnCallback; cc.getIntegerReturnValueRegister = GetIntegerReturnValueRegisterCallback; cc.getHighIntegerReturnValueRegister = GetHighIntegerReturnValueRegisterCallback; cc.getFloatReturnValueRegister = GetFloatReturnValueRegisterCallback; @@ -120,6 +121,13 @@ bool CallingConvention::IsStackReservedForArgumentRegistersCallback(void* ctxt) } +bool CallingConvention::IsStackAdjustedOnReturnCallback(void* ctxt) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + return cc->IsStackAdjustedOnReturn(); +} + + uint32_t CallingConvention::GetIntegerReturnValueRegisterCallback(void* ctxt) { CallingConvention* cc = (CallingConvention*)ctxt; @@ -226,6 +234,12 @@ bool CallingConvention::IsStackReservedForArgumentRegisters() } +bool CallingConvention::IsStackAdjustedOnReturn() +{ + return false; +} + + uint32_t CallingConvention::GetHighIntegerReturnValueRegister() { return BN_INVALID_REGISTER; @@ -312,6 +326,12 @@ bool CoreCallingConvention::IsStackReservedForArgumentRegisters() } +bool CoreCallingConvention::IsStackAdjustedOnReturn() +{ + return BNIsStackAdjustedOnReturn(m_object); +} + + uint32_t CoreCallingConvention::GetIntegerReturnValueRegister() { return BNGetIntegerReturnValueRegister(m_object); diff --git a/function.cpp b/function.cpp index 976d73d2..550691d0 100644 --- a/function.cpp +++ b/function.cpp @@ -508,6 +508,25 @@ Confidence Function::HasVariableArguments() const } +Confidence Function::GetStackAdjustment() const +{ + BNSizeWithConfidence sc = BNGetFunctionStackAdjustment(m_object); + return Confidence(sc.value, sc.confidence); +} + + +Confidence> Function::GetClobberedRegisters() const +{ + BNRegisterSetWithConfidence regs = BNGetFunctionClobberedRegisters(m_object); + set regSet; + for (size_t i = 0; i < regs.count; i++) + regSet.insert(regs.regs[i]); + Confidence> result(regSet, regs.confidence); + BNFreeClobberedRegisters(®s); + return result; +} + + void Function::SetAutoType(Type* type) { BNSetFunctionAutoType(m_object, type->GetObject()); @@ -568,6 +587,29 @@ void Function::SetAutoCanReturn(const Confidence& returns) } +void Function::SetAutoStackAdjustment(const Confidence& stackAdjust) +{ + BNSizeWithConfidence sc; + sc.value = stackAdjust.GetValue(); + sc.confidence = stackAdjust.GetConfidence(); + BNSetAutoFunctionStackAdjustment(m_object, &sc); +} + + +void Function::SetAutoClobberedRegisters(const Confidence>& clobbered) +{ + BNRegisterSetWithConfidence regs; + regs.regs = new uint32_t[clobbered.GetValue().size()]; + regs.count = clobbered.GetValue().size(); + size_t i = 0; + for (auto reg : clobbered.GetValue()) + regs.regs[i++] = reg; + regs.confidence = clobbered.GetConfidence(); + BNSetAutoFunctionClobberedRegisters(m_object, ®s); + delete[] regs.regs; +} + + void Function::SetUserType(Type* type) { BNSetFunctionUserType(m_object, type->GetObject()); @@ -628,6 +670,29 @@ void Function::SetCanReturn(const Confidence& returns) } +void Function::SetStackAdjustment(const Confidence& stackAdjust) +{ + BNSizeWithConfidence sc; + sc.value = stackAdjust.GetValue(); + sc.confidence = stackAdjust.GetConfidence(); + BNSetUserFunctionStackAdjustment(m_object, &sc); +} + + +void Function::SetClobberedRegisters(const Confidence>& clobbered) +{ + BNRegisterSetWithConfidence regs; + regs.regs = new uint32_t[clobbered.GetValue().size()]; + regs.count = clobbered.GetValue().size(); + size_t i = 0; + for (auto reg : clobbered.GetValue()) + regs.regs[i++] = reg; + regs.confidence = clobbered.GetConfidence(); + BNSetUserFunctionClobberedRegisters(m_object, ®s); + delete[] regs.regs; +} + + void Function::ApplyImportedTypes(Symbol* sym) { BNApplyImportedTypes(m_object, sym->GetObject()); @@ -1014,6 +1079,20 @@ void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, ui } +Confidence Function::GetGlobalPointerValue() const +{ + BNRegisterValueWithConfidence value = BNGetFunctionGlobalPointerValue(m_object); + return Confidence(RegisterValue::FromAPIObject(value.value), value.confidence); +} + + +Confidence Function::GetRegisterValueAtExit(uint32_t reg) const +{ + BNRegisterValueWithConfidence value = BNGetFunctionRegisterValueAtExit(m_object, reg); + return Confidence(RegisterValue::FromAPIObject(value.value), value.confidence); +} + + void Function::Reanalyze() { BNReanalyzeFunction(m_object); diff --git a/mediumlevelil.cpp b/mediumlevelil.cpp index f978f681..04a7341f 100644 --- a/mediumlevelil.cpp +++ b/mediumlevelil.cpp @@ -302,19 +302,31 @@ void MediumLevelILFunction::Finalize() void MediumLevelILFunction::GenerateSSAForm(bool analyzeConditionals, bool handleAliases, - const set& knownAliases) + const set& knownNotAliases, const set& knownAliases) { - BNVariable* vars = new BNVariable[knownAliases.size()]; + BNVariable* knownNotAlias = new BNVariable[knownNotAliases.size()]; + BNVariable* knownAlias = new BNVariable[knownAliases.size()]; + size_t i = 0; + for (auto& j : knownNotAliases) + { + knownNotAlias[i].type = j.type; + knownNotAlias[i].index = j.index; + knownNotAlias[i].storage = j.storage; + } + + i = 0; for (auto& j : knownAliases) { - vars[i].type = j.type; - vars[i].index = j.index; - vars[i].storage = j.storage; + knownAlias[i].type = j.type; + knownAlias[i].index = j.index; + knownAlias[i].storage = j.storage; } - BNGenerateMediumLevelILSSAForm(m_object, analyzeConditionals, handleAliases, vars, knownAliases.size()); - delete[] vars; + BNGenerateMediumLevelILSSAForm(m_object, analyzeConditionals, handleAliases, knownNotAlias, knownNotAliases.size(), + knownAlias, knownAliases.size()); + delete[] knownNotAlias; + delete[] knownAlias; } diff --git a/python/binaryview.py b/python/binaryview.py index d977de50..bf8a87e0 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -927,6 +927,12 @@ class BinaryView(object): else: return BinaryView._associated_data[handle.value] + @property + def global_pointer_value(self): + """Discovered value of the global pointer register, if the binary uses one (read-only)""" + result = core.BNGetGlobalPointerValue(self.handle) + return function.RegisterValue(self.arch, result.value, confidence = result.confidence) + def __len__(self): return int(core.BNGetViewLength(self.handle)) diff --git a/python/callingconvention.py b/python/callingconvention.py index bd8bbeee..e72475c9 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -37,6 +37,7 @@ class CallingConvention(object): float_arg_regs = [] arg_regs_share_index = False stack_reserved_for_arg_regs = False + stack_adjusted_on_return = False int_return_reg = None high_int_return_reg = None float_return_reg = None @@ -59,6 +60,7 @@ class CallingConvention(object): self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) self._cb.areArgumentRegistersSharedIndex = self._cb.areArgumentRegistersSharedIndex.__class__(self._arg_regs_share_index) self._cb.isStackReservedForArgumentRegisters = self._cb.isStackReservedForArgumentRegisters.__class__(self._stack_reserved_for_arg_regs) + self._cb.isStackAdjustedOnReturn = self._cb.isStackAdjustedOnReturn.__class__(self._stack_adjusted_on_return) self._cb.getIntegerReturnValueRegister = self._cb.getIntegerReturnValueRegister.__class__(self._get_int_return_reg) self._cb.getHighIntegerReturnValueRegister = self._cb.getHighIntegerReturnValueRegister.__class__(self._get_high_int_return_reg) self._cb.getFloatReturnValueRegister = self._cb.getFloatReturnValueRegister.__class__(self._get_float_return_reg) @@ -74,6 +76,7 @@ class CallingConvention(object): self.__dict__["name"] = core.BNGetCallingConventionName(self.handle) self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle) self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle) + self.__dict__["stack_adjusted_on_return"] = core.BNIsStackAdjustedOnReturn(self.handle) count = ctypes.c_ulonglong() regs = core.BNGetCallerSavedRegisters(self.handle, count) @@ -218,6 +221,13 @@ class CallingConvention(object): log.log_error(traceback.format_exc()) return False + def _stack_adjusted_on_return(self, ctxt): + try: + return self.__class__.stack_adjusted_on_return + except: + log.log_error(traceback.format_exc()) + return False + def _get_int_return_reg(self, ctxt): try: return self.arch.regs[self.__class__.int_return_reg].index diff --git a/python/function.py b/python/function.py index 55151e16..553b156f 100644 --- a/python/function.py +++ b/python/function.py @@ -50,11 +50,12 @@ class LookupTableEntry(object): class RegisterValue(object): - def __init__(self, arch = None, value = None): + def __init__(self, arch = None, value = None, confidence = types.max_confidence): if value is None: self.type = RegisterValueType.UndeterminedValue else: self.type = RegisterValueType(value.state) + self.is_constant = False if value.state == RegisterValueType.EntryValue: self.arch = arch if arch is not None: @@ -63,8 +64,10 @@ class RegisterValue(object): self.reg = value.value elif (value.state == RegisterValueType.ConstantValue) or (value.state == RegisterValueType.ConstantPointerValue): self.value = value.value + self.is_constant = True elif value.state == RegisterValueType.StackFrameOffset: self.offset = value.value + self.confidence = confidence def __repr__(self): if self.type == RegisterValueType.EntryValue: @@ -280,6 +283,9 @@ class ParameterVariables(object): def __getitem__(self, idx): return self.vars[idx] + def __len__(self): + return len(self.vars) + def with_confidence(self, confidence): return ParameterVariables(list(self.vars), confidence = confidence) @@ -598,6 +604,52 @@ class Function(object): bc.confidence = types.max_confidence core.BNSetUserFunctionHasVariableArguments(self.handle, bc) + @property + def stack_adjustment(self): + """Number of bytes removed from the stack after return""" + result = core.BNGetFunctionStackAdjustment(self.handle) + return types.SizeWithConfidence(result.value, confidence = result.confidence) + + @stack_adjustment.setter + def stack_adjustment(self, value): + sc = core.BNSizeWithConfidence() + sc.value = int(value) + if hasattr(value, 'confidence'): + sc.confidence = value.confidence + else: + sc.confidence = types.max_confidence + core.BNSetUserFunctionStackAdjustment(self.handle, sc) + + @property + def clobbered_regs(self): + """Registers that are modified by this function""" + result = core.BNGetFunctionClobberedRegisters(self.handle) + reg_set = [] + for i in xrange(0, result.count): + reg_set.append(self.arch.get_reg_name(result.regs[i])) + regs = types.RegisterSet(reg_set, confidence = result.confidence) + core.BNFreeClobberedRegisters(result) + return regs + + @clobbered_regs.setter + def clobbered_regs(self, value): + regs = core.BNRegisterSetWithConfidence() + regs.regs = (ctypes.c_uint * len(value))() + regs.count = len(value) + for i in xrange(0, len(value)): + regs.regs[i] = self.arch.get_reg_index(value[i]) + if hasattr(value, 'confidence'): + regs.confidence = value.confidence + else: + regs.confidence = types.max_confidence + core.BNSetUserFunctionClobberedRegisters(self.handle, regs) + + @property + def global_pointer_value(self): + """Discovered value of the global pointer register, if the function uses one (read-only)""" + result = core.BNGetFunctionGlobalPointerValue(self.handle) + return RegisterValue(self.arch, result.value, confidence = result.confidence) + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) @@ -963,6 +1015,27 @@ class Function(object): bc.confidence = types.max_confidence core.BNSetAutoFunctionCanReturn(self.handle, bc) + def set_auto_stack_adjustment(self, value): + sc = core.BNSizeWithConfidence() + sc.value = int(value) + if hasattr(value, 'confidence'): + sc.confidence = value.confidence + else: + sc.confidence = types.max_confidence + core.BNSetAutoFunctionStackAdjustment(self.handle, sc) + + def set_auto_clobbered_regs(self, value): + regs = core.BNRegisterSetWithConfidence() + regs.regs = (ctypes.c_uint * len(value))() + regs.count = len(value) + for i in xrange(0, len(value)): + regs.regs[i] = self.arch.get_reg_index(value[i]) + if hasattr(value, 'confidence'): + regs.confidence = value.confidence + else: + regs.confidence = types.max_confidence + core.BNSetAutoFunctionClobberedRegisters(self.handle, regs) + def get_int_display_type(self, instr_addr, value, operand, arch=None): if arch is None: arch = self.arch @@ -1160,6 +1233,10 @@ class Function(object): core.BNFreeDisassemblyTextLines(lines, count.value) return result + def get_reg_value_at_exit(self, reg): + result = core.BNGetFunctionRegisterValueAtExit(self.handle, self.arch.get_reg_index(reg)) + return RegisterValue(self.arch, result.value, confidence = result.confidence) + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): diff --git a/python/types.py b/python/types.py index fd2ee27e..bf4a7b74 100644 --- a/python/types.py +++ b/python/types.py @@ -650,6 +650,43 @@ class BoolWithConfidence(object): return self.value +class SizeWithConfidence(object): + def __init__(self, value, confidence = max_confidence): + self.value = value + self.confidence = confidence + + def __str__(self): + return str(self.value) + + def __repr__(self): + return repr(self.value) + + def __int__(self): + return self.value + + +class RegisterSet(object): + def __init__(self, reg_list, confidence = max_confidence): + self.regs = reg_list + self.confidence = confidence + + def __repr__(self): + return repr(self.regs) + + def __iter__(self): + for reg in self.regs: + yield reg + + def __getitem__(self, idx): + return self.regs[idx] + + def __len__(self): + return len(self.regs) + + def with_confidence(self, confidence): + return RegisterSet(list(self.regs), confidence = confidence) + + class ReferenceTypeWithConfidence(object): def __init__(self, value, confidence = max_confidence): self.value = value -- cgit v1.3.1 From 47333ef2460edfa9b5ba5be26fd19f80c0d8d8b6 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 29 Aug 2017 20:13:57 -0400 Subject: Updating APIs to deal with stack adjustment --- binaryninjaapi.h | 5 ++++- binaryninjacore.h | 4 +++- lowlevelilinstruction.cpp | 27 +++++++++++++++++++++++++-- lowlevelilinstruction.h | 8 ++++++++ python/lowlevelil.py | 13 +++++++++++++ python/types.py | 19 +++++++++++++++++-- type.cpp | 16 ++++++++++++++-- 7 files changed, 84 insertions(+), 8 deletions(-) (limited to 'python/types.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 5fb95021..1ac60625 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1872,6 +1872,7 @@ namespace BinaryNinja void SetConst(const Confidence& cnst); void SetVolatile(const Confidence& vltl); void SetTypeName(const QualifiedName& name); + Confidence GetStackAdjustment() const; uint64_t GetElementCount() const; uint64_t GetOffset() const; @@ -1911,7 +1912,8 @@ namespace BinaryNinja static Ref ArrayType(const Confidence>& type, uint64_t elem); static Ref FunctionType(const Confidence>& returnValue, const Confidence>& callingConvention, - const std::vector& params, const Confidence& varArg = Confidence(false, 0)); + const std::vector& params, const Confidence& varArg = Confidence(false, 0), + const Confidence& stackAdjust = Confidence(0, 0)); static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name); static std::string GenerateAutoDemangledTypeId(const QualifiedName& name); @@ -2517,6 +2519,7 @@ namespace BinaryNinja ExprId JumpTo(ExprId dest, const std::vector& targets, const ILSourceLocation& loc = ILSourceLocation()); ExprId Call(ExprId dest, const ILSourceLocation& loc = ILSourceLocation()); + ExprId CallStackAdjust(ExprId dest, size_t adjust, const ILSourceLocation& loc = ILSourceLocation()); ExprId CallSSA(const std::vector& output, ExprId dest, const std::vector& params, const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc = ILSourceLocation()); diff --git a/binaryninjacore.h b/binaryninjacore.h index f20cc1f2..1bb4c726 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -323,6 +323,7 @@ extern "C" LLIL_JUMP, LLIL_JUMP_TO, LLIL_CALL, + LLIL_CALL_STACK_ADJUST, LLIL_RET, LLIL_NORET, LLIL_IF, @@ -2655,7 +2656,7 @@ extern "C" BINARYNINJACOREAPI BNType* BNCreateArrayType(BNTypeWithConfidence* type, uint64_t elem); BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNTypeWithConfidence* returnValue, BNCallingConventionWithConfidence* callingConvention, BNFunctionParameter* params, - size_t paramCount, BNBoolWithConfidence* varArg); + size_t paramCount, BNBoolWithConfidence* varArg, BNSizeWithConfidence* stackAdjust); BINARYNINJACOREAPI BNType* BNNewTypeReference(BNType* type); BINARYNINJACOREAPI BNType* BNDuplicateType(BNType* type); BINARYNINJACOREAPI char* BNGetTypeAndName(BNType* type, BNQualifiedName* name); @@ -2688,6 +2689,7 @@ extern "C" BINARYNINJACOREAPI void BNTypeSetMemberAccess(BNType* type, BNMemberAccessWithConfidence* access); BINARYNINJACOREAPI void BNTypeSetConst(BNType* type, BNBoolWithConfidence* cnst); BINARYNINJACOREAPI void BNTypeSetVolatile(BNType* type, BNBoolWithConfidence* vltl); + BINARYNINJACOREAPI BNSizeWithConfidence BNGetTypeStackAdjustment(BNType* type); BINARYNINJACOREAPI char* BNGetTypeString(BNType* type, BNPlatform* platform); BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type, BNPlatform* platform); diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp index 19bfd983..d85e4f17 100644 --- a/lowlevelilinstruction.cpp +++ b/lowlevelilinstruction.cpp @@ -60,6 +60,7 @@ unordered_map {LowSSARegisterLowLevelOperandUsage, SSARegisterLowLevelOperand}, {ConstantLowLevelOperandUsage, IntegerLowLevelOperand}, {VectorLowLevelOperandUsage, IntegerLowLevelOperand}, + {StackAdjustmentLowLevelOperandUsage, IntegerLowLevelOperand}, {TargetLowLevelOperandUsage, IndexLowLevelOperand}, {TrueTargetLowLevelOperandUsage, IndexLowLevelOperand}, {FalseTargetLowLevelOperandUsage, IndexLowLevelOperand}, @@ -111,6 +112,7 @@ unordered_map> {LLIL_JUMP, {DestExprLowLevelOperandUsage}}, {LLIL_JUMP_TO, {DestExprLowLevelOperandUsage, TargetListLowLevelOperandUsage}}, {LLIL_CALL, {DestExprLowLevelOperandUsage}}, + {LLIL_CALL_STACK_ADJUST, {DestExprLowLevelOperandUsage, StackAdjustmentLowLevelOperandUsage}}, {LLIL_RET, {DestExprLowLevelOperandUsage}}, {LLIL_IF, {ConditionExprLowLevelOperandUsage, TrueTargetLowLevelOperandUsage, FalseTargetLowLevelOperandUsage}}, @@ -1020,7 +1022,7 @@ LowLevelILInstruction LowLevelILInstructionBase::GetSSAForm() const return *this; size_t expr = GetSSAExprIndex(); size_t instr = GetSSAInstructionIndex(); - return LowLevelILInstruction(ssa, ssa->GetRawExpr(GetSSAExprIndex()), expr, instr); + return LowLevelILInstruction(ssa, ssa->GetRawExpr(expr), expr, instr); } @@ -1031,7 +1033,7 @@ LowLevelILInstruction LowLevelILInstructionBase::GetNonSSAForm() const return *this; size_t expr = GetNonSSAExprIndex(); size_t instr = GetNonSSAInstructionIndex(); - return LowLevelILInstruction(nonSsa, nonSsa->GetRawExpr(GetSSAExprIndex()), expr, instr); + return LowLevelILInstruction(nonSsa, nonSsa->GetRawExpr(expr), expr, instr); } @@ -1160,6 +1162,9 @@ void LowLevelILInstruction::VisitExprs(const std::function().VisitExprs(func); break; + case LLIL_CALL_STACK_ADJUST: + GetDestExpr().VisitExprs(func); + break; case LLIL_CALL_SSA: GetDestExpr().VisitExprs(func); break; @@ -1301,6 +1306,9 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest, return dest->Jump(subExprHandler(GetDestExpr()), *this); case LLIL_CALL: return dest->Call(subExprHandler(GetDestExpr()), *this); + case LLIL_CALL_STACK_ADJUST: + return dest->CallStackAdjust(subExprHandler(GetDestExpr()), + GetStackAdjustment(), *this); case LLIL_RET: return dest->Return(subExprHandler(GetDestExpr()), *this); case LLIL_JUMP_TO: @@ -1647,6 +1655,15 @@ int64_t LowLevelILInstruction::GetVector() const } +size_t LowLevelILInstruction::GetStackAdjustment() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(StackAdjustmentLowLevelOperandUsage, operandIndex)) + return (size_t)GetRawOperandAsInteger(operandIndex); + throw LowLevelILInstructionAccessException(); +} + + size_t LowLevelILInstruction::GetTarget() const { size_t operandIndex; @@ -2133,6 +2150,12 @@ ExprId LowLevelILFunction::Call(ExprId dest, const ILSourceLocation& loc) } +ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, size_t adjust, const ILSourceLocation& loc) +{ + return AddExprWithLocation(LLIL_CALL_STACK_ADJUST, loc, 0, 0, dest, adjust); +} + + ExprId LowLevelILFunction::CallSSA(const vector& output, ExprId dest, const vector& params, const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc) { diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h index 03688700..b2849d44 100644 --- a/lowlevelilinstruction.h +++ b/lowlevelilinstruction.h @@ -127,6 +127,7 @@ namespace BinaryNinja LowSSARegisterLowLevelOperandUsage, ConstantLowLevelOperandUsage, VectorLowLevelOperandUsage, + StackAdjustmentLowLevelOperandUsage, TargetLowLevelOperandUsage, TrueTargetLowLevelOperandUsage, FalseTargetLowLevelOperandUsage, @@ -499,6 +500,7 @@ namespace BinaryNinja template SSARegister GetLowSSARegister() const { return As().GetLowSSARegister(); } template int64_t GetConstant() const { return As().GetConstant(); } template int64_t GetVector() const { return As().GetVector(); } + template size_t GetStackAdjustment() const { return As().GetStackAdjustment(); } template size_t GetTarget() const { return As().GetTarget(); } template size_t GetTrueTarget() const { return As().GetTrueTarget(); } template size_t GetFalseTarget() const { return As().GetFalseTarget(); } @@ -551,6 +553,7 @@ namespace BinaryNinja SSARegister GetLowSSARegister() const; int64_t GetConstant() const; int64_t GetVector() const; + size_t GetStackAdjustment() const; size_t GetTarget() const; size_t GetTrueTarget() const; size_t GetFalseTarget() const; @@ -774,6 +777,11 @@ namespace BinaryNinja { LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } }; + template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase + { + LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } + size_t GetStackAdjustment() const { return (size_t)GetRawOperandAsInteger(1); } + }; template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase { LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } diff --git a/python/lowlevelil.py b/python/lowlevelil.py index e50f80c6..75a3f1ad 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -161,6 +161,7 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_JUMP: [("dest", "expr")], LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], LowLevelILOperation.LLIL_CALL: [("dest", "expr")], + LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int")], LowLevelILOperation.LLIL_RET: [("dest", "expr")], LowLevelILOperation.LLIL_NORET: [], LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], @@ -1262,6 +1263,18 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_CALL, dest.index) + def call_stack_adjust(self, dest, stack_adjust): + """ + ``call_stack_adjust`` returns an expression which first pushes the address of the next instruction onto the stack + then jumps (branches) to the expression ``dest``. After the function exits, ``stack_adjust`` is added to the + stack pointer register. + + :param LowLevelILExpr dest: the expression to call + :return: The expression ``call(dest), stack += stack_adjust`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_CALL_STACK_ADJUST, dest.index, stack_adjust) + def ret(self, dest): """ ``ret`` returns an expression which jumps (branches) to the expression ``dest``. ``ret`` is a special alias for diff --git a/python/types.py b/python/types.py index bf4a7b74..2557db2c 100644 --- a/python/types.py +++ b/python/types.py @@ -362,6 +362,12 @@ class Type(object): """Offset into structure (read-only)""" return core.BNGetTypeOffset(self.handle) + @property + def stack_adjustment(self): + """Stack adjustment for function (read-only)""" + result = core.BNGetTypeStackAdjustment(self.handle) + return SizeWithConfidence(result.value, confidence = result.confidence) + def __str__(self): platform = None if self.platform is not None: @@ -551,7 +557,7 @@ class Type(object): return Type(core.BNCreateArrayType(type_conf, count)) @classmethod - def function(self, ret, params, calling_convention=None, variable_arguments=None): + def function(self, ret, params, calling_convention=None, variable_arguments=None, stack_adjust=None): """ ``function`` class method for creating an function Type. @@ -605,8 +611,17 @@ class Type(object): vararg_conf.value = variable_arguments.value vararg_conf.confidence = variable_arguments.confidence + if stack_adjust is None: + stack_adjust = SizeWithConfidence(0, confidence = 0) + elif not isinstance(stack_adjust, SizeWithConfidence): + stack_adjust = SizeWithConfidence(stack_adjust) + + stack_adjust_conf = core.BNSizeWithConfidence() + stack_adjust_conf.value = stack_adjust.value + stack_adjust_conf.confidence = stack_adjust.confidence + return Type(core.BNCreateFunctionType(ret_conf, conv_conf, param_buf, len(params), - vararg_conf)) + vararg_conf, stack_adjust_conf)) @classmethod def generate_auto_type_id(self, source, name): diff --git a/type.cpp b/type.cpp index aa891557..40a69ae2 100644 --- a/type.cpp +++ b/type.cpp @@ -425,6 +425,13 @@ uint64_t Type::GetOffset() const } +Confidence Type::GetStackAdjustment() const +{ + BNSizeWithConfidence result = BNGetTypeStackAdjustment(m_object); + return Confidence(result.value, result.confidence); +} + + string Type::GetString(Platform* platform) const { char* str = BNGetTypeString(m_object, platform ? platform->GetObject() : nullptr); @@ -663,7 +670,8 @@ Ref Type::ArrayType(const Confidence>& type, uint64_t elem) Ref Type::FunctionType(const Confidence>& returnValue, const Confidence>& callingConvention, - const std::vector& params, const Confidence& varArg) + const std::vector& params, const Confidence& varArg, + const Confidence& stackAdjust) { BNTypeWithConfidence returnValueConf; returnValueConf.type = returnValue->GetObject(); @@ -689,8 +697,12 @@ Ref Type::FunctionType(const Confidence>& returnValue, varArgConf.value = varArg.GetValue(); varArgConf.confidence = varArg.GetConfidence(); + BNSizeWithConfidence stackAdjustConf; + stackAdjustConf.value = stackAdjust.GetValue(); + stackAdjustConf.confidence = stackAdjust.GetConfidence(); + Type* type = new Type(BNCreateFunctionType(&returnValueConf, &callingConventionConf, - paramArray, params.size(), &varArgConf)); + paramArray, params.size(), &varArgConf, &stackAdjustConf)); delete[] paramArray; return type; } -- cgit v1.3.1