news 2026/4/16 11:03:10

(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/4/14 17:25:40

Dify镜像支持Spinnaker实现蓝绿部署

Dify镜像与Spinnaker集成实现蓝绿部署的实践路径 在AI应用快速落地的今天,企业面临的不仅是模型能力的竞争,更是工程化交付效率和系统稳定性的较量。一个精心调优的智能客服Agent,如果因为一次发布导致服务中断几分钟,用户体验可能…

作者头像 李华
网站建设 2026/4/16 11:01:19

Dify如何实现意图识别引导对话流程?

Dify如何实现意图识别引导对话流程? 在智能客服频繁“答非所问”、对话机器人陷入死循环的今天,构建一个真正理解用户意图并能动态响应的AI系统,依然是企业落地大模型应用的核心挑战。用户一句“我想退掉昨天买的鞋子”,系统不仅要…

作者头像 李华
网站建设 2026/4/16 11:01:22

eide串口下载配置图解说明

eide 串口下载配置实战指南:从原理到一键烧录的完整解析 你有没有遇到过这样的场景? 明明代码编译通过了,点击“下载”按钮却卡在90%,提示“Sync failed”; 反复插拔USB线、按复位键十几次,还是进不了IS…

作者头像 李华
网站建设 2026/4/14 14:30:03

3步搞定B站硬核会员:AI自动答题终极指南

3步搞定B站硬核会员:AI自动答题终极指南 【免费下载链接】bili-hardcore bilibili 硬核会员 AI 自动答题,直接调用 B 站 API,非 OCR 实现 项目地址: https://gitcode.com/gh_mirrors/bi/bili-hardcore 还在为B站硬核会员的100道题目感…

作者头像 李华
网站建设 2026/4/15 16:37:52

STM32不同页写入策略在I2C EEPROM代码中的实现

STM32如何聪明地绕过IC EEPROM的“页回卷”陷阱?你有没有遇到过这样的情况:明明写进了数据,读出来却乱七八糟?调试半天发现,不是代码逻辑错了,也不是通信失败——而是EEPROM悄悄把你的数据“折回去”写了。…

作者头像 李华
网站建设 2026/4/15 3:27:59

STM32平台下无源蜂鸣器频率调节实战案例

让蜂鸣器“唱歌”的秘密:STM32驱动无源蜂鸣器实现精准频率控制实战你有没有想过,一个几毛钱的蜂鸣器也能奏出《小星星》?在嵌入式开发中,声音提示早已不只是“滴”一声那么简单。从智能门锁的开机音效,到工业设备的分级…

作者头像 李华