From 9de775d7e7f9d7aaaa690c5b028cf8e204401507 Mon Sep 17 00:00:00 2001 From: Maxime Meignan Date: Tue, 8 Oct 2024 17:52:26 +0200 Subject: [PATCH] Implemented the GlobalVariable type change/monitoring --- libbs/decompilers/ida/compat.py | 18 +++++++++++++++++- libbs/decompilers/ida/hooks.py | 7 ++++++- libbs/decompilers/ida/interface.py | 8 +++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/libbs/decompilers/ida/compat.py b/libbs/decompilers/ida/compat.py index 2a50fe3..3f810eb 100644 --- a/libbs/decompilers/ida/compat.py +++ b/libbs/decompilers/ida/compat.py @@ -1261,14 +1261,30 @@ def global_var(addr): if not name: return None + type_ = idc.get_type(addr) size = idaapi.get_item_size(addr) - return GlobalVariable(addr, name, size=size, last_change=datetime.datetime.now(tz=datetime.timezone.utc)) + return GlobalVariable(addr, name, size=size, last_change=datetime.datetime.now(tz=datetime.timezone.utc), type_=type_) @execute_write def set_global_var_name(var_addr, name): return idaapi.set_name(var_addr, name) +@execute_write +def set_global_var_type(var_addr, type_str): + """ + To make sure the type is correctly displayed (especially for arrays of structs, or arrayy of chars, a.k.a. strings), + we first undefine the items where the type is going to be applied. + Parse the applied type string to infer its size, and thus the number of bytes to undefine. + """ + tif = convert_type_str_to_ida_type(type_str) + if tif is None: + idc.del_items(var_addr, flags=idc.DELIT_SIMPLE) + else: + type_size = tif.get_size() + idc.del_items(var_addr, flags=idc.DELIT_SIMPLE, nbytes=type_size) + return idc.SetType(var_addr, type_str) + def ida_type_from_serialized(typ: bytes, fields: bytes): tif = ida_typeinf.tinfo_t() diff --git a/libbs/decompilers/ida/hooks.py b/libbs/decompilers/ida/hooks.py index f58374a..2576986 100644 --- a/libbs/decompilers/ida/hooks.py +++ b/libbs/decompilers/ida/hooks.py @@ -212,6 +212,11 @@ def ti_changed(self, ea, type_, fields): self.interface.function_header_changed( FunctionHeader(None, ea, type_=curr_ret_type, args={}) ) + elif not pfn: + # Must be a global variable type change + self.interface.global_variable_changed( + GlobalVariable(addr=ea, name=idaapi.get_name(ea), size=idaapi.get_item_size(ea), type_=idc.get_type(ea)) + ) return 0 @@ -456,7 +461,7 @@ def renamed(self, ea, new_name, local_name): # symbols changing without any corresponding func is assumed to be global var if ida_func is None: self.interface.global_variable_changed( - GlobalVariable(ea, new_name, size=idaapi.get_item_size(ea)) + GlobalVariable(ea, new_name, size=idaapi.get_item_size(ea), type_=idc.get_type(ea)) ) # function name renaming elif ida_func.start_ea == ea: diff --git a/libbs/decompilers/ida/interface.py b/libbs/decompilers/ida/interface.py index 70e0ac2..1f70b3a 100755 --- a/libbs/decompilers/ida/interface.py +++ b/libbs/decompilers/ida/interface.py @@ -299,11 +299,13 @@ def _set_stack_variable(self, svar: StackVariable, **kwargs) -> bool: # global variables def _set_global_variable(self, gvar: GlobalVariable, **kwargs) -> bool: - # TODO: needs type setting implementation! + modified = False if gvar.name: - return compat.set_global_var_name(gvar.addr, gvar.name) + modified |= compat.set_global_var_name(gvar.addr, gvar.name) + if gvar.type: + modified |= compat.set_global_var_type(gvar.addr, gvar.type) - return False + return modified def _get_global_var(self, addr) -> Optional[GlobalVariable]: return compat.global_var(addr)