-
Notifications
You must be signed in to change notification settings - Fork 22
/
ipcbase.py
213 lines (190 loc) · 5.92 KB
/
ipcbase.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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import types
from util import *
services = {}
def register(name):
def sub(cls):
cls.serviceName = name
services[name] = cls
return cls
return sub
def command(request):
def sub(func):
func.cmdId = request
return func
return sub
class stub(object):
def __init__(self, cmdId=None):
self.cmdId = cmdId
self._data = []
self.movedHandles = []
self.copiedHandles = []
def data(self, *data):
self._data += list(data)
return self
def moveHandle(self, cls, *args, **kwargs):
self.movedHandles.append((cls, args, kwargs))
return self
def copyHandle(self, cls, *args, **kwargs):
self.copiedHandles.append((cls, args, kwargs))
return self
def __call__(self, message):
print 'Stub %s handler for %r to %r' % (self.name, message, self.service)
msg = IPCMessage(0)
msg = msg.data(*self._data)
for cls, args, kwargs in self.movedHandles:
if isinstance(cls, type) and issubclass(cls, IPCService):
args = [self.service.ipc] + list(args)
if callable(cls):
msg = msg.moveHandle(cls(*args, **kwargs))
else:
msg = msg.moveHandle(cls)
for cls, args, kwargs in self.copiedHandles:
if isinstance(cls, type) and issubclass(cls, IPCService):
args = [self.service.ipc] + list(args)
if callable(cls):
msg = msg.copyHandle(cls(*args, **kwargs))
else:
msg = msg.copyHandle(cls)
return msg
def partial(origcls):
def sub(newcls):
for x in dir(newcls):
if x != '__setup__' and x.startswith('__'):
continue
func = getattr(newcls, x)
ofunc = getattr(origcls, x)
if isinstance(func, stub):
fsub = func
else:
fsub = func.__func__
if hasattr(func, 'cmdId'):
fsub.cmdId = func.cmdId
if hasattr(fsub, 'cmdId'):
assert fsub.cmdId is None or fsub.cmdId == ofunc.cmdId
if hasattr(ofunc, 'cmdId'):
fsub.cmdId = ofunc.cmdId
setattr(origcls, x, fsub)
return sub
class IPCService(object):
def __init__(self, ipc, *args, **kwargs):
self.ipc = ipc
self.ctu = ipc.ctu
self.commands = {}
for name in dir(self):
func = getattr(self, name)
if hasattr(func, 'cmdId'):
self.commands[func.cmdId] = func
if isinstance(func, stub):
func.service = self
func.name = name
self.__setup__(*args, **kwargs)
def __setup__(self):
pass
def dispatch(self, handle, buffer):
incoming = IPCMessage().unpack(buffer)
print incoming
for addr, size, _ in incoming.bDescriptors:
if size == 0:
continue
self.ctu.checkwrite(addr, size, unset=True, trigger=True)
self.ctu.writemem(addr, '\0' * size, check=False)
for addr, size in incoming.cDescriptors:
if size == 0:
continue
print `addr, size`
self.ctu.checkwrite(addr, size, unset=True, trigger=True)
self.ctu.writemem(addr, '\0' * size, check=False)
print self, incoming
resp = self.handle(handle, incoming)
if isinstance(resp, tuple):
ret, resp = resp
else:
ret, resp = 0, resp
if isinstance(resp, IPCMessage):
#print ', '.join('%08x' % x for x in resp.pack())
if resp.type == -1:
resp.type = 0
return ret, resp.pack()
elif isinstance(resp, int) or isinstance(resp, long) or resp is None:
return ret, IPCMessage(resp if resp is not None else 0).setType(0).pack()
else:
return ret, resp
def handle(self, handle, message):
if message.type == 5:
if (5, message.cmdId) in self.commands:
return self.commands[(5, message.cmdId)](message)
print 'Unhandled message to %s: %r' % (self.__class__.__name__, message)
self.ipc.ctu.debugbreak()
elif message.type == 4:
if message.cmdId in self.commands:
return self.commands[message.cmdId](message)
print 'Unhandled message to %s: %r' % (self.__class__.__name__, message)
self.ipc.ctu.debugbreak()
elif message.type == 2:
print 'Closing handle for', self
self.ctu.closeHandle(handle)
return 0, IPCMessage(0).setType(0).pack()
else:
print 'Unknown message type to %s: %r' % (self.__class__.__name__, message)
self.ipc.ctu.debugbreak()
@command((5, 0))
def ConvertSessionToDomain(self, message):
dd = DomainDispatcher(self.ipc)
id = dd.add(self)
self.ctu.replaceHandle(self, dd)
return IPCMessage(0).data(id)
@command((5, 2))
def DuplicateSession(self, message):
return IPCMessage(0).moveHandle(self)
@command((5, 3))
def QueryPointerBufferSize(self, message):
return IPCMessage(0).data(0x500)
@command((5, 4))
def DuplicateSessionEx(self, message):
return IPCMessage(0).moveHandle(self)
class DomainDispatcher(IPCService):
def __init__(self, ipc):
IPCService.__init__(self, ipc)
self.handles = {}
self.handleIter = 0xefff
def add(self, obj):
self.handleIter += 1
self.handles[self.handleIter] = obj
return self.handleIter
def dispatch(self, handle, buffer):
print 'Domain dispatcher got a buffer!'
incoming = IPCMessage().unpack(buffer, domain=True)
print incoming
if incoming.type == 2:
print 'Closing domain dispatcher'
self.ctu.closeHandle(handle)
return 0, IPCMessage(0).setType(0).pack()
elif incoming.type == 5:
print 'Type 5 to domain dispatch...'
return IPCService.dispatch(self, handle, buffer)
dcmd, sicount, rawsize, objid = incoming.domainParams
if dcmd == 1:
print 'Passthrough message for', self.handles[objid]
ret, buf = self.handles[objid].dispatch(None, incoming.pack() + [None] * 16)
if buf is not None:
msg = IPCMessage().unpack(buf + [None] * 16, request=False)
if len(msg.movedHandles) != 0:
repl = []
for hnd in msg.movedHandles:
repl.append(self.add(self.ctu.handles[hnd]))
del self.ctu.handles[hnd]
msg.movedHandles = []
msg.data = repl + msg.data
buf = msg.pack(domain=True)
print 'Repacked passthrough message for domain'
return ret, buf
elif dcmd == 2:
obj = self.handles[objid]
print 'Close virtual handle', obj
if hasattr(obj, 'close'):
obj.close()
del self.handles[objid]
return 0, IPCMessage(0).setType(0).pack()
else:
print 'Unhandled domain dispatch command: %x %x %x %x' % (dcmd, sicount, rawsize, objid)
self.ctu.debugbreak()