虚拟环境#

idapyswitch 换到虚拟环境的底层版本的 dylib(虚拟环境没有dylib)

# ~/.idapro/idapythonrc.py
import os
import sys
import site

# pyenv virtualenv 根目录
VENV = os.path.expanduser("~/.pyenv/versions/reverse")

# 兼容 macOS / Linux
py_ver = f"python{sys.version_info.major}.{sys.version_info.minor}"
site_pkgs = os.path.join(VENV, "lib", py_ver, "site-packages")

# 把 venv/bin 放进 PATH,方便 subprocess 找到该环境下的命令
venv_bin = os.path.join(VENV, "bin")
os.environ["PATH"] = venv_bin + os.pathsep + os.environ.get("PATH", "")
os.environ["VIRTUAL_ENV"] = VENV

# 把虚拟环境 site-packages 接入 IDA 当前解释器
if os.path.isdir(site_pkgs):
    site.addsitedir(site_pkgs)

# 把用户包目录也并入
user_site = os.path.join(VENV, "lib", py_ver, "site-packages")
if os.path.isdir(user_site) and user_site not in sys.path:
    sys.path.insert(0, user_site)

print("[idapythonrc] VIRTUAL_ENV =", os.environ.get("VIRTUAL_ENV"))
print("[idapythonrc] site-packages =", site_pkgs)
print("[idapythonrc] sys.executable =", sys.executable)
print("[idapythonrc] sys.version =", sys.version)

vscode setting.json 配置#

加入:

{
    "python.analysis.extraPaths": [
    "/Applications/IDA Professional 9.2.app/Contents/MacOS/python",
  ],
    "python.autoComplete.extraPaths": [
    "/Applications/IDA Professional 9.2.app/Contents/MacOS/python",
  ],
}

the Legend of Zelda Ⅲ 可打印字符映射

f = ida_funcs.get_func(0x131F)

def find_xor_sub(ea):
    """ Return the second operand of xor and sub """
    f = ida_funcs.get_func(ea)
    for ea in Heads(f.start_ea, f.end_ea):
        insn = idaapi.insn_t()
        idaapi.decode_insn(insn, ea)
        if idaapi.decode_insn(insn, ea):
            if insn.itype == idaapi.NN_xor:
                xor_val = insn.ops[1].value
            if insn.itype == idaapi.NN_sub:
                sub_val = insn.ops[1].value
                return [xor_val, sub_val]

print("==============================\n")
correct_path = ['A', 'V', 'T', 'S', 'J', 'U', 'N', 'B', 'C', 'P', 'I', 'B', 'K', 'A', 'M', 'Q', 'F', 'Q', 'T', 'Z']
map = {node:0 for node in correct_path}
for ea in Heads(f.start_ea, f.end_ea):
    insn = idaapi.insn_t()
    idaapi.decode_insn(insn, ea)
    if ida_idp.is_call_insn(insn):
        input_val = get_wide_byte(ea-15)
        op = insn.ops[0]
        if op.type == ida_ua.o_near or op.type == ida_ua.o_mem:
            target_addr = op.addr
            idc.jumpto(target_addr)
            f_in = ida_funcs.get_func(target_addr)
            xor_val, sub_val = find_xor_sub(target_addr)
            returned_val = chr((input_val ^ xor_val) - sub_val)
            if returned_val in map:
                    map[returned_val] = chr(input_val)
        if target_addr != ida_idaapi.BADADDR and ida_funcs.get_func(target_addr):
            func_name = f"Here from '{chr(input_val)}' to '{returned_val}'"
            idc.set_cmt(ea, func_name, 1)
            print(ida_funcs.get_func_name(target_addr))
            
        print("Call at %x" % ea)
        
idc.jumpto(0x131F)
print("==============================\n")

print(''.join([map[node] for node in correct_path])