-
Notifications
You must be signed in to change notification settings - Fork 81
Expand file tree
/
Copy pathtagged_pointers.py
More file actions
81 lines (66 loc) · 2.62 KB
/
tagged_pointers.py
File metadata and controls
81 lines (66 loc) · 2.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#
# ida_kernelcache/tagged_pointers.py
# Brandon Azad
#
"""ida_kernelcache.tagged_pointers
This module is responsible for processing the tagged pointers in the new iOS 12 kernelcache and
replacing them with their untagged equivalents. All found pointers are also converted into offsets.
In an alternative implementation, we could just add cross-references in IDA. However, I think this
approach is better because it is closer to what the kernelcache looks like at runtime.
"""
import idc
import idautils
import ida_utilities as idau
import kernel
_log = idau.make_log(1, __name__)
def tagged_pointer_tag(tp):
return (tp >> 48) & 0xffff
def tagged_pointer_untag(tp):
return tp | 0xffff000000000000
def is_tagged_pointer_format(value):
return tagged_pointer_tag(value) != 0xffff and \
(value & 0x0000ffff00000000) == 0x0000fff000000000
def is_tagged_pointer(value):
return is_tagged_pointer_format(value) and \
idau.is_mapped(tagged_pointer_untag(value), value=False)
def tagged_pointer_link(tag):
return (tag >> 1) & ~0x3
def tagged_pointer_next(ea, tp, end=None):
assert ea
# First try to get the offset to the next link.
if tp:
link_offset = tagged_pointer_link(tagged_pointer_tag(tp))
if link_offset:
return ea + link_offset
# Skip the current tagged pointer in preparation for scanning.
ea += idau.WORD_SIZE
# We don't have a link. Do a forward scan until we find the next tagged pointer.
_log(3, 'Scanning for next tagged pointer')
if end is None:
end = idc.SegEnd(ea)
for value, value_ea in idau.ReadWords(ea, end, step=4, addresses=True):
if is_tagged_pointer(value):
return value_ea
# If we didn't find any tagged pointers at all, return None.
return None
def untag_pointer(ea, tp):
_log(4, 'Untagging pointer at {:x}', ea)
idau.patch_word(ea, tagged_pointer_untag(tp))
idc.OpOff(ea, 0, 0)
def untag_pointers_in_range(start, end):
assert kernel.kernelcache_format == kernel.KC_12_MERGED, 'Wrong kernelcache format'
ea, tp = start, None
while True:
ea = tagged_pointer_next(ea, tp, end)
if ea is None or ea >= end:
break
tp = idau.read_word(ea)
if not is_tagged_pointer(tp):
_log(1, 'Tagged pointer traversal failed: ea={:x}, tp={:x}'.format(ea, tp))
break
untag_pointer(ea, tp)
def untag_pointers():
_log(2, 'Starting tagged pointer conversion')
for seg in idautils.Segments():
untag_pointers_in_range(idc.SegStart(seg), idc.SegEnd(seg))
_log(2, 'Tagged pointer conversion complete')