-
Notifications
You must be signed in to change notification settings - Fork 45
/
extract_vmcall_handler_table_apply_idb.py
169 lines (147 loc) · 5.92 KB
/
extract_vmcall_handler_table_apply_idb.py
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# -*- coding: utf-8 -*-
# Description:
# - Find Hypercall Dispatch Table
# - Extract all Hypercalls inlcuding undocumented after end
# - Fix up IDB - renaming func_ptr to hypercall name and setting stuct field sizes
# - Create .h with all call codes in table
# Assuming base of 0x0
import sys
import idaapi
from collections import namedtuple
# Apply to IDB
APPLY_TO_IDB = True
hypercalls_from_pdf_path = 'HypercallsOnlyFromPdf.h'
hypercalls_undoc_path = 'Hypercalls.h'
HypercallDispatchFormat = namedtuple('HypercallDispatchFormat',
['func_ptr',
'call_code',
'is_rep_call',
'input_size_1',
'input_size_2',
'output_size_1',
'output_size_2',
'unkw'])
HypercallDefine = namedtuple('HypercallDefine',
['define',
'hypercall_name',
'call_code'])
# Hypercall table alway seems to appear in segment "CONST"
hypercall_dispatch_table = idaapi.get_segm_by_name("CONST").startEA
print '[+] Hypercall Dispatch Table: ' + hex(hypercall_dispatch_table)
# Find +X segment
segX_start = 0
segX_end = 0
for ea in idautils.Segments():
seg = idaapi.getseg(ea)
if seg and (seg.perm & idaapi.SEGPERM_EXEC):
SigmName = idc.SegName(ea)
print '[+] Segments with +X permission: ' + SigmName
segX_start = seg.startEA
segX_end = seg.endEA
# Loop through hypercall table
hypercalls = []
valid_hypercall = True
addr = hypercall_dispatch_table
while valid_hypercall:
func_ptr = idaapi.get_qword(addr)
# Set struct field sizes in IDA in the HypercallDispatchFormat format
if APPLY_TO_IDB:
MakeQword(addr)
addr += 8
call_code = idaapi.get_word(addr)
if APPLY_TO_IDB:
MakeWord(addr)
addr += 2
is_rep_call = idaapi.get_word(addr)
if APPLY_TO_IDB:
MakeWord(addr)
addr += 2
input_size_1 = idaapi.get_word(addr)
if APPLY_TO_IDB:
MakeWord(addr)
addr += 2
input_size_2 = idaapi.get_word(addr)
if APPLY_TO_IDB:
MakeWord(addr)
addr += 2
output_size_1 = idaapi.get_word(addr)
if APPLY_TO_IDB:
MakeWord(addr)
addr += 2
output_size_2 = idaapi.get_word(addr)
if APPLY_TO_IDB:
MakeWord(addr)
addr += 2
unkw = idaapi.get_dword(addr)
if APPLY_TO_IDB:
MakeDword(addr)
addr += 4
# A valid hypercall struct will contain a valid func_ptr
if func_ptr >= segX_start and func_ptr <= segX_end:
hypercalls.append(HypercallDispatchFormat(func_ptr=func_ptr, call_code=call_code, is_rep_call=is_rep_call, input_size_1=input_size_1, input_size_2=input_size_2, output_size_1=output_size_1, output_size_2=output_size_2, unkw=unkw))
else:
valid_hypercall = False
break
# Get hypercall names from C header Hypercalls.h
hypercall_format_size = 24
hypercall_define = []
# Open Hypercalls.h
with open(hypercalls_from_pdf_path, 'rb') as hypercalls_pdf_h:
for line in hypercalls_pdf_h:
# Find #define per line
if re.match('\\s*#define.*', line):
# Get rid of new lines at end
line = re.sub('\r\n|\r|\n', '', line)
# Get rid of indent for some #defines
line = re.sub('\\s*#define', '#define', line)
if len(line.split(' ')) != 3:
print '[-] Something went wrong with ' + line
hypercall_define.append(HypercallDefine(*line.split(' ')))
# Link up hypercall name from .h file with func_ptrs found from this .idb
for hypercall in hypercalls:
# Use call_code as index into dispatch table
func_ptr_hc = idc.get_qword(hypercall_dispatch_table + (hypercall_format_size * hypercall.call_code))
for define in hypercall_define:
# Use call_code to get hypercall name from header #defines
define_callcode = int(define.call_code, 16)
if define_callcode == hypercall.call_code:
#print define.hypercall_name, hex(hypercall.call_code)
# Fix IDB
if APPLY_TO_IDB:
MakeNameEx(func_ptr_hc, define.hypercall_name, SN_NOWARN)
MakeCode(func_ptr_hc)
MakeFunction(func_ptr_hc)
# Create C .h file of all hypercalls
with open(hypercalls_undoc_path, 'w+') as hypercalls_h:
addr = hypercall_dispatch_table
valid_hypercall = True
hypercalls_h.write('//\n// Auto-generated file from extract_vmcall_handler_table.py\n//\n')
hypercalls_h.write('typedef struct { const CHAR *name; UINT16 callcode; UINT16 isRep; UINT16 inputSize; UINT16 outputSize; } HYPERCALL_ENTRY;\n\n')
hypercalls_h.write('HYPERCALL_ENTRY HypercallEntries[] = {\n')
while valid_hypercall:
func_ptr = idaapi.get_qword(addr)
addr += 8
call_code = idaapi.get_word(addr)
addr += 2
is_rep_call = idaapi.get_word(addr)
addr += 2
input_size_1 = idaapi.get_word(addr)
addr += 2
input_size_2 = idaapi.get_word(addr)
addr += 2
output_size_1 = idaapi.get_word(addr)
addr += 2
output_size_2 = idaapi.get_word(addr)
addr += 2
unkw = idaapi.get_dword(addr)
addr += 4
if func_ptr >= segX_start and func_ptr <= segX_end:
func_name = GetFunctionName(func_ptr)
# Get rid of python 'L' -_-
call_code_str = hex(call_code)[:-1]
func_name = re.sub('Reserved....', 'Reserved' + call_code_str, func_name)
hypercalls_h.write('{"' + func_name + '", ' + call_code_str + ', ' + str(is_rep_call) + ', ' + str(input_size_1) + ', ' + str(output_size_1) +'},\n')
else:
valid_hypercall = False
break
hypercalls_h.write('};\n')