本帖最后由 m_h 于 2025-7-10 10:24 编辑
GitHub - mefistotelis/ida-pro-loadmap: Plugin for IDA Pro disassembler which allows loading .map files. ,这个插件并不支持 delphi 的map? idr导出确定无法读取。
GitHub - RetroReversing/idapro-map-loader: Open .map files in IDA pro and set function names based on the symbols in the map file 这个 太老了api不行
我就找ai给我更新了下。会打日志。由于dump 不是在ope 所以地址计算使用的是
BASE_ADJUSTMENT = 0x71111000 # 手动设置
正常来说使用,
BASE_ADJUSTMENT = IMAGE_BASE - 0x10000
就可以。
import os
import sys
import random
from idautils import *
from idaapi import *
import idc
import ida_name
import ida_funcs
import ida_nalt
# ---------------------- 配置部分 ----------------------
MAP_FILE_PATH = r"C:\V12003518_dumpOPE_SCY.map" # 替换为你的.map文件路径
IMAGE_BASE = ida_nalt.get_imagebase()
#BASE_ADJUSTMENT = IMAGE_BASE - 0x10000 # 默认调整值(可能需要手动修正)
# 示例:IDA 地址 0x711340CC,MAP 计算地址 0x230CC
# 调整值 = IDA_addr - MAP_calculated_addr = 0x711340CC - 0x230CC = 0x71111000
BASE_ADJUSTMENT = 0x71111000 # 手动设置
# ----------------------------------------------------
def parse_borland_symbol_line(line, symbols_addresses):
"""解析Borland格式的.map文件行(修正地址计算)"""
line = line.strip()
if not line or ":" not in line or any(x in line for x in ["Start", "Address", "Program entry"]):
return symbols_addresses
try:
parts = line.split()
seg_offset = parts[0]
seg, offset = seg_offset.split(":")
# 优先从符号名中提取完整地址(如 `Finalization_711A4A70` -> 0x711A4A70)
if "_" in parts[-1]:
full_addr_str = parts[-1].split("_")[-1]
if full_addr_str.isalnum() and len(full_addr_str) == 8: # 检查是否为8位十六进制
linear_addr = int(full_addr_str, 16)
symbol_name = parts[-1]
symbols_addresses[linear_addr] = symbol_name
print(f"[DEBUG] 直接映射符号: 0x{linear_addr:08X} -> {symbol_name}")
return symbols_addresses
# 回退到段:偏移计算(需确保BASE_ADJUSTMENT正确)
linear_addr = (int(seg, 16) << 4) + int(offset, 16) + BASE_ADJUSTMENT
symbol_name = parts[-1]
symbols_addresses[linear_addr] = symbol_name
print(f"[DEBUG] 计算映射符号: 0x{linear_addr:08X} -> {symbol_name}")
except Exception as e:
print(f"[WARN] 跳过无效行: {line} (错误: {str(e)})")
return symbols_addresses
def is_name_used(name, exclude_ea=idc.BADADDR):
"""检查名称是否已被使用"""
for ea, current_name in Names():
if current_name == name and ea != exclude_ea:
return True
return False
def safe_rename(ea, new_name):
"""安全重命名函数(处理冲突和异常)"""
try:
# 清理旧名称(使用 SN_FORCE 而不是 SN_DELTAIL)
ida_name.set_name(ea, "", ida_name.SN_FORCE | ida_name.SN_NOWARN)
# 处理名称冲突
final_name = new_name
if is_name_used(new_name, ea):
final_name = f"{new_name}_{ea:08X}"
print(f"[NOTE] 名称冲突处理: {new_name} -> {final_name}")
# 强制重命名
if ida_name.set_name(ea, final_name, ida_name.SN_FORCE | ida_name.SN_NOWARN):
print(f"[SUCCESS] 重命名 0x{ea:08X}: {final_name}")
return True
else:
# 回退方案:添加随机后缀
random_suffix = random.randint(0, 999)
fallback_name = f"{final_name}_{random_suffix:03d}"
if ida_name.set_name(ea, fallback_name, ida_name.SN_FORCE | ida_name.SN_NOWARN):
print(f"[RETRY] 重命名回退: 0x{ea:08X} -> {fallback_name}")
return True
else:
print(f"[ERROR] 无法重命名 0x{ea:08X}(包括回退方案)")
return False
except Exception as e:
print(f"[ERROR] 重命名失败 @ 0x{ea:08X}: {str(e)}")
return False
# ---------------------- 主逻辑 ----------------------
print("=" * 60)
print(f"正在加载MAP文件: {MAP_FILE_PATH}")
print(f"IDA基址: 0x{IMAGE_BASE:08X}, 调整值: 0x{BASE_ADJUSTMENT:08X}")
print("=" * 60)
# 1. 加载MAP文件
all_symbols = {}
if not os.path.exists(MAP_FILE_PATH):
print(f"[ERROR] 文件不存在: {MAP_FILE_PATH}")
sys.exit(1)
else:
try:
with open(MAP_FILE_PATH, "r") as f:
in_publics = False
for line in f:
if "Address Publics by Value" in line:
in_publics = True
continue
if in_publics:
parse_borland_symbol_line(line, all_symbols)
print(f"[INFO] 成功加载 {len(all_symbols)} 个符号")
except Exception as e:
print(f"[ERROR] 读取MAP文件失败: {str(e)}")
sys.exit(1)
# 2. 应用符号到IDA函数
rename_count = 0
for seg_start in Segments():
for func_ea in Functions(seg_start, idc.get_segm_end(seg_start)):
if func_ea in all_symbols:
if safe_rename(func_ea, all_symbols[func_ea]):
rename_count += 1
else:
# 尝试匹配函数内的地址
for insn_ea in FuncItems(func_ea):
if insn_ea in all_symbols:
print(f"[HINT] 发现函数内符号匹配: 0x{func_ea:08X} 包含 0x{insn_ea:08X} -> {all_symbols[insn_ea]}")
if safe_rename(func_ea, all_symbols[insn_ea]):
rename_count += 1
break
# 3. 结果统计
print("=" * 60)
print(f"处理完成!")
print(f"MAP符号总数: {len(all_symbols)}")
print(f"成功重命名函数: {rename_count}")
print(f"未匹配的符号: {len(all_symbols) - rename_count}")
if rename_count == 0:
print("\n[疑难解答]")
print("1. 检查基址调整值是否正确:")
print(f" IDA基址: 0x{IMAGE_BASE:08X}")
print(f" 当前调整值: 0x{BASE_ADJUSTMENT:08X}")
print("2. 手动测试示例(在IDA Python命令行中执行):")
if all_symbols:
sample_addr = next(iter(all_symbols))
print(f" ida_name.set_name(0x{sample_addr:08X}, 'TEST_NAME', ida_name.SN_FORCE | ida_name.SN_NOWARN)")
print("=" * 60)
部分脚本内容
Name: V12003518_dumpOPE_SCY.dll EP: 00082774 : Size: 000BA000
Start Length Name Class
0001:00000000 0000BA000H CODE CODE
Address Publics by Value _ RVA+Base
0001:00000228 system.kernel32.CloseHandle_71121228
...若干内容
0001:00083A70 V12003518_dumpOPE_SCY.Finalization_711A4A70
Program entry point at 0001:00082774
|