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
81
82
83
84
85
86
87
88
89
|
#!/usr/bin/env python3
# gr_walk2.py - deeper walk: from the window memdesc records, follow the
# kernel pointers 2-3 levels and search for page-array records
# {vmap_cpu, flags, PA, 0x1000} (2+ consecutive) to recover the page lists.
import sys, struct
sys.path.insert(0, "/tmp")
import guest_pin_stream as gps
PAT_SIZE = struct.pack("<Q", 0x20000)
PAT_FLAGS = struct.pack("<Q", 0x03008000)
def is_pa(v):
return 0x100000000 <= v < 0x180000000
def page_array_at(kc, va, n=0x400):
"""Return [(off, [PA,...])] for runs of {ptr,flags,PA,0x1000} records."""
d = kc.read(va, n)
if not d:
return []
out = []
i = 0
while i + 32 <= len(d):
p, fl, pa, z = struct.unpack_from("<4Q", d, i)
if z == 0x1000 and is_pa(pa) and gps.is_kern_ptr(p):
run = [pa]
j = i + 32
while j + 32 <= len(d):
p2, fl2, pa2, z2 = struct.unpack_from("<4Q", d, j)
if z2 == 0x1000 and is_pa(pa2):
run.append(pa2)
j += 32
else:
break
if len(run) >= 2:
out.append((i, run))
i = j
else:
i += 8
return out
def main():
kc = gps.Kcore()
if not kc.load():
print("# kcore load failed"); return 1
pov = kc.page_offset_base
# find memdesc records (fast direct-map scan)
found = []
CH = 1 << 20
pa = 0x100000000
while pa < 0x180000000 and len(found) < 12:
d = kc.read(pov + pa, CH)
if d:
st = 0
while True:
i = d.find(PAT_SIZE, st)
if i < 0:
break
st = i + 1
if i + 16 <= len(d) and d[i+8:i+16] == PAT_FLAGS:
found.append((pa + i, d[i:i+0x40]))
pa += CH
print("# memdesc records: %d" % len(found))
for (gpa, rec) in found:
size, flags = struct.unpack_from("<QQ", rec, 0)
wpa = struct.unpack_from("<Q", rec, 0x10)[0]
print("rec@0x%x size=0x%x pa=0x%x" % (gpa, size, wpa))
kptrs = [struct.unpack_from("<Q", rec, o)[0] for o in range(0x18, 0x40, 8)]
for kp in kptrs:
if not gps.is_kern_ptr(kp):
continue
# level 1: read the target, look for page arrays directly
for arr in page_array_at(kc, kp):
print(" L1 kptr 0x%x: page-array run at +0x%x: %s" %
(kp, arr[0], ["0x%x" % x for x in arr[1][:12]]))
# level 2: follow pointers in the target
d = kc.read(kp, 0x100)
if not d:
continue
for o in range(0, 0x100, 8):
p2 = struct.unpack_from("<Q", d, o)[0]
if not gps.is_kern_ptr(p2):
continue
for arr in page_array_at(kc, p2):
print(" L2 0x%x -> 0x%x: page-array at +0x%x: %s" %
(kp, p2, arr[0], ["0x%x" % x for x in arr[1][:12]]))
return 0
if __name__ == "__main__":
sys.exit(main())
|