IDA Python 运行脚本
方式1:执行IDA Python(IDC/IDAPython) 函数
Python 输入框(交互式 REPL):单独表达式会自动回显返回值
Shift+F2(Execute script 脚本窗口):纯脚本模式,只执行语句,不会自动打印返回值!
# 1) 看那个字符串
idc.get_strlit_contents(0x65B15, -1, 0) # -> b' &\t:=;\nplzdontcrackme856c91'
-
0x65B15→ ea
字符串的起始地址(Effective Address),在 IDA 里就是这个字符串所在的地址。 -1→ length
-1含义:自动读取,由 IDA 自动判断字符串长度(读到字符串结束符为止)
如果填数字(比如10)就是强制只读取 N 个字节。
-
0→ strtype 字符串类型
IDA 字符串类型常量:-
0→ STRTYPE_C:标准 C 风格以\0空字符结尾的 ASCII 字符串(最常用) - 1:宽字符串 unicode16,2:pascal 字符串(前缀存长度)等
-
返回值
- 成功:返回bytes 原始字节串(不是 python str),比如
b"hello" - 失败:返回
None
ida python 输入框

ida python 输入框
⚠️ 注意:返回的是 bytes,如果你要打印成文本,需要手动 .decode('ascii'),遇到中文可能用utf-8/gbk
方式2:shit f2 (ida/file/script command...)
import idc
res = idc.get_strlit_contents(0x65B15, -1, 0)
print("shift+f2运行脚本log:", res)

python运行脚本
# 1) 看那个字符串
idc.get_strlit_contents(0x65B15, -1, 0) # -> b' &\t:=;\nplzdontcrackme856c91'
# 2) 验证 SHA-256 表(前 6 个 u32)
import ida_bytes, struct
b = ida_bytes.get_bytes(0x65B31, 24) # 直接从程序内存读取原始字节
[hex(struct.unpack('<I', b[i:i+4])[0]) for i in range(0,24,4)]
# -> ['0x428a2f98','0x71374491','0xb5c0fbcf','0xe9b5dba5','0x3956c25b','0x59f111f1']
# 3) 确认字符串只有 2 个引用
import idautils
for x in idautils.XrefsTo(0x65B15): print(hex(x.frm))
# -> 0x2b6b8, 0x2ba00
方式3:script file...
选择 python 脚本文件
IDA Python 脚本:导出 qimei_core_generate 函数完整二进制 + 反汇编文本
text:0000000000025BC0 ; QIMEI 核心生成引擎 (超大 + 混淆)。据 type 参数生成不同 QIMEI 子串: type=0 → z 设备 ID; type=1 → o 缓存 QIMEI; type=3 → z2 设备 ID + 版本;type=6 → m QIMEI 字符串;type=7 → r 上报串;type=13 → r4 加密;type=15 → a 加密字节。内含 q16/q36 标识、plzdontcrackme856c91 反破解提示、XTEA 加密、设备特征采集 (ActivityThread/signatures/NetworkInterface/stat 等)
.text:0000000000025BC0 ; Attributes: bp-based frame
.text:0000000000025BC0
.text:0000000000025BC0 ; _QWORD *__fastcall qimei_core_generate (_QWORD *__return_ptr, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD)
.text:0000000000025BC0 qimei_core_generate ; CODE XREF: qimei_str_manip+130↑p
.text:0000000000025BC0 ; qimei_str_manip+880↑p ...
.text:0000000000025BC0
.text:0000000000025BC0 var_4070 = -0x4070
.text:0000000000025BC0 var_4058 = -0x4058
.text:0000000000025BC0 var_4050 = -0x4050
.text:0000000000025BC0 var_4048 = -0x4048
脚本
适用 IDA Pro 9.x,ARM64,目标函数:qimei_core_generate(0x25BC0)
输出两类文件:
-
qimei_core_generate.bin:函数原始机器码二进制(可丢进 IDA/Ghidra 单独分析) -
qimei_core_generate_disasm.txt:完整反汇编文本,方便阅读
dumpFunc.py
import ida_funcs
import ida_bytes
import idautils
import idaapi
import ida_ua
import os
def dump_func_full(func_ea, out_bin_name="qimei_core_generate.bin", out_disasm_name="qimei_core_generate_disasm.txt"):
func = ida_funcs.get_func(func_ea)
if not func:
print(f"错误:找不到函数 @ {hex(func_ea)}")
return
print(f"函数 qimei_core_generate: start={hex(func.start_ea)}, end={hex(func.end_ea)}")
chunks = list(idautils.Chunks(func.start_ea))
print(f"检测到函数碎片数量: {len(chunks)}")
# 拼接全部碎片原始二进制
all_raw = b""
for chunk_start, chunk_end in chunks:
chunk_data = ida_bytes.get_bytes(chunk_start, chunk_end - chunk_start)
all_raw += chunk_data
# 计算绝对路径
bin_fullpath = os.path.abspath(out_bin_name)
disasm_fullpath = os.path.abspath(out_disasm_name)
with open(bin_fullpath, "wb") as f:
f.write(all_raw)
print(f"✅ 合并全部碎片机器码保存至: {bin_fullpath},总字节: {len(all_raw)}")
# 导出反汇编文本
disasm_lines = []
for chunk_start, chunk_end in chunks:
ea = chunk_start
while ea < chunk_end:
insn = ida_ua.insn_t()
if ida_ua.decode_insn(insn, ea):
# line = idaapi.generate_disasm_line(ea, 0) 第二个参数**flags 传 0 在 IDA9.3 SP2 ARM64 会输出原始格式化标记字符 `SOH`(ASCII 0x01,控制字符)**,不是人类可读汇编文本。
line = idaapi.generate_disasm_line(ea, idaapi.GENDSM_FORCE_CODE)
disasm_lines.append(f"{hex(ea):<16} {line}")
ea += insn.size
else:
ea += 1
with open(disasm_fullpath, "w", encoding="utf-8") as f:
f.write("\n".join(disasm_lines))
print(f"✅ 完整反汇编保存至: {disasm_fullpath}")
# 打印调用交叉引用
print("\n----- XrefsTo: 调用 qimei_core_generate 的位置 -----")
for xref in idautils.XrefsTo(func.start_ea):
print(f" call from: {hex(xref.frm)}")
# 入口
if __name__ == "__main__":
dump_func_full(0x25BC0)
- 优先:
idautils.Chunks遍历全部函数碎片(解决 OLLVM 拆分函数,完整导出全部代码) - 遍历指令改用
ida_ua规范 API,避开 FuncItems 类型 bug -
Chunks 是关键:OLLVM 控制流扁平化会把函数拆成多个不连续碎片,只用
start~end会漏掉部分代码,idautils.Chunks会取出全部片段,合并 bin 才完整。 - 输出的
qimei_core_generate.bin:所有碎片按地址顺序拼接,不是原 ELF 内存连续块,单独加载进 IDA 时,基址填原库基址,按顺序加载即可。
重要说明(libqimei.so 这个超大混淆函数重点)

打开汇编文本-有乱码
dumpFunc_tag_remove.py
import ida_funcs
import ida_bytes
import idautils
import idaapi
import ida_ua
import os
def dump_func_full(func_ea,
out_bin_name="qimei_core_generate.bin",
out_disasm_name="qimei_core_generate_disasm_fixed.txt"):
func = ida_funcs.get_func(func_ea)
if not func:
print(f"错误:找不到函数 @ {hex(func_ea)}")
return
print(f"函数 qimei_core_generate: start={hex(func.start_ea)}, end={hex(func.end_ea)}")
chunks = list(idautils.Chunks(func.start_ea))
print(f"检测到函数碎片数量: {len(chunks)}")
# 1、导出原始二进制(bin文件是好的,不变)
all_raw = b""
for chunk_start, chunk_end in chunks:
chunk_data = ida_bytes.get_bytes(chunk_start, chunk_end - chunk_start)
all_raw += chunk_data
bin_fullpath = os.path.abspath(out_bin_name)
with open(bin_fullpath, "wb") as f:
f.write(all_raw)
print(f"✅ bin: {bin_fullpath} 总字节:{len(all_raw)}")
# 2、导出汇编:使用 tag_remove() 清除IDA内部 !reg! )!xxx! 标记
disasm_lines = []
for chunk_start, chunk_end in chunks:
ea = chunk_start
while ea < chunk_end:
insn = ida_ua.insn_t()
insn_len = ida_ua.decode_insn(insn, ea)
if insn_len <= 0:
ea += 1
continue
raw_line = idaapi.generate_disasm_line(ea, idaapi.GENDSM_FORCE_CODE)
# ===== 关键:tag_remove 剥离IDA所有内部标记符号!官方API =====
clean_line = idaapi.tag_remove(raw_line)
disasm_lines.append(f"{hex(ea):<18} {clean_line}")
ea += insn_len
disasm_fullpath = os.path.abspath(out_disasm_name)
with open(disasm_fullpath, "w", encoding="utf‑8") as f:
f.write("\n".join(disasm_lines))
print(f"✅ 修复后disasm: {disasm_fullpath}")
print("\n----- XrefsTo: 调用 qimei_core_generate -----")
for xref in idautils.XrefsTo(func.start_ea):
print(f" call from: {hex(xref.frm)}")
if __name__ == "__main__":
dump_func_full(0x25BC0)

打开汇编文本-去tag