import idc
import idaapi
import idautils
import os
import re
def sanitize_filename(name, max_length=100):
"""清理文件名,移除非法字符并限制长度"""
# 移除或替换非法字符
name = re.sub(r'[<>:"/\\|?*]', '_', name)
# 移除多余的下划线
name = re.sub(r'_+', '_', name)
# 限制长度
if len(name) > max_length:
name = name[:max_length]
# 确保文件名不为空
if not name or name.isspace():
name = "unknown_function"
return name.strip()
def export_complete_function_info(output_dir="exported_functions"):
"""
导出所有函数的反汇编和反编译代码(修复文件名问题)
"""
print(f"开始导出函数信息到目录: {output_dir}")
# 创建输出目录(确保路径存在)
try:
if not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
print(f"目录已创建: {os.path.abspath(output_dir)}")
except Exception as e:
print(f"创建目录失败: {e}")
# 使用当前目录作为备选
output_dir = "."
print(f"使用当前目录: {os.path.abspath(output_dir)}")
# 获取函数列表
functions = list(idautils.Functions())
total_functions = len(functions)
print(f"找到 {total_functions} 个函数")
exported_count = 0
hexrays_available = False
# 检查Hex-Rays反编译器是否可用
try:
import ida_hexrays
hexrays_available = True
print("Hex-Rays反编译器可用")
except:
print("Hex-Rays反编译器不可用,仅导出反汇编代码")
for i, func_ea in enumerate(functions):
func_name = idc.get_func_name(func_ea)
# 创建安全的文件名
safe_name = sanitize_filename(func_name)
filename = f"{safe_name}_{func_ea:08X}.txt"
filepath = os.path.join(output_dir, filename)
# 进一步确保文件路径不会太长
if len(filepath) > 200:
# 如果路径太长,使用更短的文件名
filename = f"func_{func_ea:08X}.txt"
filepath = os.path.join(output_dir, filename)
try:
# 确保目录存在(再次检查)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, 'w', encoding='utf-8', errors='ignore') as f:
# 写入函数基本信息
f.write(f"函数名称: {func_name}\n")
f.write(f"起始地址: 0x{func_ea:08X}\n")
# 获取函数对象
func = idaapi.get_func(func_ea)
if func:
f.write(f"结束地址: 0x{func.end_ea:08X}\n")
f.write(f"函数大小: {func.end_ea - func.start_ea} 字节\n")
f.write("\n" + "="*70 + "\n")
f.write("反汇编代码 (包含地址信息):\n")
f.write("="*70 + "\n\n")
# 导出反汇编代码
if func:
ea = func.start_ea
while ea < func.end_ea and ea != idc.BADADDR:
if idc.is_code(idc.get_full_flags(ea)):
# 获取地址和反汇编指令
address = f"0x{ea:08X}"
disasm = idc.GetDisasm(ea)
# 获取注释
comment = idc.get_cmt(ea, 0)
if comment:
f.write(f"{address}: {disasm:<50} // {comment}\n")
else:
f.write(f"{address}: {disasm}\n")
# 移动到下一条指令
next_ea = idc.next_head(ea, func.end_ea)
if next_ea == idc.BADADDR or next_ea <= ea:
break
ea = next_ea
# 导出反编译代码(如果可用)
if hexrays_available:
f.write("\n" + "="*70 + "\n")
f.write("反编译代码 (Hex-Rays):\n")
f.write("="*70 + "\n\n")
try:
cfunc = ida_hexrays.decompile(func_ea)
if cfunc:
f.write(str(cfunc))
else:
f.write("// 反编译失败\n")
except Exception as e:
f.write(f"// 反编译错误: {str(e)}\n")
else:
f.write("\n// Hex-Rays反编译器不可用\n")
exported_count += 1
if i % 100 == 0: # 每100个函数打印一次进度
print(f"进度: {i+1}/{total_functions}")
except Exception as e:
print(f"导出函数 {func_name} 时出错: {str(e)}")
# 尝试使用更简单的文件名
try:
simple_filename = f"func_{func_ea:08X}.txt"
simple_filepath = os.path.join(output_dir, simple_filename)
with open(simple_filepath, 'w', encoding='utf-8', errors='ignore') as f:
f.write(f"函数名称: {func_name}\n地址: 0x{func_ea:08X}\n")
f.write(f"原始文件名过长,使用简化文件名保存\n")
print(f"使用简化文件名成功保存: {simple_filename}")
exported_count += 1
except Exception as e2:
print(f"简化文件名也失败: {e2}")
print(f"导出完成! 成功导出 {exported_count}/{total_functions} 个函数")
print(f"文件保存在: {os.path.abspath(output_dir)}")
# 在IDA输出窗口显示完成信息
idc.msg(f"\n函数导出完成: {exported_count}/{total_functions} 个函数已导出到 {output_dir}\n")
# 简化版本:只使用地址作为文件名
def export_simple_version(output_dir="simple_export"):
"""使用简化文件名导出,避免路径过长问题"""
print("使用简化版本导出...")
if not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
functions = list(idautils.Functions())
exported_count = 0
for func_ea in functions:
func_name = idc.get_func_name(func_ea)
filename = f"func_{func_ea:08X}.txt"
filepath = os.path.join(output_dir, filename)
try:
with open(filepath, 'w', encoding='utf-8', errors='ignore') as f:
f.write(f"Function: {func_name}\n")
f.write(f"Address: 0x{func_ea:08X}\n\n")
func = idaapi.get_func(func_ea)
if func:
f.write("Disassembly:\n")
f.write("-" * 50 + "\n")
ea = func.start_ea
while ea < func.end_ea:
if idc.is_code(idc.get_full_flags(ea)):
disasm = idc.GetDisasm(ea)
f.write(f"0x{ea:08X}: {disasm}\n")
next_ea = idc.next_head(ea, func.end_ea)
if next_ea == idc.BADADDR:
break
ea = next_ea
exported_count += 1
except Exception as e:
print(f"导出失败 {func_name}: {e}")
print(f"简化版本导出完成: {exported_count} 个函数")
# 立即执行导出(使用修复版本)
if __name__ == "__main__":
# 先尝试完整版本
try:
export_complete_function_info("exported_functions")
except Exception as e:
print(f"完整版本失败: {e}")
print("尝试简化版本...")
export_simple_version("simple_export")