Skip to content

Instantly share code, notes, and snippets.

@jimmy947788
Last active August 26, 2025 15:27
Show Gist options
  • Select an option

  • Save jimmy947788/7e91f1ddb0f853be17012e8769e5883d to your computer and use it in GitHub Desktop.

Select an option

Save jimmy947788/7e91f1ddb0f853be17012e8769e5883d to your computer and use it in GitHub Desktop.
该脚本用于在 IDA 中查找 ARM64 架构的 SVC 指令,并添加注释显示系统调用号对应的系统调用名称。
# IDA 9.1 / Python 3.x
# 更快的 ARM64 SVC 標註器:單次遍歷 + 狀態機追蹤 W8/X8 的 syscall 立即數
# Author: Jimmy(優化版 by ChatGPT)
# Note: 依賴你提供的 syscall_mapping(已內嵌),支援 MOV/MOVZ/ORR(wzr/xzr)三種常見立即數寫入型式。
import idaapi
import idautils
import idc
import ida_funcs
import ida_segment
import ida_kernwin
VERBOSE = False # 需要詳細日誌時設 True
ONLY_SVC_ZERO = True # 只對 SVC #0 標註(常見 Linux aarch64 約定)
# === 系統呼叫映射(來源:你的原始腳本) ===========================
syscall_mapping = {
0: "__NR_io_setup", 1: "__NR_io_destroy", 2: "__NR_io_submit", 3: "__NR_io_cancel",
4: "__NR_io_getevents", 5: "__NR_setxattr", 6: "__NR_lsetxattr", 7: "__NR_fsetxattr",
8: "__NR_getxattr", 9: "__NR_lgetxattr", 10: "__NR_fgetxattr", 11: "__NR_listxattr",
12: "__NR_llistxattr", 13: "__NR_flistxattr", 14: "__NR_removexattr", 15: "__NR_lremovexattr",
16: "__NR_fremovexattr", 17: "__NR_getcwd", 18: "__NR_lookup_dcookie", 19: "__NR_eventfd2",
20: "__NR_epoll_create1", 21: "__NR_epoll_ctl", 22: "__NR_epoll_pwait", 23: "__NR_dup",
24: "__NR_dup3", 25: "__NR_fcntl", 26: "__NR_inotify_init1", 27: "__NR_inotify_add_watch",
28: "__NR_inotify_rm_watch", 29: "__NR_ioctl", 30: "__NR_ioprio_set", 31: "__NR_ioprio_get",
32: "__NR_flock", 33: "__NR_mknodat", 34: "__NR_mkdirat", 35: "__NR_unlinkat",
36: "__NR_symlinkat", 37: "__NR_linkat", 38: "__NR_renameat", 39: "__NR_umount2",
40: "__NR_mount", 41: "__NR_pivot_root", 42: "__NR_nfsservctl", 43: "__NR_statfs",
44: "__NR_fstatfs", 45: "__NR_truncate", 46: "__NR_ftruncate", 47: "__NR_fallocate",
48: "__NR_faccessat", 49: "__NR_chdir", 50: "__NR_fchdir", 51: "__NR_chroot",
52: "__NR_fchmod", 53: "__NR_fchmodat", 54: "__NR_fchownat", 55: "__NR_fchown",
56: "__NR_openat", 57: "__NR_close", 58: "__NR_vhangup", 59: "__NR_pipe2",
60: "__NR_quotactl", 61: "__NR_getdents64", 62: "__NR_lseek", 63: "__NR_read",
64: "__NR_write", 65: "__NR_readv", 66: "__NR_writev", 67: "__NR_pread64",
68: "__NR_pwrite64", 69: "__NR_preadv", 70: "__NR_pwritev", 71: "__NR_sendfile",
72: "__NR_pselect6", 73: "__NR_ppoll", 74: "__NR_signalfd4", 75: "__NR_vmsplice",
76: "__NR_splice", 77: "__NR_tee", 78: "__NR_readlinkat", 79: "__NR_fstatat",
80: "__NR_fstat", 81: "__NR_sync", 82: "__NR_fsync", 83: "__NR_fdatasync",
84: "__NR_sync_file_range", 85: "__NR_timerfd_create", 86: "__NR_timerfd_settime",
87: "__NR_timerfd_gettime", 88: "__NR_utimensat", 89: "__NR_acct", 90: "__NR_capget",
91: "__NR_capset", 92: "__NR_personality", 93: "__NR_exit", 94: "__NR_exit_group",
95: "__NR_waitid", 96: "__NR_set_tid_address", 97: "__NR_unshare", 98: "__NR_futex",
99: "__NR_set_robust_list", 100: "__NR_get_robust_list", 101: "__NR_nanosleep",
102: "__NR_getitimer", 103: "__NR_setitimer", 104: "__NR_kexec_load",
105: "__NR_init_module", 106: "__NR_delete_module", 107: "__NR_timer_create",
108: "__NR_timer_gettime", 109: "__NR_timer_getoverrun", 110: "__NR_timer_settime",
111: "__NR_timer_delete", 112: "__NR_clock_settime", 113: "__NR_clock_gettime",
114: "__NR_clock_getres", 115: "__NR_clock_nanosleep", 116: "__NR_syslog",
117: "__NR_ptrace", 118: "__NR_sched_setparam", 119: "__NR_sched_setscheduler",
120: "__NR_sched_getscheduler", 121: "__NR_sched_getparam", 122: "__NR_sched_setaffinity",
123: "__NR_sched_getaffinity", 124: "__NR_sched_yield",
125: "__NR_sched_get_priority_max", 126: "__NR_sched_get_priority_min",
127: "__NR_sched_rr_get_interval", 128: "__NR_restart_syscall", 129: "__NR_kill",
130: "__NR_tkill", 131: "__NR_tgkill", 132: "__NR_sigaltstack", 133: "__NR_rt_sigsuspend",
134: "__NR_rt_sigaction", 135: "__NR_rt_sigprocmask", 136: "__NR_rt_sigpending",
137: "__NR_rt_sigtimedwait", 138: "__NR_rt_sigqueueinfo", 139: "__NR_rt_sigreturn",
140: "__NR_setpriority", 141: "__NR_getpriority", 142: "__NR_reboot",
143: "__NR_setregid", 144: "__NR_setgid", 145: "__NR_setreuid", 146: "__NR_setuid",
147: "__NR_setresuid", 148: "__NR_getresuid", 149: "__NR_setresgid", 150: "__NR_getresgid",
151: "__NR_setfsuid", 152: "__NR_setfsgid", 153: "__NR_times", 154: "__NR_setpgid",
155: "__NR_getpgid", 156: "__NR_getsid", 157: "__NR_setsid", 158: "__NR_getgroups",
159: "__NR_setgroups", 160: "__NR_uname", 161: "__NR_sethostname",
162: "__NR_setdomainname", 163: "__NR_getrlimit", 164: "__NR_setrlimit",
165: "__NR_getrusage", 166: "__NR_umask", 167: "__NR_prctl", 168: "__NR_getcpu",
169: "__NR_gettimeofday", 170: "__NR_settimeofday", 171: "__NR_adjtimex",
172: "__NR_getpid", 173: "__NR_getppid", 174: "__NR_getuid", 175: "__NR_geteuid",
176: "__NR_getgid", 177: "__NR_getegid", 178: "__NR_gettid", 179: "__NR_sysinfo",
180: "__NR_mq_open", 181: "__NR_mq_unlink", 182: "__NR_mq_timedsend", 183: "__NR_mq_timedreceive",
184: "__NR_mq_notify", 185: "__NR_mq_getsetattr", 186: "__NR_msgget", 187: "__NR_msgctl",
188: "__NR_msgrcv", 189: "__NR_msgsnd", 190: "__NR_semget", 191: "__NR_semctl",
192: "__NR_semtimedop", 193: "__NR_semop", 194: "__NR_shmget", 195: "__NR_shmctl",
196: "__NR_shmat", 197: "__NR_shmdt", 198: "__NR_socket", 199: "__NR_socketpair",
200: "__NR_bind", 201: "__NR_listen", 202: "__NR_accept", 203: "__NR_connect",
204: "__NR_getsockname", 205: "__NR_getpeername", 206: "__NR_sendto", 207: "__NR_recvfrom",
208: "__NR_setsockopt", 209: "__NR_getsockopt", 210: "__NR_shutdown", 211: "__NR_sendmsg",
212: "__NR_recvmsg", 213: "__NR_readahead", 214: "__NR_brk", 215: "__NR_munmap",
216: "__NR_mremap", 217: "__NR_add_key", 218: "__NR_rest_key", 219: "__NR_keyctl",
220: "__NR_clone", 221: "__NR_execve", 222: "__NR_mmap", 223: "__NR_fadvise64",
224: "__NR_swapon", 225: "__NR_swapoff", 226: "__NR_mprotect", 227: "__NR_msync",
228: "__NR_mlock", 229: "__NR_munlock", 230: "__NR_mlockall", 231: "__NR_munlockall",
232: "__NR_mincore", 233: "__NR_madvise", 234: "__NR_remap_file_pages", 235: "__NR_mbind",
236: "__NR_get_mempolicy", 237: "__NR_set_mempolicy", 238: "__NR_migrate_pages",
239: "__NR_move_pages", 240: "__NR_rt_tgsigqueueinfo", 241: "__NR_perf_event_open",
242: "__NR_accept4", 243: "__NR_recvmmsg", 244: "__NR_or1k_atomic", 260: "__NR_wait4",
261: "__NR_prlimit64", 262: "__NR_fanotify_init", 263: "__NR_fanotify_mark",
264: "__NR_name_to_handle_at", 265: "__NR_open_by_handle_at", 266: "__NR_clock_adjtime",
267: "__NR_syncfs", 268: "__NR_setns", 269: "__NR_sendmmsg", 270: "__NR_process_vm_readv",
271: "__NR_process_vm_writev", 272: "__NR_kcmp", 273: "__NR_finit_module",
274: "__NR_sched_setattr", 275: "__NR_sched_getattr", 276: "__NR_renameat2",
277: "__NR_seccomp", 278: "__NR_getrandom", 279: "__NR_memfd_create", 280: "__NR_bpf",
281: "__NR_execveat", 282: "__NR_userfaultfd", 283: "__NR_membarrier", 284: "__NR_mlock2",
285: "__NR_copy_file_range", 286: "__NR_preadv2", 287: "__NR_pwritev2"
}
# ===============================================================
def is_code_seg(seg):
return seg and (seg.perm & ida_segment.SEGPERM_EXEC) != 0
def write_to_x8_with_imm(ea):
"""
偵測是否為將立即數寫入 W8/X8 的常見型式:
1) MOV {W8|X8}, #imm
2) MOVZ {W8|X8}, #imm (忽略帶 lsl 的搬運)
3) ORR {W8|X8}, {WZR|XZR}, #imm
回傳 (True, imm) 或 (False, None)
若偵測到對 W8/X8 的寫入但非立即數,回傳 ('clobber', None) 表示應重置狀態。
"""
mnem = idc.print_insn_mnem(ea)
dst = idc.print_operand(ea, 0).upper()
if dst not in ("W8", "X8"):
return (False, None)
# MOV dst, #imm
if mnem == "MOV":
if idc.get_operand_type(ea, 1) == idc.o_imm:
return (True, idc.get_operand_value(ea, 1))
else:
return ("clobber", None)
# MOVZ dst, #imm (若帶 lsl,通常是拼 32/64 位,這裡保守略過)
if mnem == "MOVZ":
if idc.get_operand_type(ea, 1) == idc.o_imm:
# 粗略判斷是否有 lsl(避免錯讀 MOVZ+MOVK 序列中的高段)
asm = idc.generate_disasm_line(ea, 0) or ""
if "lsl" in asm.lower():
return ("clobber", None) # 可能是高 16 位,保守視為非立即數可用
return (True, idc.get_operand_value(ea, 1))
else:
return ("clobber", None)
# ORR dst, {WZR|XZR}, #imm => 等效 mov dst, #imm
if mnem == "ORR":
op1 = idc.print_operand(ea, 1).upper()
if op1 in ("WZR", "XZR") and idc.get_operand_type(ea, 2) == idc.o_imm:
return (True, idc.get_operand_value(ea, 2))
else:
return ("clobber", None)
# 其它對 W8/X8 的寫入(ADD, MOVK, MOVN, LDR, BL, etc.)視為污損
if dst in ("W8", "X8"):
return ("clobber", None)
return (False, None)
def is_svc(ea):
if idc.print_insn_mnem(ea) != "SVC":
return False
if ONLY_SVC_ZERO:
try:
return idc.get_operand_type(ea, 0) == idc.o_imm and idc.get_operand_value(ea, 0) == 0
except Exception:
return False
return True
def annotate(ea, sysno):
name = syscall_mapping.get(sysno, f"Unknown syscall {sysno}")
comment = f"System call: {name}"
# 1=repeatable comment,方便在多處顯示
idc.set_cmt(ea, comment, 1)
if VERBOSE:
print(f"[+] 注釋 {hex(ea)} -> {comment}")
def main():
ida_kernwin.show_wait_box("auto:ARM64 SVC 標註中…")
total_funcs = 0
total_hits = 0
for f_ea in idautils.Functions():
total_funcs += 1
# 只處理屬於可執行段的函式
seg = ida_segment.getseg(f_ea)
if not is_code_seg(seg):
continue
f_end = idc.get_func_attr(f_ea, idc.FUNCATTR_END)
current_sysno = None
if VERBOSE:
print(f"== 處理函式: {idc.get_func_name(f_ea)} ({hex(f_ea)}~{hex(f_end)})")
for ea in idautils.FuncItems(f_ea):
# 快速過濾:非代碼指令直接跳過
if not idc.is_code(idc.get_full_flags(ea)):
continue
# 嘗試匹配對 W8/X8 的立即數寫入
flag, imm = write_to_x8_with_imm(ea)
if flag is True:
current_sysno = imm
if VERBOSE:
print(f" 捕獲 syscall #{imm} at {hex(ea)}")
continue
elif flag == "clobber":
# 任一非立即數寫入視為污染,重置
current_sysno = None
continue
# 匹配 SVC 並標註
if is_svc(ea) and current_sysno is not None:
annotate(ea, current_sysno)
total_hits += 1
# 標註完可選擇重置(避免跨基本塊污染);這裡保守重置
current_sysno = None
ida_kernwin.hide_wait_box()
ida_kernwin.info(f"完成:掃描 {total_funcs} 個函式,標註 {total_hits} 處 SVC。")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment