news 2026/5/27 19:49:40

(9-3-05)智能编程助手(IDA Pro+VS Code+MCP):变量与函数修改操作

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(9-3-05)智能编程助手(IDA Pro+VS Code+MCP):变量与函数修改操作

本部分的主要功能是提供对程序元素的修改能力,支持重命名局部变量、全局变量和函数,设置全局变量和局部变量的类型,以及修改函数原型。可以读取全局变量的编译时值,例如从C语言声明创建或更新自定义类型,并能刷新反编译器窗口以实时显示修改结果,方便逆向分析中的人工调整和类型标注。

(1)下面代码的功能是定义了一个名为 refresh_decompiler_widget 的函数,用于刷新反编译器窗口,确保所做的更改能够立即显示出来。

def refresh_decompiler_widget(): """刷新反编译器窗口""" widget = ida_kernwin.get_current_widget() if widget is not None: vu = ida_hexrays.get_widget_vdui(widget) if vu is not None: vu.refresh_ctext()

(2)下面代码的功能是定义了一个名为 refresh_decompiler_ctext 的函数,用于刷新指定函数地址的反编译文本,确保反编译器视图是最新的。

def refresh_decompiler_ctext(function_address: int): """刷新函数的反编译文本""" error = ida_hexrays.hexrays_failure_t() cfunc: ida_hexrays.cfunc_t = ida_hexrays.decompile_func(function_address, error, ida_hexrays.DECOMP_WARNINGS) if cfunc: cfunc.refresh_func_ctext()

(3)下面代码的功能是定义了一个名为 rename_local_variable 的函数,用于重命名函数中的局部变量。它首先获取函数对象,然后尝试重命名局部变量,如果失败则抛出错误。

@jsonrpc @idawrite def rename_local_variable( function_address: Annotated[str, "包含变量的函数地址"], old_name: Annotated[str, "变量的当前名称"], new_name: Annotated[str, "变量的新名称(空字符串表示默认名称)"] ): """重命名函数中的局部变量""" func = idaapi.get_func(parse_address(function_address)) if not func: raise IDAError(f"地址{function_address}处未找到函数") if not ida_hexrays.rename_lvar(func.start_ea, old_name, new_name): raise IDAError(f"重命名函数{hex(func.start_ea)}中的局部变量{old_name}失败") refresh_decompiler_ctext(func.start_ea)

(4)下面代码的功能是定义了一个名为 rename_global_variable 的函数,用于重命名全局变量。它通过获取全局变量的地址,然后尝试重命名该变量,如果失败则抛出错误。

@jsonrpc @idawrite def rename_global_variable( old_name: Annotated[str, "全局变量的当前名称"], new_name: Annotated[str, "全局变量的新名称(空字符串表示默认名称)"] ): """重命名全局变量""" ea = idaapi.get_name_ea(idaapi.BADADDR, old_name) if not idaapi.set_name(ea, new_name): raise IDAError(f"将全局变量{old_name}重命名为{new_name}失败") refresh_decompiler_ctext(ea)

(5)下面代码的功能是定义了一个名为 set_global_variable_type 的函数,用于设置全局变量的类型。它通过获取变量地址和新类型信息,然后应用新类型,如果失败则抛出错误。

@jsonrpc @idawrite def set_global_variable_type( variable_name: Annotated[str, "全局变量的名称"], new_type: Annotated[str, "变量的新类型"] ): """设置全局变量的类型""" ea = idaapi.get_name_ea(idaapi.BADADDR, variable_name) tif = get_type_by_name(new_type) if not tif: raise IDAError(f"解析的声明不是变量类型") if not ida_typeinf.apply_tinfo(ea, tif, ida_typeinf.PT_SIL): raise IDAError(f"应用类型失败")

(6)下面代码的功能是定义了一个名为 get_global_variable_value_by_name 的函数,用于读取全局变量的值(如果编译时已知)。它通过变量名获取变量地址,然后调用内部函数获取变量值。

@jsonrpc @idaread def get_global_variable_value_by_name(variable_name: Annotated[str, "全局变量的名称"]) -> str: """ 读取全局变量的值(如果编译时已知) 优先使用此函数,而非`data_read_*`函数。 """ ea = idaapi.get_name_ea(idaapi.BADADDR, variable_name) if ea == idaapi.BADADDR: raise IDAError(f"未找到全局变量{variable_name}") return get_global_variable_value_internal(ea)

(7)下面代码的功能是定义了一个名为 get_global_variable_value_at_address 的函数,该函数通过地址读取全局变量的值(如果编译时已知)。它解析地址并调用内部函数获取变量值。

@jsonrpc @idaread def get_global_variable_value_at_address(ea: Annotated[str, "全局变量的地址"]) -> str: """ 通过地址读取全局变量的值(如果编译时已知) 优先使用此函数,而非`data_read_*`函数。 """ ea = parse_address(ea) return get_global_variable_value_internal(ea)

(8)下面代码的功能是定义了一个名为 get_global_variable_value_internal 的内部函数,用于根据地址读取全局变量的值。它获取变量的类型信息,确定变量大小,然后根据大小读取并返回变量的值。

def get_global_variable_value_internal(ea: int) -> str: """内部函数:根据地址读取全局变量的值""" # 获取变量的类型信息 tif = ida_typeinf.tinfo_t() if not ida_nalt.get_tinfo(tif, ea): # 无类型信息,尝试通过名称推断大小 if not ida_bytes.has_any_name(ea): raise IDAError(f"无法获取地址{ea:#x}处变量的类型信息") size = ida_bytes.get_item_size(ea) if size == 0: raise IDAError(f"无法获取地址{ea:#x}处变量的类型信息") else: # 确定变量大小 size = tif.get_size() # 根据大小读取值 if size == 0 and tif.is_array() and tif.get_array_element().is_decl_char(): return_string = idaapi.get_strlit_contents(ea, -1, 0).decode("utf-8").strip() return f"\"{return_string}\"" elif size == 1: return hex(ida_bytes.get_byte(ea)) elif size == 2: return hex(ida_bytes.get_word(ea)) elif size == 4: return hex(ida_bytes.get_dword(ea)) elif size == 8: return hex(ida_bytes.get_qword(ea)) else: # 其他大小返回原始字节 return ' '.join(hex(x) for x in ida_bytes.get_bytes(ea, size))

(9)下面代码的功能是定义了一个名为 rename_function 的函数,该函数用于重命名函数。首先获取函数对象,然后尝试重命名函数,如果失败则抛出错误。

@jsonrpc @idawrite def rename_function( function_address: Annotated[str, "要重命名的函数地址"], new_name: Annotated[str, "函数的新名称(空字符串表示默认名称)"] ): """重命名函数""" func = idaapi.get_func(parse_address(function_address)) if not func: raise IDAError(f"地址{function_address}处未找到函数") if not idaapi.set_name(func.start_ea, new_name): raise IDAError(f"将函数{hex(func.start_ea)}重命名为{new_name}失败") refresh_decompiler_ctext(func.start_ea)

(10)下面代码的功能是定义了一个名为 set_function_prototype 的函数,该函数用于设置指定函数的原型。它首先获取函数对象,然后尝试应用新的函数原型,如果失败则抛出错误。成功应用后,会刷新反编译器窗口以显示更改。

@jsonrpc @idawrite def set_function_prototype( function_address: Annotated[str, "函数的地址"], prototype: Annotated[str, "函数的新原型"] ): """设置函数的原型""" func = idaapi.get_func(parse_address(function_address)) if not func: raise IDAError(f"地址{function_address}处未找到函数") try: tif = ida_typeinf.tinfo_t(prototype, None, ida_typeinf.PT_SIL) if not tif.is_func(): raise IDAError(f"解析的声明不是函数类型") if not ida_typeinf.apply_tinfo(func.start_ea, tif, ida_typeinf.PT_SIL): raise IDAError(f"应用类型失败") refresh_decompiler_ctext(func.start_ea) except Exception as e: raise IDAError(f"解析原型字符串失败:{prototype}")

(11)下面代码的功能是定义了一个名为 my_modifier_t 的类,该类继承自类ida_hexrays.user_lvar_modifier_t,用于修改局部变量的类型。类y_modifier_t包含了始化方法和修改局部变量类型的 modify_lvars 方法。

class my_modifier_t(ida_hexrays.user_lvar_modifier_t): """用于修改局部变量类型的自定义修改器""" def __init__(self, var_name: str, new_type: ida_typeinf.tinfo_t): ida_hexrays.user_lvar_modifier_t.__init__(self) self.var_name = var_name self.new_type = new_type def modify_lvars(self, lvars): """修改局部变量的类型""" for lvar_saved in lvars.lvvec: lvar_saved: ida_hexrays.lvar_saved_info_t if lvar_saved.name == self.var_name: lvar_saved.type = self.new_type return True return False

(12)下面代码的功能是定义了一个名为 parse_decls_ctypes 的函数,该函数通过 ctypes 解析 C 类型声明,主要用于在 Windows 平台上获取错误信息。

def parse_decls_ctypes(decls: str, hti_flags: int) -> tuple[int, str]: """通过ctypes解析声明(主要用于Windows平台获取错误信息)""" if sys.platform == "win32": import ctypes assert isinstance(decls, str), "decls必须是字符串" assert isinstance(hti_flags, int), "hti_flags必须是整数" c_decls = decls.encode("utf-8") c_til = None ida_dll = ctypes.CDLL("ida") ida_dll.parse_decls.argtypes = [ ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int, ] ida_dll.parse_decls.restype = ctypes.c_int messages = [] @ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p) def magic_printer(fmt: bytes, arg1: bytes): if fmt.count(b"%") == 1 and b"%s" in fmt: formatted = fmt.replace(b"%s", arg1) messages.append(formatted.decode("utf-8")) return len(formatted) + 1 else: messages.append(f"不支持的magic_printer格式:{repr(fmt)}") return 0 errors = ida_dll.parse_decls(c_til, c_decls, magic_printer, hti_flags) else: # 注意:上述方法也可能在其他平台上工作,但未经过测试,且可变参数ABI存在差异。 errors = ida_typeinf.parse_decls(None, decls, False, hti_flags) messages = [] return errors, messages

(13)下面代码的功能是定义了一个名为 declare_c_type 的函数,该函数从 C 声明创建或更新本地类型。它解析 C 声明,如果解析成功则返回成功信息,否则抛出错误。

@jsonrpc @idawrite def declare_c_type( c_declaration: Annotated[str, "类型的C声明。例如:typedef int foo_t; struct bar { int a; bool b; };"] ): """从C声明创建或更新本地类型""" # PT_SIL:抑制警告对话框(尽管在此处似乎不必要) # PT_EMPTY:允许空类型(也不必要?) # PT_TYP:带结构体标签打印状态消息 flags = ida_typeinf.PT_SIL | ida_typeinf.PT_EMPTY | ida_typeinf.PT_TYP errors, messages = parse_decls_ctypes(c_declaration, flags) pretty_messages = "\n".join(messages) if errors > 0: raise IDAError(f"解析类型失败:\n{c_declaration}\n\n错误:\n{pretty_messages}") return f"成功\n\n信息:\n{pretty_messages}"

(14)下面代码的功能是定义了一个名为 set_local_variable_type 的函数,该函数用于设置局部变量的类型。它首先解析新类型,然后获取函数对象,尝试重命名局部变量,接着应用新类型,如果失败则抛出错误。

@jsonrpc @idawrite def set_local_variable_type( function_address: Annotated[str, "包含变量的反编译函数地址"], variable_name: Annotated[str, "变量名"], new_type: Annotated[str, "变量的新类型"] ): """设置局部变量的类型""" try: # 某些版本的IDA不支持此构造函数 new_tif = ida_typeinf.tinfo_t(new_type, None, ida_typeinf.PT_SIL) except Exception: try: new_tif = ida_typeinf.tinfo_t() # parse_decl需要类型后带分号 ida_typeinf.parse_decl(new_tif, None, new_type + ";", ida_typeinf.PT_SIL) except Exception: raise IDAError(f"解析类型失败:{new_type}") func = idaapi.get_func(parse_address(function_address)) if not func: raise IDAError(f"地址{function_address}处未找到函数") if not ida_hexrays.rename_lvar(func.start_ea, variable_name, variable_name): raise IDAError(f"未找到局部变量:{variable_name}") modifier = my_modifier_t(variable_name, new_tif) if not ida_hexrays.modify_user_lvars(func.start_ea, modifier): raise IDAError(f"修改局部变量失败:{variable_name}") refresh_decompiler_ctext(func.start_ea)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/23 15:58:39

5大亮点揭秘:clawPDF如何成为Windows最佳开源PDF工具

5大亮点揭秘:clawPDF如何成为Windows最佳开源PDF工具 【免费下载链接】clawPDF Open Source Virtual (Network) Printer for Windows that allows you to create PDFs, OCR text, and print images, with advanced features usually available only in enterprise s…

作者头像 李华
网站建设 2026/5/21 20:25:01

XposedRimetHelper钉钉助手:智能位置模拟实战指南

在现代办公环境中,钉钉打卡已成为日常标配,但固定的考勤地点往往限制了我们的工作灵活性。今天我们来探讨如何通过XposedRimetHelper钉钉助手实现智能位置模拟,让远程办公和灵活考勤成为可能。 【免费下载链接】XposedRimetHelper Xposed 钉钉…

作者头像 李华
网站建设 2026/5/21 10:34:41

象过河进销存软件评测:为什么中小企业都爱它的简单易用

对于灯具店老板来说,进销存管理常常是让人头疼的难题 —— 灯饰产品种类繁杂、配件型号多,组装管理费时;商品易损坏导致退换货频繁,售后台账混乱;新老客户报价记不清,一不小心报错价就流失客户;…

作者头像 李华
网站建设 2026/5/21 0:55:32

Dify镜像可用于小说章节续写创作辅助

Dify 镜像在小说创作中的实践:如何用 AI 辅助续写而不失风格与连贯性 你有没有过这样的经历?写到第五章时,突然记不清主角的左耳是不是有颗痣;构思反派对峙场景时,翻遍前三章才确认他讨厌玫瑰是因为童年创伤。长篇小说…

作者头像 李华
网站建设 2026/5/23 14:28:17

解锁IDM长期使用:三步掌握注册表配置技术

解锁IDM长期使用:三步掌握注册表配置技术 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script 还在为IDM试用期结束而烦恼?现在你只需要掌握一…

作者头像 李华