def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): """Most UEFI modules don't assign globals in the entry function and instead call a initialization routine and pass the system table to it where global assignments are made. This function ensures that the types are applied to the initialization function params so that we can catch global assignments outside of the module entry :param instr: High level IL instruction object """ if instr.operation not in [ HighLevelILOperation.HLIL_TAILCALL, HighLevelILOperation.HLIL_CALL ]: return if instr.dest.operation != HighLevelILOperation.HLIL_CONST_PTR: return argv_is_passed = False for arg in instr.params: if 'ImageHandle' in str( arg ) or 'SystemTable' or 'FileHandle' or 'PeiServices' in str(arg): argv_is_passed = True break if not argv_is_passed: return func = self.bv.get_function_at(instr.dest.constant) old = func.function_type call_args = instr.params new_params = [] for arg, param in zip(call_args, old.parameters): if hasattr(arg, 'var'): new_type = arg.var.type else: new_type = param.type new_type.confidence = 256 new_params.append(FunctionParameter(new_type, param.name)) # TODO: this is a hack to account for odd behavior. func.function_type should be able to set directly to # Type.Function(...). However, during testing this isn't the case. I am only able to get it to work if I # set function_type to a string and update analysis. gross_hack = str( Type.function(old.return_value, new_params, old.calling_convention, old.has_variable_arguments, old.stack_adjustment)).replace( '(', '{}('.format(func.name)) try: func.function_type = gross_hack self.bv.update_analysis_and_wait() except SyntaxError: pass # BN can't parse int48_t and other types despite that it uses it. Ran into this from a sidt instruction
def process_msvc_func(func): view = func.view arch = func.arch symbol = func.symbol mangled_name = symbol.raw_name if mangled_name.startswith('??_7') and not mangled_name.endswith( '@@6B@'): # Skip buggy vtables return sym_type, sym_parts = demangle_ms(arch, mangled_name) if (sym_type is None) or (sym_type.type_class != TypeClass.FunctionTypeClass): return if isinstance(sym_parts, str): return params = [ v.type for v in sym_type.parameters if v.type.type_class != TypeClass.VoidTypeClass ] return_type = sym_type.return_value tokens_before = [str(v) for v in sym_type.get_tokens_before_name()] convention = 'cdecl' if '__cdecl' in tokens_before: convention = 'cdecl' elif '__stdcall' in tokens_before: convention = 'stdcall' elif '__thiscall' in tokens_before: convention = 'thiscall' if (convention == 'thiscall') and len(sym_parts) >= 2: if 'static' not in tokens_before: type_name = '::'.join(sym_parts[:-1]) this_type = Type.pointer( arch, Type.named_type( NamedTypeReference( NamedTypeReferenceClass.StructNamedTypeClass, name=type_name))) params.insert(0, this_type) func.function_type = Type.function(return_type, params, arch.calling_conventions[convention], sym_type.has_variable_arguments)
def get_symbol_type(self, sym): if self.bv.has_database: func = self.bv.get_function_at(sym.address) if func: return Type.function( func.return_type, [ FunctionParameter( param.type, param.name, location=param) for param in func.parameter_vars ], calling_convention=func.calling_convention, variable_arguments=func.has_variable_arguments, stack_adjust=func.stack_adjustment) dvar = self.bv.get_data_var_at(sym.address) if dvar: return dvar.type return None
def process_msvc_func(func): arch = func.arch plat = func.platform sym_type, sym_parts = demangle_ms(arch, func.symbol.raw_name) if (sym_type is None) or (sym_type.type_class != TypeClass.FunctionTypeClass): return if isinstance(sym_parts, str): return params = [ v.type for v in sym_type.parameters if v.type.type_class != TypeClass.VoidTypeClass ] return_type = sym_type.return_value tokens_before = [str(v) for v in sym_type.get_tokens_before_name()] is_member = ('public:' in tokens_before) or ( 'protected:' in tokens_before) or ('private:' in tokens_before) is_static = 'static' in tokens_before is_virtual = 'virtual' in tokens_before convention = plat.default_calling_convention if '__cdecl' in tokens_before: convention = plat.cdecl_calling_convention elif '__stdcall' in tokens_before: convention = plat.stdcall_calling_convention elif '__fastcall' in tokens_before: convention = plat.fastcall_calling_convention elif '__thiscall' in tokens_before: convention = arch.calling_conventions['thiscall'] if return_type.type_class == TypeClass.NamedTypeReferenceClass and return_type.named_type_reference.type_class in { NamedTypeReferenceClass.ClassNamedTypeClass, NamedTypeReferenceClass.StructNamedTypeClass, NamedTypeReferenceClass.UnionNamedTypeClass }: # TODO: This should only added for large/non trivial types return_type = Type.pointer(arch, return_type) params.insert(0, FunctionParameter(return_type, name="retptr")) if len(sym_parts) >= 2 and (is_member or is_virtual) and not is_static: type_name = '::'.join(sym_parts[:-1]) this_type = Type.pointer( arch, Type.named_type( NamedTypeReference( NamedTypeReferenceClass.StructNamedTypeClass, name=type_name))) params.insert(0, FunctionParameter(this_type, name="this")) if (sym_parts[-1] == sym_parts[-2]) and (return_type.type_class == TypeClass.VoidTypeClass): return_type = this_type func_type = Type.function(return_type, params, convention, sym_type.has_variable_arguments) func.function_type = func_type
def ty_from_demangler_node(node, cv_qual=frozenset(), arg_count_hint=None): if node.kind == 'builtin': if node.value in ty_for_cxx_builtin: return ty_for_cxx_builtin[node.value] else: return None elif node.kind in ['name', 'qual_name']: named_ty_ref = NamedTypeReference(name=str(node)) return Type.named_type(named_ty_ref) elif node.kind in ['pointer', 'lvalue', 'rvalue']: pointee_ty = ty_from_demangler_node(node.value) if pointee_ty is None: return None is_const = ('const' in cv_qual) is_volatile = ('volatile' in cv_qual) if node.kind == 'pointer': return Type.pointer(arch, pointee_ty, is_const, is_volatile) elif node.kind == 'lvalue': return Type.pointer( arch, pointee_ty, is_const, is_volatile, ref_type=ReferenceType.ReferenceReferenceType) elif node.kind == 'rvalue': return Type.pointer(arch, pointee_ty, is_const, is_volatile, ref_type=ReferenceType.RValueReferenceType) elif node.kind == 'cv_qual': return ty_from_demangler_node(node.value, cv_qual=node.qual) elif node.kind == 'func': is_ctor_dtor = False if node.name and node.name.kind == 'qual_name': qual_name = node.name.value if qual_name[-1].kind in ['ctor', 'dtor']: is_ctor_dtor = True if is_ctor_dtor: ret_ty = Type.void() elif node.ret_ty is not None: ret_ty = ty_from_demangler_node(node.ret_ty) if ret_ty is None: return None else: ret_ty = Type.int(arch.default_int_size).with_confidence(0) arg_nodes = list(node.arg_tys) arg_tys = [] var_arg = False if arg_nodes[-1].kind == 'builtin' and arg_nodes[-1].value == '...': arg_nodes.pop() var_arg = True elif arg_nodes[0].kind == 'builtin' and arg_nodes[ 0].value == 'void': arg_nodes = arg_nodes[1:] this_arg = False if node.name and node.name.kind == 'qual_name': qual_name = node.name.value if is_ctor_dtor or (arg_count_hint is not None and len(arg_nodes) == arg_count_hint - 1): this_arg = True this_node = Node('qual_name', qual_name[:-1]) this_ty = ty_from_demangler_node(this_node) if this_ty is None: return None arg_tys.append(Type.pointer(arch, this_ty)) for arg_node in arg_nodes: arg_ty = ty_from_demangler_node(arg_node) if arg_ty is None: return None arg_tys.append(arg_ty) ty = Type.function(ret_ty, arg_tys, variable_arguments=var_arg) if arg_count_hint is not None: # toplevel invocation, so return whether we inferred a this argument return this_arg, ty else: return ty else: log.log_warn("Cannot convert demangled AST {} to a type".format( repr(node)))
enum_type.append('BLUE', 4) enum_type.append('INDIGO', 5) enum_type.append('VIOLET', 6) typelib.add_named_type('MyEnumerationType', enum_type) # example: ArrayTypeClass # # unsigned char[256] typelib.add_named_type('MyArrayType', Type.array(Type.int(1), 256)) # example: FunctionTypeClass # # int ()(int, int, int) ret = Type.int(4) params = [Type.int(4), Type.int(4), Type.int(4)] ftype = Type.function(ret, params) typelib.add_named_type('MyFunctionType', ftype) #------------------------------------------------------------------------------ # PART2: Named Objects #------------------------------------------------------------------------------ # example: any external/imported functions named _MySuperComputation # are typed int _MySuperComputation(int, int) ret = Type.int(4) params = [Type.int(4), Type.int(4)] ftype = Type.function(ret, params) typelib.add_named_object('_MySuperComputation', ftype) # finalize