Rizin
unix-like reverse engineering framework and cli tools
machtraps.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 #
3 # SPDX-FileCopyrightText: 2019 Francesco Tamagni <mrmacete@protonmail.ch>
4 # SPDX-License-Identifier: LGPL-3.0-only
5 #
6 # -*- coding: utf-8 -*-
7 
8 """
9 Example usage to regenerate traps.json:
10  - open the dyld cache in rizin like this:
11 RZ_DYLDCACHE_FILTER=libsystem_kernel rizin -e bin.usextr=false ~/Library/Developer/Xcode/iOS\ DeviceSupport/12.1.2\ \‍(16C101\‍)\ arm64e/Symbols/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e
12 
13  - run the script with this command:
14  #!pipe python3 /path/to/this/script.py > traps.json
15 
16 """
17 
18 import json
19 import re
20 
21 import rzpipe
22 
23 r = rzpipe.open()
24 
25 
26 def walk_back_until(addr, pattern, min_addr):
27  cursor = addr
28  while cursor >= min_addr:
29  op = r.cmdj("aoj@" + str(cursor))[0]["opcode"]
30  if re.search(pattern, op) != None:
31  return cursor + 4
32  if re.search(r"^ret", op) != None:
33  return cursor + 4
34  if re.search(r"^b ", op) != None:
35  return cursor + 4
36  cursor -= 4
37 
38  return min_addr
39 
40 
41 def carve_trap_num(addr, flag):
42  saved_seek = r.cmd("?v $$")
43  r.cmd("e io.cache=true")
44  r.cmd("e emu.write=true")
45  r.cmd("aei")
46  r.cmd("aeim")
47  min_addr = int(r.cmd("?v " + flag), 0)
48  emu_start = walk_back_until(addr - 4, r"^b|^ret|^invalid", min_addr)
49  r.cmd("s " + str(emu_start))
50  obj = r.cmd("aefa 0x%08x~[0]:0" % addr)
51  r.cmd("s " + saved_seek)
52  val = r.cmdj("pv4j @ %s+0x14" % obj.strip())[0]["value"]
53  if val == 0:
54  val = r.cmdj("pv4j @ %s+0x18" % obj.strip())[0]["value"]
55  return val
56 
57 
58 def beautify_name(name):
59  return re.sub(r"^_", "", name)
60 
61 
63  msgs = r.cmdj("axtj @ sym._mach_msg")
64  if len(msgs) == 0:
65  r.cmd("s sym._mach_msg")
66  r.cmd("aae $SS @ $S")
67  r.cmd("shu")
68  msgs = r.cmdj("axtj @ sym._mach_msg")
69  if len(msgs) == 0:
70  print("Cannot find refs to mach_msg!")
71  return
72 
73  traps = {}
74  for ref in msgs:
75  if ref["type"] != "CALL" or "realname" not in ref:
76  continue
77  name = ref["realname"]
78  if re.search(r"^_mach_msg", name) != None:
79  continue
80  addr = ref["from"]
81  traps[addr] = {"name": name}
82 
83  result = []
84  for addr in traps:
85  trap = traps[addr]
86  flag = "sym.%s" % trap["name"]
87  trap["name"] = beautify_name(trap["name"])
88  trap["num"] = carve_trap_num(addr, flag)
89  if trap["num"] != None:
90  result.append(trap)
91 
92  result.sort(key=lambda x: x["num"])
93 
94  return result
95 
96 
97 if __name__ == "__main__":
98  traps = carve_traps()
99  print(json.dumps(traps, indent=4))
size_t len
Definition: 6502dis.c:15
def beautify_name(name)
Definition: machtraps.py:58
def carve_traps()
Definition: machtraps.py:62
def carve_trap_num(addr, flag)
Definition: machtraps.py:41
def walk_back_until(addr, pattern, min_addr)
Definition: machtraps.py:26
static int
Definition: sfsocketcall.h:114