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
|
#!/usr/bin/env python3
# gr_walk.py - find the RM window memdesc records in the guest's own RAM
# (via /proc/kcore direct map) and walk their kernel page-list pointers in
# the SAME pass (addresses go stale otherwise). Prints VA->PA candidates.
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 main():
kc = gps.Kcore()
if not kc.load():
print("# kcore load failed"); return 1
pov = kc.page_offset_base
print("# page_offset_base=0x%x" % pov)
found = []
CH = 1 << 20
pa = 0x100000000
end = 0x180000000
while pa < end and len(found) < 12:
va = pov + pa
d = kc.read(va, 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+0x60]))
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]
kptrs = [struct.unpack_from("<Q", rec, o)[0] for o in (0x18, 0x20, 0x28, 0x30, 0x38)]
print("rec@0x%x size=0x%x pa=0x%x kptrs=%s" %
(gpa, size, wpa, ["0x%x" % k for k in kptrs]))
# walk each kptr for PA-like lists
for kp in kptrs:
if not gps.is_kern_ptr(kp):
continue
dd = kc.read(kp, 0x80)
if not dd:
print(" kptr 0x%x: unreadable" % kp); continue
words = struct.unpack_from("<%dQ" % (len(dd)//8), dd, 0)
pas = [w for w in words if 0x100000000 <= w < 0x180000000]
npas = [w for w in words if 0x100000000 <= (w & ~0xfff) < 0x180000000]
print(" kptr 0x%x: %s" % (kp, " ".join("0x%x" % w for w in words[:10])))
if len(npas) >= 2:
print(" PA-like: %s" % ["0x%x" % w for w in npas[:16]])
return 0
if __name__ == "__main__":
sys.exit(main())
|