mirror of
https://github.com/skelsec/aardwolf
synced 2026-06-08 17:28:11 +00:00
282 lines
9.7 KiB
Python
282 lines
9.7 KiB
Python
|
|
import io
|
|
import enum
|
|
from typing import List
|
|
|
|
from aardwolf.extensions.RDPECLIP.protocol.formatlist import CLIPBRD_FORMAT
|
|
|
|
class MAPPING_MODE(enum.Enum):
|
|
TEXT = 0x00000001 #Each logical unit is mapped to one device pixel. Positive x is to the right; positive y is down.
|
|
LOMETRIC = 0x00000002 #Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is up.
|
|
HIMETRIC = 0x00000003 #Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is up.
|
|
LOENGLISH = 0x00000004 #Each logical unit is mapped to 0.01 inch. Positive x is to the right; positive y is up.
|
|
HIENGLISH = 0x00000005 #Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is up.
|
|
TWIPS = 0x00000006 #Each logical unit is mapped to 1/20 of a printer's point (1/1440 of an inch), also called a twip. Positive x is to the right; positive y is up.
|
|
ISOTROPIC = 0x00000007 #Logical units are mapped to arbitrary units with equally scaled axes; one unit along the x-axis is equal to one unit along the y-axis.
|
|
ANISOTROPIC = 0x00000008
|
|
|
|
|
|
class CLIPRDR_MFPICT:
|
|
def __init__(self):
|
|
self.mappingMode:MAPPING_MODE = None
|
|
self.xExt:int = None
|
|
self.yExt:int = None
|
|
self.metaFileData:bytes = None
|
|
|
|
def to_bytes(self):
|
|
t = self.mappingMode.value.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.xExt.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.yExt.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.metaFileData
|
|
return t
|
|
|
|
@staticmethod
|
|
def from_bytes(bbuff: bytes):
|
|
return CLIPRDR_MFPICT.from_buffer(io.BytesIO(bbuff))
|
|
|
|
@staticmethod
|
|
def from_buffer(buff: io.BytesIO):
|
|
msg = CLIPRDR_MFPICT()
|
|
msg.mappingMode = MAPPING_MODE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
|
|
msg.xExt = int.from_bytes(buff.read(4), byteorder='little', signed=False)
|
|
msg.yExt = int.from_bytes(buff.read(4), byteorder='little', signed=False)
|
|
msg.metaFileData = buff.read()
|
|
return msg
|
|
|
|
def __repr__(self):
|
|
t = '==== CLIPRDR_MFPICT ====\r\n'
|
|
for k in self.__dict__:
|
|
if isinstance(self.__dict__[k], enum.IntFlag):
|
|
value = self.__dict__[k]
|
|
elif isinstance(self.__dict__[k], enum.Enum):
|
|
value = self.__dict__[k].name
|
|
else:
|
|
value = self.__dict__[k]
|
|
t += '%s: %s\r\n' % (k, value)
|
|
return t
|
|
|
|
class PALETTEENTRY:
|
|
def __init__(self):
|
|
self.red:int = None
|
|
self.green:int = None
|
|
self.blue:int = None
|
|
self.extra:bytes = b'\x00'
|
|
|
|
def to_bytes(self):
|
|
t = self.red.to_bytes(1, byteorder='little', signed=False)
|
|
t += self.green.to_bytes(1, byteorder='little', signed=False)
|
|
t += self.blue.to_bytes(1, byteorder='little', signed=False)
|
|
t += self.extra
|
|
return t
|
|
|
|
@staticmethod
|
|
def from_bytes(bbuff: bytes):
|
|
return PALETTEENTRY.from_buffer(io.BytesIO(bbuff))
|
|
|
|
@staticmethod
|
|
def from_buffer(buff: io.BytesIO):
|
|
msg = PALETTEENTRY()
|
|
msg.red = buff.read(1)[0]
|
|
msg.green = buff.read(1)[0]
|
|
msg.blue = buff.read(1)[0]
|
|
msg.extra = buff.read(1)
|
|
return msg
|
|
|
|
def __repr__(self):
|
|
t = '==== PALETTEENTRY ====\r\n'
|
|
for k in self.__dict__:
|
|
if isinstance(self.__dict__[k], enum.IntFlag):
|
|
value = self.__dict__[k]
|
|
elif isinstance(self.__dict__[k], enum.Enum):
|
|
value = self.__dict__[k].name
|
|
else:
|
|
value = self.__dict__[k]
|
|
t += '%s: %s\r\n' % (k, value)
|
|
return t
|
|
|
|
|
|
class CLIPRDR_PALETTE:
|
|
def __init__(self):
|
|
self.paletteEntriesData:List[PALETTEENTRY] = []
|
|
|
|
def to_bytes(self):
|
|
t = b''
|
|
for pe in self.paletteEntriesData:
|
|
t += pe.to_bytes()
|
|
return t
|
|
|
|
@staticmethod
|
|
def from_bytes(bbuff: bytes):
|
|
return CLIPRDR_PALETTE.from_buffer(io.BytesIO(bbuff))
|
|
|
|
@staticmethod
|
|
def from_buffer(buff: io.BytesIO):
|
|
msg = CLIPRDR_PALETTE()
|
|
while buff.read(1) != b'':
|
|
buff.seek(-1,1)
|
|
PALETTEENTRY.from_buffer(buff)
|
|
return msg
|
|
|
|
def __repr__(self):
|
|
t = '==== CLIPRDR_PALETTE ====\r\n'
|
|
for k in self.__dict__:
|
|
if isinstance(self.__dict__[k], enum.IntFlag):
|
|
value = self.__dict__[k]
|
|
elif isinstance(self.__dict__[k], enum.Enum):
|
|
value = self.__dict__[k].name
|
|
else:
|
|
value = self.__dict__[k]
|
|
t += '%s: %s\r\n' % (k, value)
|
|
return t
|
|
|
|
class FD_FLAGS(enum.IntFlag):
|
|
ATTRIBUTES = 0x00000004 #The fileAttributes field contains valid data.
|
|
FILESIZE = 0x00000040 #The fileSizeHigh and fileSizeLow fields contain valid data.
|
|
WRITESTIME = 0x00000020 #The lastWriteTime field contains valid data.
|
|
SHOWPROGRESSUI = 0x00004000 #A progress indicator SHOULD be shown when copying the file.
|
|
|
|
class FILE_ATTRIBUTE(enum.IntFlag):
|
|
READONLY = 0x00000001 #A file that is read-only. Applications can read the file, but cannot write to it or delete it.
|
|
HIDDEN = 0x00000002 #The file or directory is hidden. It is not included in an ordinary directory listing.
|
|
SYSTEM = 0x00000004 #A file or directory that the operating system uses a part of, or uses exclusively.
|
|
DIRECTORY = 0x00000010 #Identifies a directory.
|
|
ARCHIVE = 0x00000020 #A file or directory that is an archive file or directory. Applications typically use this attribute to mark files for backup or removal.
|
|
NORMAL = 0x00000080 #A file that does not have other attributes set. This attribute is valid only when used alone.
|
|
|
|
class CLIPRDR_FILEDESCRIPTOR:
|
|
def __init__(self):
|
|
self.flags:FD_FLAGS = None
|
|
self.reserved1:bytes = b'\x00'*32
|
|
self.fileAttributes:FILE_ATTRIBUTE = None
|
|
self.reserved2:bytes = None
|
|
self.lastWriteTime:int = None
|
|
self.fileSizeHigh:int = None
|
|
self.fileSizeLow:int = None
|
|
self.fileName:str = None #520 bytes, 260 chars null term
|
|
|
|
self.fileSize:int =None
|
|
|
|
def to_bytes(self):
|
|
if self.fileSize is not None:
|
|
self.fileSizeHigh = self.fileSize >> 32
|
|
self.fileSizeLow = self.fileSize & 0xFFFFFFFF
|
|
|
|
t = self.flags.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.reserved1
|
|
t += self.fileAttributes.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.reserved2
|
|
t += self.lastWriteTime.to_bytes(8, byteorder='little', signed=False)
|
|
t += self.fileSizeHigh.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.fileSizeLow.to_bytes(4, byteorder='little', signed=False)
|
|
t += self.fileName.encode('utf-16-le').ljust(b'\x00',520)
|
|
return t
|
|
|
|
@staticmethod
|
|
def from_bytes(bbuff: bytes):
|
|
return CLIPRDR_FILEDESCRIPTOR.from_buffer(io.BytesIO(bbuff))
|
|
|
|
@staticmethod
|
|
def from_buffer(buff: io.BytesIO):
|
|
msg = CLIPRDR_FILEDESCRIPTOR()
|
|
msg.flags = FD_FLAGS(int.from_bytes(buff.read(4), byteorder='little', signed=False))
|
|
msg.reserved1 = buff.read(32)
|
|
msg.fileAttributes = FILE_ATTRIBUTE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
|
|
msg.reserved2 = buff.read(16)
|
|
msg.lastWriteTime = FILE_ATTRIBUTE(int.from_bytes(buff.read(8), byteorder='little', signed=False))
|
|
msg.fileSizeHigh = FILE_ATTRIBUTE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
|
|
msg.fileSizeLow = FILE_ATTRIBUTE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
|
|
msg.fileName = buff.read(520).decode('utf-16-le').replace('\x00','')
|
|
msg.fileSize = msg.fileSizeHigh << 32 | msg.fileSizeLow
|
|
return msg
|
|
|
|
def __repr__(self):
|
|
t = '==== CLIPRDR_FILEDESCRIPTOR ====\r\n'
|
|
for k in self.__dict__:
|
|
if isinstance(self.__dict__[k], enum.IntFlag):
|
|
value = self.__dict__[k]
|
|
elif isinstance(self.__dict__[k], enum.Enum):
|
|
value = self.__dict__[k].name
|
|
else:
|
|
value = self.__dict__[k]
|
|
t += '%s: %s\r\n' % (k, value)
|
|
return t
|
|
|
|
|
|
class CLIPRDR_FILELIST:
|
|
def __init__(self):
|
|
self.cItems:MAPPING_MODE = None
|
|
self.fileDescriptorArray:List[CLIPRDR_FILEDESCRIPTOR] = []
|
|
|
|
def to_bytes(self):
|
|
t = len(self.fileDescriptorArray).to_bytes(4, byteorder='little', signed=False)
|
|
for fd in self.fileDescriptorArray:
|
|
t += fd.to_bytes()
|
|
return t
|
|
|
|
@staticmethod
|
|
def from_bytes(bbuff: bytes):
|
|
return CLIPRDR_FILELIST.from_buffer(io.BytesIO(bbuff))
|
|
|
|
@staticmethod
|
|
def from_buffer(buff: io.BytesIO):
|
|
msg = CLIPRDR_FILELIST()
|
|
msg.cItems = int.from_bytes(buff.read(4), byteorder='little', signed=False)
|
|
for _ in range(msg.cItems):
|
|
msg.fileDescriptorArray.append(CLIPRDR_FILEDESCRIPTOR.from_buffer(buff))
|
|
return msg
|
|
|
|
def __repr__(self):
|
|
t = '==== CLIPRDR_FILELIST ====\r\n'
|
|
for k in self.__dict__:
|
|
if isinstance(self.__dict__[k], enum.IntFlag):
|
|
value = self.__dict__[k]
|
|
elif isinstance(self.__dict__[k], enum.Enum):
|
|
value = self.__dict__[k].name
|
|
else:
|
|
value = self.__dict__[k]
|
|
t += '%s: %s\r\n' % (k, value)
|
|
return t
|
|
|
|
class CLIPRDR_FORMAT_DATA_RESPONSE:
|
|
def __init__(self):
|
|
self.dataobj = None
|
|
|
|
def to_bytes(self, otype:CLIPBRD_FORMAT):
|
|
if otype == CLIPBRD_FORMAT.CF_UNICODETEXT:
|
|
t = self.dataobj.encode('utf-16-le') + b'\x00'*3
|
|
elif otype == CLIPBRD_FORMAT.CF_TEXT:
|
|
t = self.dataobj.encode('ascii') + b'\x00'
|
|
else:
|
|
t = self.dataobj.to_bytes()
|
|
return t
|
|
|
|
@staticmethod
|
|
def from_bytes(bbuff: bytes, otype:CLIPBRD_FORMAT):
|
|
return CLIPRDR_FORMAT_DATA_RESPONSE.from_buffer(io.BytesIO(bbuff), otype = otype)
|
|
|
|
@staticmethod
|
|
def from_buffer(buff: io.BytesIO, otype:CLIPBRD_FORMAT):
|
|
msg = CLIPRDR_FORMAT_DATA_RESPONSE()
|
|
if otype == CLIPBRD_FORMAT.CF_HDROP: #TODO: not sure
|
|
msg.dataobj = CLIPRDR_FILELIST.from_buffer(buff)
|
|
elif otype == CLIPBRD_FORMAT.CF_PALETTE:
|
|
msg.dataobj = CLIPRDR_PALETTE.from_buffer(buff)
|
|
elif otype == CLIPBRD_FORMAT.CF_METAFILEPICT:
|
|
msg.dataobj = CLIPRDR_MFPICT.from_buffer(buff)
|
|
elif otype == CLIPBRD_FORMAT.CF_UNICODETEXT:
|
|
msg.dataobj = buff.read().decode('utf-16-le').replace('\x00','')
|
|
elif otype == CLIPBRD_FORMAT.CF_TEXT:
|
|
msg.dataobj = buff.read().decode().replace('\x00','')
|
|
return msg
|
|
|
|
def __repr__(self):
|
|
t = '==== CLIPRDR_FORMAT_DATA_RESPONSE ====\r\n'
|
|
for k in self.__dict__:
|
|
if isinstance(self.__dict__[k], enum.IntFlag):
|
|
value = self.__dict__[k]
|
|
elif isinstance(self.__dict__[k], enum.Enum):
|
|
value = self.__dict__[k].name
|
|
else:
|
|
value = self.__dict__[k]
|
|
t += '%s: %s\r\n' % (k, value)
|
|
return t |