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': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions:{'bar': <type: int32_t(int32_t x)>}}, '') >>> """ if filename is None: filename = "input" dir_buf = (ctypes.c_char_p * len(include_dirs))() for i in range(0, len(include_dirs)): dir_buf[i] = include_dirs[i].encode('charmap') 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 range(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 range(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 range(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 _get_lines_for_data(self, ctxt, view, addr, type, prefix, prefixCount, width, count, typeCtx, ctxCount): try: file_metadata = filemetadata.FileMetadata( handle=core.BNGetFileForView(view)) view = binaryview.BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) type = types.Type(handle=core.BNNewTypeReference(type)) prefixTokens = function.InstructionTextToken.get_instruction_lines( prefix, prefixCount) pycontext = [] for i in range(ctxCount): pycontext.append( TypeContext( types.Type(core.BNNewTypeReference(typeCtx[i].type)), typeCtx[i].offset)) result = self.perform_get_lines_for_data(ctxt, view, addr, type, prefixTokens, width, pycontext) count[0] = len(result) line_buf = (core.BNDisassemblyTextLine * len(result))() for i in range(len(result)): line = result[i] color = line.highlight if not isinstance( color, enums.HighlightStandardColor) and not isinstance( color, highlight.HighlightColor): raise ValueError( "Specified color is not one of HighlightStandardColor, highlight.HighlightColor" ) if isinstance(color, enums.HighlightStandardColor): color = highlight.HighlightColor(color) line_buf[i].highlight = color._get_core_struct() if line.address is None: if len(line.tokens) > 0: line_buf[i].addr = line.tokens[0].address else: line_buf[i].addr = 0 else: line_buf[i].addr = line.address if line.il_instruction is not None: line_buf[i].instrIndex = line.il_instruction.instr_index else: line_buf[i].instrIndex = 0xffffffffffffffff line_buf[i].count = len(line.tokens) line_buf[ i].tokens = function.InstructionTextToken.get_instruction_lines( line.tokens) return ctypes.cast(line_buf, ctypes.c_void_p).value except: log.log_error(traceback.format_exc()) return None
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 include_dirs: optional list of string filename include directories :type include_dirs: list(str) :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': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions: {'bar': <type: int32_t(int32_t x)>}}, '') >>> """ if not (isinstance(filename, str) and os.path.isfile(filename) and os.access(filename, os.R_OK)): raise AttributeError("File {} doesn't exist or isn't readable".format(filename)) dir_buf = (ctypes.c_char_p * len(include_dirs))() for i in range(0, len(include_dirs)): dir_buf[i] = include_dirs[i].encode('charmap') 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.decode("utf-8") core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: raise SyntaxError(error_str) type_dict = {} variables = {} functions = {} for i in range(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 range(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 range(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 _is_valid_for_data(self, ctxt, view, addr, type, context, ctxCount): try: file_metadata = filemetadata.FileMetadata( handle=core.BNGetFileForView(view)) view = binaryview.BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) type = types.Type(handle=core.BNNewTypeReference(type)) pycontext = [] for i in range(0, ctxCount): pycontext.append( types.Type(core.BNNewTypeReference(context[i]))) return self.perform_is_valid_for_data(ctxt, view, addr, type, pycontext) except: log.log_error(traceback.format_exc()) return False
def demangle_ms(arch, mangled_name): """ ``demangle_ms`` demangles a mangled Microsoft Visual Studio C++ name to a Type object. :param Architecture arch: Architecture for the symbol. Required for pointer and integer sizes. :param str mangled_name: a mangled Microsoft Visual Studio C++ name :return: returns tuple of (Type, demangled_name) or (None, mangled_name) on error :rtype: Tuple :Example: >>> demangle_ms(Architecture["x86_64"], "?testf@Foobar@@SA?AW4foo@1@W421@@Z") (<type: public: static enum Foobar::foo __cdecl (enum Foobar::foo)>, ['Foobar', 'testf']) >>> """ handle = ctypes.POINTER(core.BNType)() outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() names = [] if core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)): for i in range(outSize.value): names.append(pyNativeStr(outName[i])) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) return (types.Type(handle), names) return (None, mangled_name)
def demangle_gnu3(arch, mangled_name, options=None): """ ``demangle_gnu3`` demangles a mangled name to a Type object. :param Architecture arch: Architecture for the symbol. Required for pointer and integer sizes. :param str mangled_name: a mangled GNU3 name :param options: (optional) Whether to simplify demangled names : None falls back to user settings, a BinaryView uses that BinaryView's settings, or a boolean to set it directally :type options: Tuple[bool, BinaryView, None] :return: returns tuple of (Type, demangled_name) or (None, mangled_name) on error :rtype: Tuple """ handle = ctypes.POINTER(core.BNType)() outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() names = [] if (isinstance(options, BinaryView) and core.BNDemangleGNU3WithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ (isinstance(options, bool) and core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ (options is None and core.BNDemangleGNU3WithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), None)): for i in range(outSize.value): names.append(pyNativeStr(outName[i])) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) if not handle: return (None, names) return (types.Type(handle), names) return (None, mangled_name)
def demangle_ms(arch, mangled_name, options=False): """ ``demangle_ms`` demangles a mangled Microsoft Visual Studio C++ name to a Type object. :param Architecture arch: Architecture for the symbol. Required for pointer and integer sizes. :param str mangled_name: a mangled Microsoft Visual Studio C++ name :param options: (optional) Whether to simplify demangled names : None falls back to user settings, a BinaryView uses that BinaryView's settings, or a boolean to set it directally :type options: Tuple[bool, BinaryView, None] :return: returns tuple of (Type, demangled_name) or (None, mangled_name) on error :rtype: Tuple :Example: >>> demangle_ms(Architecture["x86_64"], "?testf@Foobar@@SA?AW4foo@1@W421@@Z") (<type: public: static enum Foobar::foo __cdecl (enum Foobar::foo)>, ['Foobar', 'testf']) >>> """ handle = ctypes.POINTER(core.BNType)() outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() names = [] if (isinstance(options, BinaryView) and core.BNDemangleMSWithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ (isinstance(options, bool) and core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ (options is None and core.BNDemangleMSWithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), None)): for i in range(outSize.value): names.append(pyNativeStr(outName[i])) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) return (types.Type(handle), names) return (None, mangled_name)
def expr_type(self): """Type of expression""" result = core.BNGetHighLevelILExprType(self._function.handle, self._expr_index) if result.type: 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 functions(self): """List of platform-specific function definitions (read-only)""" count = ctypes.c_ulonglong(0) type_list = core.BNGetPlatformFunctions(self.handle, count) result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result
def system_calls(self): """List of system calls for this platform (read-only)""" count = ctypes.c_ulonglong(0) call_list = core.BNGetPlatformSystemCalls(self.handle, count) result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(call_list[i].name) 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
def named_types(self): """ A dict containing all named types provided by a type library (read-only) """ count = ctypes.c_ulonglong(0) result = {} named_types = core.BNGetTypeLibraryNamedTypes(self.handle, count) for i in range(0, count.value): name = types.QualifiedName._from_core_struct(named_types[i].name) result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) return result
def demangle_gnu3(arch, mangled_name): handle = ctypes.POINTER(core.BNType)() outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() names = [] if core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)): for i in range(outSize.value): names.append(pyNativeStr(outName[i])) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) if not handle: return (None, names) return (types.Type(handle), names) return (None, mangled_name)
def get_named_type(self, name): """ `get_named_type` direct extracts a reference to a contained type -- when attempting to extract types from a library into a BinaryView, consider using :py:meth:`import_library_type <binaryninja.binaryview.BinaryView.import_library_type>` instead. :param QualifiedName name: :rtype: Type """ if not isinstance(name, types.QualifiedName): name = types.QualifiedName(name) t = core.BNGetTypeLibraryNamedType(self.handle, name._get_core_struct()) if t is None: return None return types.Type(t)
def get_system_call_type(self, number): obj = core.BNGetPlatformSystemCallType(self.handle, number) if not obj: return None return types.Type(obj, platform=self)
def get_function_by_name(self, name, exactMatch=False): name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformFunctionByName(self.handle, name, exactMatch) if not obj: return None 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, platform=self)