-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathLabel3dsCTRFns.py
181 lines (144 loc) · 6.54 KB
/
Label3dsCTRFns.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
170
171
172
173
174
175
176
177
178
179
180
181
# Labels 3ds CTR lib functions
# @category 3ds
#
from collections import Counter
from ghidra_utils import bytesToByteArr, nameCtrFunc, findFirstByteArray, readBytes, getCallArgs, getValueFromConstantVarnode, getOrCreateNamespace
from ctr_services import getCommandName, service_handle_names
listing = currentProgram.getListing()
memory = currentProgram.getMemory()
def makeIpcHeader(command_id, normal_params, translate_params):
return command_id << 16 | (normal_params & 0x3f) << 6 | translate_params & 0x3f
def parseIpcVarNode(varnode):
addr = varnode.getAddress()
if addr.isRegisterAddress():
return None
if addr.isConstantAddress():
return addr.getOffset()
return memory.getInt(addr)
def nameIpcFunc(ipc_func, ipc_header, handle):
func_name = getCommandName(ipc_header, handle)
nameCtrFunc(ipc_func, func_name)
def nameIpcWrapperFunc(ipc_func, ipc_header, handle):
func_name = getCommandName(ipc_header, handle)
nameCtrFunc(ipc_func, func_name + '_wrapper')
def getConstantFromMov(mov_addr):
inst = listing.getInstructionContaining(mov_addr)
if inst is not None:
pcode_ops = inst.getPcode()
for pcode_op in pcode_ops:
if pcode_op.getMnemonic() == 'COPY':
varnode = pcode_op.getInputs()[0]
return getValueFromConstantVarnode(varnode)
return None
def getIpcHeaderFromAddr(addr):
ipc_header = getConstantFromMov(addr)
if ipc_header is None:
ipc_store_refs = getReferencesFrom(addr)
if len(ipc_store_refs) > 0:
ipc_header_addr = ipc_store_refs[0].getToAddress()
ipc_header = memory.getInt(ipc_header_addr)
return ipc_header
ctr_namespace = getOrCreateNamespace('ctr')
handles_by_caller_funcs = {}
for handle_name in service_handle_names:
handles = getSymbols(handle_name, ctr_namespace)
for handle in handles:
refs = getReferencesTo(handle.getAddress())
for ref in refs:
handle_name = handle.getName()
from_addr = ref.getFromAddress()
func_ref = getFunctionContaining(from_addr)
if func_ref is not None:
func_addr = func_ref.getEntryPoint()
handles_by_caller_funcs[func_addr] = handle_name
def getHandleOfIpcCommand(ipc_func):
return handles_by_caller_funcs.get(ipc_func.getEntryPoint())
# ---------------------------------------------------------------------------
# IPC functions using ipc_set_header
ipc_set_header_bytes = [0x10, 0xb5, 0x04, 0x46, 0x08, 0x46, 0x11, 0x46, 0x1a, 0x46, 0x02, 0x9b, 0xff, 0xff, 0xff, 0xff, 0x21, 0x68, 0x08, 0x60, 0x10, 0xbd]
ipc_set_header_mask = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
ipc_set_header_addr = findFirstByteArray(ipc_set_header_bytes, ipc_set_header_mask)
if ipc_set_header_addr is None:
ipc_make_header_refs = []
else:
ipc_make_header_refs = getReferencesTo(ipc_set_header_addr)
if ipc_make_header_refs is None:
ipc_make_header_refs = []
result = []
for ref in ipc_make_header_refs:
func = getFunctionContaining(ref.getFromAddress())
if func is not None:
result.append(func)
else:
print('Cannot find function for {}. Could this be part of a service command handler jump table?'.format(ref.getFromAddress()))
ipc_make_header_refs = result
dupliate_ipc_make_header_refs = []
unique_ipc_make_header_refs = []
for ref, count in Counter(ipc_make_header_refs).items():
if count > 1:
dupliate_ipc_make_header_refs.append(ref)
else:
unique_ipc_make_header_refs.append(ref)
# If a function sets a header multiple times, it's likely a command handler
for ipc_func in dupliate_ipc_make_header_refs:
nameCtrFunc(ipc_func, 'handleServiceCommand')
for ipc_func in unique_ipc_make_header_refs:
args = getCallArgs(ipc_func, ipc_set_header_addr)
if len(args) < 4:
print('Bad number of args at {}'.format(ipc_set_header_addr))
else:
command_id = parseIpcVarNode(args[1])
normal_params = parseIpcVarNode(args[2])
translate_params = parseIpcVarNode(args[3])
if command_id is not None and normal_params is not None and translate_params is not None:
ipc_header = makeIpcHeader(command_id, normal_params, translate_params)
handle = getHandleOfIpcCommand(ipc_func)
nameIpcFunc(ipc_func, ipc_header, handle)
# ---------------------------------------------------------------------------
# IPC functions using inlined svc_sync_sync_request
svc_send_sync_request = bytesToByteArr([0x32, 0x00, 0x00, 0xef])
svc_send_sync_request_mask = bytesToByteArr([0xff, 0xff, 0xff, 0xff])
func_start_bytes = bytesToByteArr([0x00, 0x00, 0x0d, 0xe9])
func_start_mask = bytesToByteArr([0x00, 0x00, 0x0f, 0xff])
get_thread_local_storage_bytes = bytesToByteArr([0x70, 0x4f, 0x1d, 0xee])
get_thread_local_storage_mask = bytesToByteArr([0xff, 0x0f, 0xff, 0xff])
start_address = memory.getExecuteSet().getMaxAddress()
while start_address is not None:
svc_send_sync_request_addr = memory.findBytes(start_address, svc_send_sync_request, svc_send_sync_request_mask, False, monitor)
if svc_send_sync_request_addr is None:
# No more functions
break
if readBytes(svc_send_sync_request_addr.add(4), 4) == bytesToByteArr([0x1e, 0xff, 0x2f, 0xe1]):
# Non-inlined svcSendSyncRequest
start_address = None
continue
ipc_func_addr = memory.findBytes(svc_send_sync_request_addr, func_start_bytes, func_start_mask, False, monitor)
if ipc_func_addr is None:
# No more functions
break
wrapper_func = None
ipc_func = getFunctionContaining(ipc_func_addr)
if ipc_func is None:
# Bad data
# We should probably check the section before assuming this
break
if not ipc_func.getEntryPoint().equals(ipc_func_addr):
wrapper_func = ipc_func
ipc_func = createFunction(ipc_func_addr, 'UNKNOWN_CTR_IPC_FN')
ipc_func_body = ipc_func.getBody()
ipc_func_start = ipc_func_body.getMinAddress()
ipc_func_end = ipc_func_body.getMaxAddress()
get_thread_local_storage_addr = memory.findBytes(ipc_func_start, ipc_func_end, get_thread_local_storage_bytes, get_thread_local_storage_mask, True, monitor)
ipc_store_header_addr = get_thread_local_storage_addr.add(4)
ipc_header = None
while ipc_header is None and ipc_store_header_addr < svc_send_sync_request_addr:
ipc_header = getIpcHeaderFromAddr(ipc_store_header_addr)
ipc_store_header_addr = ipc_store_header_addr.add(4)
if ipc_header is None:
print('Cannot find ipc header for {}!'.format(ipc_func_addr))
continue
handle = getHandleOfIpcCommand(ipc_func)
nameIpcFunc(ipc_func, ipc_header, handle)
if wrapper_func is not None:
nameIpcWrapperFunc(wrapper_func, ipc_header, handle)
start_address = ipc_func_addr.subtract(4)