mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
rewrite of alpc.py + adapt rpc/client.py
This commit is contained in:
+246
-317
@@ -1,66 +1,121 @@
|
||||
import ctypes
|
||||
from collections import namedtuple
|
||||
|
||||
import windows
|
||||
from windows import winproxy
|
||||
from windows import generated_def as gn
|
||||
from windows import generated_def as gdef
|
||||
|
||||
ALPC_MSGFLG_REPLY_MESSAGE = 0x1
|
||||
ALPC_MSGFLG_LPC_MODE = 0x2
|
||||
ALPC_MSGFLG_RELEASE_MESSAGE = 0x10000
|
||||
ALPC_MSGFLG_SYNC_REQUEST = 0x20000
|
||||
ALPC_MSGFLG_WAIT_USER_MODE = 0x100000
|
||||
ALPC_MSGFLG_WAIT_ALERTABLE = 0x200000
|
||||
ALPC_MSGFLG_WOW64_CALL = 0x80000000
|
||||
|
||||
ALPC_MESSAGE_SECURITY_ATTRIBUTE = 0x80000000
|
||||
ALPC_MESSAGE_VIEW_ATTRIBUTE = 0x40000000
|
||||
ALPC_MESSAGE_CONTEXT_ATTRIBUTE = 0x20000000
|
||||
ALPC_MESSAGE_HANDLE_ATTRIBUTE = 0x10000000
|
||||
class AlpcMessage(object):
|
||||
# PORT_MESSAGE + MessageAttribute
|
||||
def __init__(self, msg_or_size=None, attributes=None):
|
||||
# Init the PORT_MESSAGE
|
||||
if isinstance(msg_or_size, (long, int)):
|
||||
self.port_message_buffer_size = msg_or_size
|
||||
self.port_message_raw_buffer = ctypes.c_buffer(msg_or_size)
|
||||
self.port_message = AlpcMessagePort.from_buffer(self.port_message_raw_buffer)
|
||||
self.port_message.set_datalen(0)
|
||||
elif isinstance(msg_or_size, AlpcMessagePort):
|
||||
self.port_message = msg_or_size
|
||||
self.port_message_raw_buffer = self.port_message.raw_buffer
|
||||
self.port_message_buffer_size = len(self.port_message_raw_buffer)
|
||||
|
||||
# Init the MessageAttributes
|
||||
if attributes is None:
|
||||
self.attributes = MessageAttribute.with_all_attributes()
|
||||
else:
|
||||
self.attributes = attributes
|
||||
|
||||
# PORT_MESSAGE wrappers
|
||||
@property
|
||||
def type(self):
|
||||
return self.port_message.u2.s2.Type
|
||||
|
||||
def get_port_message_data(self):
|
||||
return self.port_message.data
|
||||
|
||||
def set_port_message_data(self, data):
|
||||
self.port_message.data = data
|
||||
|
||||
data = property(get_port_message_data, set_port_message_data)
|
||||
|
||||
# MessageAttributes wrappers
|
||||
|
||||
## Low level attributes access
|
||||
@property
|
||||
def security_attribute(self):
|
||||
return self.attributes.get_attribute(gdef.ALPC_MESSAGE_SECURITY_ATTRIBUTE)
|
||||
|
||||
@property
|
||||
def view_attribute(self):
|
||||
return self.attributes.get_attribute(gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
|
||||
@property
|
||||
def context_attribute(self):
|
||||
return self.attributes.get_attribute(gdef.ALPC_MESSAGE_CONTEXT_ATTRIBUTE)
|
||||
|
||||
@property
|
||||
def handle_attribute(self):
|
||||
return self.attributes.get_attribute(gdef.ALPC_MESSAGE_HANDLE_ATTRIBUTE)
|
||||
|
||||
## Low level validity check (Test)
|
||||
@property
|
||||
def view_is_valid(self): # Change the name ?
|
||||
return self.attributes.is_valid(gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
|
||||
|
||||
## High level setup (Test)
|
||||
def setup_view(self, size, section_handle=0, flags=None):
|
||||
raise NotImplementedError(self.setup_view)
|
||||
|
||||
|
||||
|
||||
class AlpcMessage(gn.PORT_MESSAGE):
|
||||
def __new__(cls, buffersize):
|
||||
size = ctypes.sizeof(cls) + buffersize
|
||||
buffer = ctypes.c_buffer(size)
|
||||
self = cls.from_buffer(buffer)
|
||||
class AlpcMessagePort(gdef.PORT_MESSAGE):
|
||||
# Constructeur
|
||||
@classmethod
|
||||
def from_buffer(self, buffer):
|
||||
# A sort of super(AlpcMessagePort).from_buffer
|
||||
# But from_buffer is from the Metaclass of AlpcMessagePort so we use 'type(AlpcMessagePort)'
|
||||
# To access the standard version of from_buffer.
|
||||
self = type(AlpcMessagePort).from_buffer(AlpcMessagePort, buffer)
|
||||
self.buffer_size = len(buffer)
|
||||
self.raw_buffer = buffer
|
||||
self.header_size = ctypes.sizeof(self)
|
||||
self.max_datasize = self.buffer_size - self.header_size
|
||||
return self
|
||||
|
||||
def __init__(self, buffersize):
|
||||
self.u1.s1.TotalLength = buffersize + ctypes.sizeof(self)
|
||||
self.u1.s1.DataLength = buffersize
|
||||
return super(AlpcMessage, self).__init__()
|
||||
@classmethod
|
||||
def from_buffer_size(cls, buffer_size):
|
||||
buffer = ctypes.c_buffer(buffer_size)
|
||||
return cls.from_buffer(buffer)
|
||||
|
||||
def read_data(self):
|
||||
return self.raw_buffer[ctypes.sizeof(self):ctypes.sizeof(self) + self.u1.s1.DataLength]
|
||||
|
||||
def write_data(self, data):
|
||||
self.raw_buffer[ctypes.sizeof(self): ctypes.sizeof(self) + len(data)] = data
|
||||
if len(data) > self.max_datasize:
|
||||
raise ValueError("Cannot write data of len <{0}> (raw_buffer size == <{1}>)".format(len(data), self.buffer_size))
|
||||
self.raw_buffer[self.header_size: self.header_size + len(data)] = data
|
||||
self.set_datalen(len(data))
|
||||
|
||||
data = property(read_data, write_data)
|
||||
|
||||
class MessageAttribute(gn.ALPC_MESSAGE_ATTRIBUTES):
|
||||
# def __new__(cls, flags):
|
||||
# size = cls._get_required_buffer_size(flags)
|
||||
# buffer = ctypes.c_buffer(size)
|
||||
# self = cls.from_buffer(buffer)
|
||||
# self.raw_buffer = buffer
|
||||
# return self
|
||||
ATTRIBUTE_BY_FLAG = [(gn.ALPC_MESSAGE_SECURITY_ATTRIBUTE, gn.ALPC_SECURITY_ATTR),
|
||||
(gn.ALPC_MESSAGE_VIEW_ATTRIBUTE, gn.ALPC_DATA_VIEW_ATTR),
|
||||
(gn.ALPC_MESSAGE_CONTEXT_ATTRIBUTE, gn.ALPC_CONTEXT_ATTR),
|
||||
(gn.ALPC_MESSAGE_HANDLE_ATTRIBUTE, gn.ALPC_HANDLE_ATTR)]
|
||||
def set_datalen(self, datalen):
|
||||
self.u1.s1.TotalLength = self.header_size + datalen
|
||||
self.u1.s1.DataLength = datalen
|
||||
|
||||
def get_datalen(self):
|
||||
return self.u1.s1.DataLength
|
||||
|
||||
datalen = property(get_datalen, set_datalen)
|
||||
|
||||
|
||||
#define ALPC_MESSAGE_SECURITY_ATTRIBUTE 0x80000000
|
||||
#define ALPC_MESSAGE_VIEW_ATTRIBUTE 0x40000000
|
||||
#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE 0x20000000
|
||||
#define ALPC_MESSAGE_HANDLE_ATTRIBUTE 0x10000000
|
||||
|
||||
def __init__(self, flags):
|
||||
res = gn.DWORD()
|
||||
winproxy.AlpcInitializeMessageAttribute(flags, self, len(self.raw_buffer), res)
|
||||
class MessageAttribute(gdef.ALPC_MESSAGE_ATTRIBUTES):
|
||||
ATTRIBUTE_BY_FLAG = [(gdef.ALPC_MESSAGE_SECURITY_ATTRIBUTE, gdef.ALPC_SECURITY_ATTR),
|
||||
(gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE, gdef.ALPC_DATA_VIEW_ATTR),
|
||||
(gdef.ALPC_MESSAGE_CONTEXT_ATTRIBUTE, gdef.ALPC_CONTEXT_ATTR),
|
||||
(gdef.ALPC_MESSAGE_HANDLE_ATTRIBUTE, gdef.ALPC_HANDLE_ATTR)]
|
||||
|
||||
@classmethod
|
||||
def with_attributes(cls, flags):
|
||||
@@ -68,13 +123,20 @@ class MessageAttribute(gn.ALPC_MESSAGE_ATTRIBUTES):
|
||||
buffer = ctypes.c_buffer(size)
|
||||
self = cls.from_buffer(buffer)
|
||||
self.raw_buffer = buffer
|
||||
res = gn.DWORD()
|
||||
res = gdef.DWORD()
|
||||
winproxy.AlpcInitializeMessageAttribute(flags, self, len(self.raw_buffer), res)
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def with_all_attributes(cls):
|
||||
return cls.with_attributes(gdef.ALPC_MESSAGE_SECURITY_ATTRIBUTE |
|
||||
gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE |
|
||||
gdef.ALPC_MESSAGE_CONTEXT_ATTRIBUTE |
|
||||
gdef.ALPC_MESSAGE_HANDLE_ATTRIBUTE)
|
||||
|
||||
@staticmethod
|
||||
def _get_required_buffer_size(flags):
|
||||
res = gn.DWORD()
|
||||
res = gdef.DWORD()
|
||||
try:
|
||||
windows.winproxy.AlpcInitializeMessageAttribute(flags, None, 0, res)
|
||||
except windows.generated_def.ntstatus.NtStatusException as e:
|
||||
@@ -83,314 +145,181 @@ class MessageAttribute(gn.ALPC_MESSAGE_ATTRIBUTES):
|
||||
return res.value
|
||||
|
||||
def is_allocated(self, value):
|
||||
return self.AllocatedAttributes & value
|
||||
return bool(self.AllocatedAttributes & value)
|
||||
|
||||
def is_valid(self, value):
|
||||
return self.ValidAttributes & value
|
||||
return bool(self.ValidAttributes & value)
|
||||
|
||||
def get_attribute(self, flag):
|
||||
def get_attribute(self, attribute):
|
||||
if not self.is_allocated(attribute):
|
||||
raise ValueError("Cannot get non-allocated attribute <{0}>".format(attribute))
|
||||
offset = ctypes.sizeof(self)
|
||||
for sflag, struct in self.ATTRIBUTE_BY_FLAG:
|
||||
if sflag == flag:
|
||||
if sflag == attribute:
|
||||
return struct.from_address(ctypes.addressof(self) + offset)
|
||||
elif self.is_allocated(sflag):
|
||||
offset += ctypes.sizeof(struct)
|
||||
raise ValueError("ALPC Attribute Flag not found :(")
|
||||
raise ValueError("ALPC Attribute <{0}> not found :(".format(attribute))
|
||||
|
||||
AlpcSection = namedtuple("AlpcSection", ["handle", "size"])
|
||||
|
||||
class AlpcTransportBase(object):
|
||||
def send_receive(self, alpc_message, receive_msg=None, flags=gdef.ALPC_MSGFLG_SYNC_REQUEST):
|
||||
if isinstance(alpc_message, basestring):
|
||||
raw_alpc_message = alpc_message
|
||||
alpc_message = AlpcMessage(max(0x1000, len(alpc_message)))
|
||||
alpc_message.port_message.data = raw_alpc_message
|
||||
|
||||
if receive_msg is None:
|
||||
receive_msg = AlpcMessage(0x1000)
|
||||
receive_size = gdef.SIZE_T(receive_msg.port_message_buffer_size)
|
||||
winproxy.NtAlpcSendWaitReceivePort(self.handle, flags, alpc_message.port_message, alpc_message.attributes, receive_msg.port_message, receive_size, receive_msg.attributes, None)
|
||||
return receive_msg
|
||||
|
||||
def send(self, alpc_message, flags=0):
|
||||
if isinstance(alpc_message, basestring):
|
||||
raw_alpc_message = alpc_message
|
||||
alpc_message = AlpcMessage(max(0x1000, len(alpc_message)))
|
||||
alpc_message.port_message.data = raw_alpc_message
|
||||
winproxy.NtAlpcSendWaitReceivePort(self.handle, flags, alpc_message.port_message, alpc_message.attributes, None, None, None, None)
|
||||
|
||||
def recv(self, receive_msg=None, flags=0):
|
||||
if receive_msg is None:
|
||||
receive_msg = AlpcMessage(0x1000)
|
||||
receive_size = gdef.SIZE_T(receive_msg.port_message_buffer_size)
|
||||
winproxy.NtAlpcSendWaitReceivePort(self.handle, flags, None, None, receive_msg.port_message, receive_size, receive_msg.attributes, None)
|
||||
return receive_msg
|
||||
|
||||
|
||||
|
||||
class AlpcClient(AlpcTransportBase):
|
||||
DEFAULT_MAX_MESSAGE_LENGTH = 0x1000
|
||||
|
||||
|
||||
class AlpcPORT(object):
|
||||
def __init__(self, port_name, msglen=0x1000):
|
||||
self.port_name = port_name
|
||||
self.handle = self._create_port(port_name, msglen)
|
||||
|
||||
def _create_port(self, port_name, msglen=0x1000):
|
||||
handle = gn.HANDLE()
|
||||
raw_name = port_name
|
||||
if not raw_name.startswith("\\"):
|
||||
raw_name = "\\" + port_name
|
||||
utf16_len = len(raw_name) * 2
|
||||
port_name = gn.UNICODE_STRING(utf16_len, utf16_len, raw_name)
|
||||
|
||||
obj_attr = gn.OBJECT_ATTRIBUTES()
|
||||
obj_attr.Length = ctypes.sizeof(obj_attr)
|
||||
obj_attr.RootDirectory = None
|
||||
obj_attr.ObjectName = ctypes.pointer(port_name)
|
||||
obj_attr.Attributes = 0
|
||||
obj_attr.SecurityDescriptor = None
|
||||
obj_attr.SecurityQualityOfService = None
|
||||
|
||||
port_attr = gn.ALPC_PORT_ATTRIBUTES()
|
||||
port_attr.Flags = 0
|
||||
# port_attr.Flags = 0x2080000 # Test
|
||||
port_attr.MaxMessageLength = msglen
|
||||
port_attr.MemoryBandwidth = 0
|
||||
port_attr.MaxPoolUsage = 0
|
||||
|
||||
winproxy.NtAlpcCreatePort(handle, obj_attr, port_attr)
|
||||
return handle.value
|
||||
|
||||
#class AlpcExchange(object):
|
||||
# def send_receive_data(port_handle, data):
|
||||
# raw_sendmsg = ctypes.c_buffer(0x1000)
|
||||
# size = gn.SIZE_T(0x1000)
|
||||
# sendmsg = ctypes.cast(raw_sendmsg, gn.PPORT_MESSAGE)
|
||||
# buffer = ctypes.c_buffer(0x200)
|
||||
# sendmsg_attr = ctypes.cast(buffer, gn.PALPC_MESSAGE_ATTRIBUTES)
|
||||
# res = gn.DWORD()
|
||||
# winproxy.AlpcInitializeMessageAttribute(ALPC_MESSAGE_CONTEXT_ATTRIBUTE + ALPC_MESSAGE_HANDLE_ATTRIBUTE + 1, sendmsg_attr , 0x200, res)
|
||||
#
|
||||
# sendmsg = AlpcMessage(len(data))
|
||||
# sendmsg.data = data
|
||||
#
|
||||
# size = gn.SIZE_T(0x1000)
|
||||
# receive = AlpcMessage(size.value)
|
||||
# buffer = ctypes.c_buffer(0x200)
|
||||
# receive_attr = ctypes.cast(buffer, gn.PALPC_MESSAGE_ATTRIBUTES)
|
||||
# res = gn.DWORD()
|
||||
#
|
||||
# winproxy.NtAlpcSendWaitReceivePort(port_handle, ALPC_MSGFLG_SYNC_REQUEST, sendmsg, sendmsg_attr, receive, size, receive_attr, None)
|
||||
# return receive, receive_attr
|
||||
|
||||
|
||||
def send_receive_data(port_handle, data):
|
||||
# sendmsg_attr = MessageAttribute.with_attributes(ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
# sendmsg_attr.ValidAttributes = ALPC_MESSAGE_VIEW_ATTRIBUTE
|
||||
sendmsg_attr = MessageAttribute.with_attributes(0)
|
||||
sendmsg = AlpcMessage(len(data))
|
||||
sendmsg.data = data
|
||||
|
||||
# import pdb;pdb.set_trace()
|
||||
|
||||
size = gn.SIZE_T(0x1000)
|
||||
receive = AlpcMessage(size.value)
|
||||
receive_attr = MessageAttribute.with_attributes(ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
# Its strange that this line does not always have the same effect has the one bellow
|
||||
# winproxy.NtAlpcSendWaitReceivePort(port_handle, ALPC_MSGFLG_SYNC_REQUEST, sendmsg, sendmsg_attr, receive, ctypes.byref(size), receive_attr, None)
|
||||
winproxy.NtAlpcSendWaitReceivePort(port_handle, ALPC_MSGFLG_SYNC_REQUEST, sendmsg, sendmsg_attr, receive, size, receive_attr, None)
|
||||
# winproxy.NtAlpcSendWaitReceivePort(port_handle, 0x40020000, sendmsg, sendmsg_attr, receive, size, receive_attr, None)
|
||||
return receive_attr, receive
|
||||
|
||||
|
||||
class ALPC_DATA_VIEW_ATTR(ctypes.Structure): # _ALPC_DATA_VIEW_ATTR
|
||||
_fields_ = [
|
||||
("Flags", gn.ULONG),
|
||||
("SectionHandle", gn.HANDLE),
|
||||
("ViewBase", gn.ULONG), # must be zero on input
|
||||
("ViewSize", gn.ULONG)
|
||||
]
|
||||
|
||||
class ALPC_DATA_VIEW_ATTR64(ctypes.Structure): # _ALPC_DATA_VIEW_ATTR
|
||||
_fields_ = [
|
||||
("Flags", gn.ULONG),
|
||||
("SectionHandle", gn.HANDLE),
|
||||
("ViewBase", gn.ULONGLONG), # must be zero on input
|
||||
("ViewSize", gn.ULONGLONG)
|
||||
]
|
||||
|
||||
def send_receive_data_view(port_handle, data, view):
|
||||
sendmsg_attr = MessageAttribute.with_attributes(ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
sendmsg_attr.ValidAttributes = ALPC_MESSAGE_VIEW_ATTRIBUTE
|
||||
|
||||
view_attr = ALPC_DATA_VIEW_ATTR64.from_address(ctypes.addressof(sendmsg_attr) + 8)
|
||||
# view_attr.Flags = 0x60000 # 0x20000 -> Unmap la section dans le sender
|
||||
view_attr.Flags = 0x40000
|
||||
# view_attr.Flags = 0x10000
|
||||
view_attr.SectionHandle = view.SectionHandle
|
||||
view_attr.ViewBase = view.ViewBase
|
||||
view_attr.ViewSize = view.ViewSize
|
||||
|
||||
xx = windows.winproxy.AlpcGetMessageAttribute(sendmsg_attr, ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
|
||||
|
||||
sendmsg = AlpcMessage(len(data))
|
||||
sendmsg.data = data
|
||||
|
||||
|
||||
print(sendmsg_attr.ValidAttributes)
|
||||
|
||||
size = gn.SIZE_T(0x1000)
|
||||
receive = AlpcMessage(size.value)
|
||||
receive_attr = MessageAttribute.with_attributes(ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
receive_attr.ValidAttributes = ALPC_MESSAGE_VIEW_ATTRIBUTE
|
||||
# Its strange that this line does not always have the same effect has the one bellow
|
||||
# winproxy.NtAlpcSendWaitReceivePort(port_handle, ALPC_MSGFLG_SYNC_REQUEST, sendmsg, sendmsg_attr, receive, ctypes.byref(size), receive_attr, None)
|
||||
# winproxy.NtAlpcSendWaitReceivePort(port_handle, 0, sendmsg, sendmsg_attr, None, size, None, None)
|
||||
winproxy.NtAlpcSendWaitReceivePort(port_handle, ALPC_MSGFLG_SYNC_REQUEST , sendmsg, sendmsg_attr, receive, size, receive_attr, None)
|
||||
# winproxy.NtAlpcSendWaitReceivePort(port_handle, 0x000000000410000, sendmsg, sendmsg_attr, None, None, None, None)
|
||||
# 0000000000410000 # Flags ?
|
||||
print(hex(windows.current_process.query_memory(view.ViewBase).State))
|
||||
print(hex(windows.current_process.query_memory(view.ViewBase).Protect))
|
||||
return receive_attr, receive
|
||||
|
||||
|
||||
|
||||
class AlpcClient(object):
|
||||
def __init__(self):
|
||||
self.portname = None
|
||||
def __init__(self, port_name=None):
|
||||
self.handle = None
|
||||
self.portname = None
|
||||
if port_name is not None:
|
||||
x = self.connect_to_port(port_name, "")
|
||||
|
||||
def connect_to_port(self, port_name, connect_msg=None, maxmsglen=0x1000):
|
||||
def _alpc_port_to_unicode_string(self, name):
|
||||
utf16_len = len(name) * 2
|
||||
return gdef.UNICODE_STRING(utf16_len, utf16_len, name)
|
||||
|
||||
def connect_to_port(self, port_name, connect_message=None, receive_message=None, port_attr=None, port_attr_flags=0x10000, obj_attr=None, flags=gdef.ALPC_MSGFLG_SYNC_REQUEST, timeout=None):
|
||||
# TODO raise on mutual exclusive parameter
|
||||
if self.handle is not None:
|
||||
raise ValueError("Client already connected")
|
||||
handle = gn.HANDLE()
|
||||
handle = gdef.HANDLE()
|
||||
port_name_unicode = self._alpc_port_to_unicode_string(port_name)
|
||||
|
||||
#raw_name = "\\" + port_name
|
||||
raw_name = port_name
|
||||
utf16_len = len(raw_name) * 2
|
||||
if port_attr is None:
|
||||
port_attr = gdef.ALPC_PORT_ATTRIBUTES()
|
||||
port_attr.Flags = port_attr_flags # Flag qui fonctionne pour l'UAC
|
||||
port_attr.MaxMessageLength = self.DEFAULT_MAX_MESSAGE_LENGTH
|
||||
port_attr.MemoryBandwidth = 0
|
||||
port_attr.MaxPoolUsage = 0xffffffff
|
||||
port_attr.MaxSectionSize = 0xffffffff
|
||||
port_attr.MaxViewSize = 0xffffffff
|
||||
port_attr.MaxTotalSectionSize = 0xffffffff
|
||||
port_attr.DupObjectTypes = 0
|
||||
|
||||
port_name = gn.UNICODE_STRING(utf16_len, utf16_len, raw_name)
|
||||
|
||||
# obj_attr = gn.OBJECT_ATTRIBUTES()
|
||||
# obj_attr.Length = ctypes.sizeof(obj_attr)
|
||||
# obj_attr.RootDirectory = None
|
||||
# obj_attr.ObjectName = None
|
||||
# obj_attr.Attributes = 0
|
||||
# obj_attr.SecurityDescriptor = None
|
||||
# obj_attr.SecurityQualityOfService = None
|
||||
|
||||
obj_attr = None
|
||||
|
||||
|
||||
port_attr = gn.ALPC_PORT_ATTRIBUTES()
|
||||
port_attr.Flags = 0
|
||||
port_attr.MaxMessageLength = maxmsglen
|
||||
port_attr.MemoryBandwidth = 0
|
||||
port_attr.MaxPoolUsage = 0
|
||||
|
||||
if True:
|
||||
port_attr.SecurityQos.Length = 12
|
||||
port_attr.SecurityQos.ImpersonationLevel = 2
|
||||
port_attr.SecurityQos.Length = ctypes.sizeof(port_attr.SecurityQos)
|
||||
port_attr.SecurityQos.ImpersonationLevel = gdef.SecurityImpersonation
|
||||
port_attr.SecurityQos.ContextTrackingMode = 0
|
||||
port_attr.SecurityQos.EffectiveOnly = 0
|
||||
|
||||
|
||||
#define ALPC_PORFLG_ALLOW_LPC_REQUESTS 0x20000 // rev
|
||||
#define ALPC_PORFLG_WAITABLE_PORT 0x40000 // dbg
|
||||
#define ALPC_PORFLG_SYSTEM_PROCESS 0x100000 // dbg
|
||||
|
||||
#port_attr.MaxPoolUsage = 0
|
||||
port_attr.Flags = 0x10000 # Flag qui fonctionne pour l'UAC
|
||||
port_attr.Flags = 0x2090000 # Test
|
||||
port_attr.Flags = 0x2080000 # Test # Tes2
|
||||
# 0x0010000 est le flag qui permet l'impersonation (en tout cas le pop UAC)
|
||||
#port_attr.MaxPoolUsage = 4294967295
|
||||
#port_attr.MaxSectionSize = 4294967295
|
||||
port_attr.MaxViewSize = 4294967295
|
||||
#port_attr.MaxTotalSectionSize = 4294967295
|
||||
#port_attr.DupObjectTypes = 4093
|
||||
|
||||
# tst.Flags -> 34144256
|
||||
# tst.SecurityQos.Length -> 12
|
||||
# tst.SecurityQos.ImpersonationLevel -> SecurityImpersonation(0x2L)
|
||||
# tst.SecurityQos.ContextTrackingMode -> 0
|
||||
# tst.SecurityQos.EffectiveOnly -> 0
|
||||
# tst.MaxMessageLength -> 4096
|
||||
# tst.MemoryBandwidth -> 0
|
||||
# tst.MaxPoolUsage -> 4294967295
|
||||
# tst.MaxSectionSize -> 4294967295
|
||||
# tst.MaxViewSize -> 4294967295
|
||||
# tst.MaxTotalSectionSize -> 4294967295
|
||||
# tst.DupObjectTypes -> 4093
|
||||
|
||||
if connect_msg is not None:
|
||||
size = len(connect_msg)
|
||||
send_msg = AlpcMessage(size)
|
||||
send_msg.data = connect_msg
|
||||
sendmsg_attr = MessageAttribute.with_attributes(0)
|
||||
receive_attr = MessageAttribute.with_attributes(0)
|
||||
receive_attr = None
|
||||
sendmsg_attr = None
|
||||
buffersize = gn.DWORD(len(send_msg.raw_buffer))
|
||||
else:
|
||||
size = None
|
||||
if connect_message is None:
|
||||
send_msg = None
|
||||
sendmsg_attr = None
|
||||
receive_attr = None
|
||||
send_msg_attr = None
|
||||
buffersize = None
|
||||
elif isinstance(connect_message, basestring):
|
||||
buffersize = gdef.DWORD(len(connect_message) + 0x1000)
|
||||
send_msg = AlpcMessagePort.from_buffer_size(buffersize.value)
|
||||
send_msg.data = connect_message
|
||||
send_msg_attr = MessageAttribute.with_all_attributes()
|
||||
else:
|
||||
raise NotImplementedError("TODO: connect_to_port with type(connect_message) == AlpcMessage")
|
||||
|
||||
#print(hex([0].AllocatedAttributes))
|
||||
#import pdb;pdb.set_trace()
|
||||
x = winproxy.NtAlpcConnectPort(handle, port_name,obj_attr, port_attr, ALPC_MSGFLG_SYNC_REQUEST, None, send_msg, buffersize, sendmsg_attr, receive_attr, None)
|
||||
|
||||
receive_attr = MessageAttribute.with_all_attributes()
|
||||
winproxy.NtAlpcConnectPort(handle, port_name_unicode, obj_attr, port_attr, flags, None, send_msg, buffersize, send_msg_attr, receive_attr, timeout)
|
||||
# If send_msg is not None, it contains the ClientId.UniqueProcess : PID of the server :)
|
||||
self.handle = handle.value
|
||||
self.portname = port_name
|
||||
if connect_msg is not None:
|
||||
return send_msg
|
||||
return AlpcMessage(send_msg, receive_attr) if send_msg is not None else None
|
||||
|
||||
def send_receive(self, data):
|
||||
return send_receive_data(self.handle, data)
|
||||
def create_port_section(self, Flags, SectionHandle, SectionSize):
|
||||
AlpcSectionHandle = gdef.HANDLE()
|
||||
ActualSectionSize = gdef.SIZE_T()
|
||||
# RPCRT4 USE FLAGS 0x40000 ALPC_VIEWFLG_NOT_SECURE ?
|
||||
winproxy.NtAlpcCreatePortSection(self.handle, Flags, SectionHandle, SectionSize, AlpcSectionHandle, ActualSectionSize)
|
||||
return AlpcSection(AlpcSectionHandle.value, ActualSectionSize.value)
|
||||
|
||||
def send_receive_view(self, data, view):
|
||||
return send_receive_data_view(self.handle, data, view)
|
||||
def map_section(self, section_handle, size, flags=0):
|
||||
view_attributes = gdef.ALPC_DATA_VIEW_ATTR()
|
||||
view_attributes.Flags = 0
|
||||
view_attributes.SectionHandle = section_handle
|
||||
view_attributes.ViewBase = 0
|
||||
view_attributes.ViewSize = size
|
||||
r = winproxy.NtAlpcCreateSectionView(self.handle, flags, view_attributes)
|
||||
return view_attributes
|
||||
|
||||
|
||||
class AlpcServer(object):
|
||||
def __init__(self, port_name):
|
||||
self.port = AlpcPORT(port_name)
|
||||
class AlpcServer(AlpcTransportBase):
|
||||
DEFAULT_MAX_MESSAGE_LENGTH = 0x1000
|
||||
|
||||
def wait_data(self):
|
||||
size = gn.SIZE_T(0x1000)
|
||||
receive = AlpcMessage(size.value)
|
||||
# receive_attr = MessageAttribute(0)
|
||||
receive_attr = MessageAttribute.with_attributes(ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
winproxy.NtAlpcSendWaitReceivePort(self.port.handle, 0, None, None, receive, size, receive_attr, None)
|
||||
return receive_attr, receive
|
||||
def __init__(self, port_name=None):
|
||||
self.port_name = None
|
||||
if port_name is not None:
|
||||
self.create_port(port_name)
|
||||
|
||||
def accept_connection(self, msg):
|
||||
port_handle = self.port.handle
|
||||
rhandle = gn.HANDLE()
|
||||
def _alpc_port_to_unicode_string(self, name):
|
||||
utf16_len = len(name) * 2
|
||||
return gdef.UNICODE_STRING(utf16_len, utf16_len, name)
|
||||
|
||||
ALPC_HANDLEFLG_DUPLICATE_INHERIT = 0x80000
|
||||
port_attr = gn.ALPC_PORT_ATTRIBUTES()
|
||||
port_attr.Flags = ALPC_HANDLEFLG_DUPLICATE_INHERIT
|
||||
# port_attr.Flags = ALPC_HANDLEFLG_DUPLICATE_INHERIT + 0x30000 # Testing
|
||||
# port_attr.Flags = 0x2080000 # Testing
|
||||
port_attr.DupObjectTypes = 4
|
||||
port_attr.MaxMessageLength = 0x578
|
||||
port_attr.MemoryBandwidth = 0
|
||||
port_attr.MaxPoolUsage = 0x15E00
|
||||
def create_port(self, port_name, msglen=None, port_attr_flags=0, obj_attr=None, port_attr=None):
|
||||
# TODO raise on mutual exclusive parameter (port_attr + port_attr_flags | obj_attr + msglen)
|
||||
handle = gdef.HANDLE()
|
||||
raw_name = port_name
|
||||
if not raw_name.startswith("\\"):
|
||||
raw_name = "\\" + port_name
|
||||
port_name = self._alpc_port_to_unicode_string(raw_name)
|
||||
|
||||
winproxy.NtAlpcAcceptConnectPort(rhandle, port_handle, 0, None, port_attr, None, msg, None, 1)
|
||||
if msglen is None:
|
||||
msglen = self.DEFAULT_MAX_MESSAGE_LENGTH
|
||||
if obj_attr is None:
|
||||
obj_attr = gdef.OBJECT_ATTRIBUTES()
|
||||
obj_attr.Length = ctypes.sizeof(obj_attr)
|
||||
obj_attr.RootDirectory = None
|
||||
obj_attr.ObjectName = ctypes.pointer(port_name)
|
||||
obj_attr.Attributes = 0
|
||||
obj_attr.SecurityDescriptor = None
|
||||
obj_attr.SecurityQualityOfService = None
|
||||
if port_attr is None:
|
||||
port_attr = gdef.ALPC_PORT_ATTRIBUTES()
|
||||
port_attr.Flags = 0
|
||||
port_attr.MaxMessageLength = msglen
|
||||
port_attr.MemoryBandwidth = 0
|
||||
port_attr.MaxPoolUsage = 0xffffffff
|
||||
port_attr.MaxSectionSize = 0xffffffff
|
||||
port_attr.MaxViewSize = 0xffffffff
|
||||
port_attr.MaxTotalSectionSize = 0xffffffff
|
||||
port_attr.DupObjectTypes = 0
|
||||
|
||||
winproxy.NtAlpcCreatePort(handle, obj_attr, port_attr)
|
||||
self.port_name = raw_name
|
||||
self.handle = handle.value
|
||||
|
||||
def accept_connection(self, msg, port_attr=None):
|
||||
rhandle = gdef.HANDLE()
|
||||
|
||||
if port_attr is None:
|
||||
port_attr = gdef.ALPC_PORT_ATTRIBUTES()
|
||||
port_attr.Flags = gdef.ALPC_HANDLEFLG_DUPLICATE_INHERIT
|
||||
port_attr.Flags = 0 # Testing
|
||||
port_attr.DupObjectTypes = 4
|
||||
port_attr.MaxMessageLength = 0x1000
|
||||
port_attr.MemoryBandwidth = 0
|
||||
port_attr.MaxPoolUsage = 0xffffffff
|
||||
|
||||
winproxy.NtAlpcAcceptConnectPort(rhandle, self.handle, 0, None, port_attr, None, msg.port_message, None, True)
|
||||
return rhandle.value, msg
|
||||
|
||||
def send_receive(self, data):
|
||||
return send_receive_data(self.port.handle, data)
|
||||
|
||||
def reply(self, reply_to_msg, reply_msg):
|
||||
port_handle = self.port.handle
|
||||
sendmsg = AlpcMessage(len(reply_msg))
|
||||
sendmsg.data = reply_msg
|
||||
sendmsg_attr = MessageAttribute.with_attributes(0)
|
||||
sendmsg.MessageId = reply_to_msg.MessageId
|
||||
winproxy.NtAlpcSendWaitReceivePort(port_handle, ALPC_MSGFLG_RELEASE_MESSAGE, sendmsg, None, None, None, None, None)
|
||||
return None, None
|
||||
|
||||
|
||||
def reply_with_view(self, reply_to_msg, reply_msg, view):
|
||||
|
||||
sendmsg_attr = MessageAttribute.with_attributes(ALPC_MESSAGE_VIEW_ATTRIBUTE)
|
||||
sendmsg_attr.ValidAttributes = ALPC_MESSAGE_VIEW_ATTRIBUTE
|
||||
|
||||
view_attr = ALPC_DATA_VIEW_ATTR.from_address(ctypes.addressof(sendmsg_attr) + 8)
|
||||
view_attr.Flags = 0x60000 # 0x20000 -> Unmap la section dans le sender
|
||||
# view_attr.Flags = 0x40000
|
||||
# view_attr.Flags = 0x40000
|
||||
view_attr.SectionHandle = view.SectionHandle
|
||||
view_attr.ViewBase = view.ViewBase
|
||||
view_attr.ViewSize = view.ViewSize
|
||||
print("Section jandle = {0}".format(view.SectionHandle))
|
||||
|
||||
windows.current_process.write_memory(view.ViewBase, "SERRRRVVVVVV")
|
||||
|
||||
port_handle = self.port.handle
|
||||
sendmsg = AlpcMessage(len(reply_msg))
|
||||
sendmsg.data = reply_msg
|
||||
# sendmsg_attr = MessageAttribute.with_attributes(0)
|
||||
sendmsg.MessageId = reply_to_msg.MessageId
|
||||
winproxy.NtAlpcSendWaitReceivePort(port_handle, 0x410000, sendmsg, sendmsg_attr, None, None, None, None)
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import ndr
|
||||
from client import RPC_SYNTAX_IDENTIFIER, RPCClient
|
||||
from client import (RPC_SYNTAX_IDENTIFIER, RPCClient,
|
||||
REQUEST_TYPE_CALL, REQUEST_TYPE_BIND,
|
||||
RESPONSE_TYPE_BIND_OK, RESPONSE_TYPE_FAIL, RESPONSE_TYPE_SUCESS)
|
||||
from epmapper import find_alpc_endpoint_and_connect, endpoint_map_alpc, construct_alpc_tower
|
||||
+58
-15
@@ -1,6 +1,6 @@
|
||||
import windows.alpc as alpc
|
||||
import windows.alpc2 as alpc
|
||||
import windows.com
|
||||
from windows.generated_def import USHORT
|
||||
from windows.generated_def import USHORT, DWORD, CHAR
|
||||
import ctypes
|
||||
import struct
|
||||
|
||||
@@ -42,24 +42,49 @@ KNOW_RESPONSE_TYPE = {
|
||||
KNOWN_RPC_ERROR_CODE = {
|
||||
1783 : "RPC_X_BAD_STUB_DATA",
|
||||
1717 : "RPC_S_UNKNOWN_IF",
|
||||
1745 : "RPC_S_PROCNUM_OUT_OF_RANGE"
|
||||
|
||||
1728 : "RPC_S_PROTOCOL_ERROR",
|
||||
1730 : "RPC_S_UNSUPPORTED_TRANS_SYN",
|
||||
1745 : "RPC_S_PROCNUM_OUT_OF_RANGE",
|
||||
}
|
||||
|
||||
BIND_IF_SYNTAX_NDR32 = 1
|
||||
BIND_IF_SYNTAX_NDR64 = 2
|
||||
BIND_IF_SYNTAX_UNKNOWN = 4
|
||||
|
||||
NOT_USED = 0xBAADF00D
|
||||
|
||||
class ALPC_RPC_BIND(ctypes.Structure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("request_type", DWORD),
|
||||
("UNK1", DWORD),
|
||||
("UNK2", DWORD),
|
||||
("target", RPC_SYNTAX_IDENTIFIER),
|
||||
("flags", DWORD),
|
||||
("if_nb_ndr32", USHORT),
|
||||
("if_nb_ndr64", USHORT),
|
||||
("if_nb_unkn", USHORT),
|
||||
("PAD", USHORT),
|
||||
("register_multiple_syntax", DWORD),
|
||||
("use_flow", DWORD),
|
||||
("UNK5", DWORD),
|
||||
("maybe_flow_id", DWORD),
|
||||
("UNK7", DWORD),
|
||||
("some_context_id", DWORD),
|
||||
("UNK9", DWORD),
|
||||
]
|
||||
|
||||
|
||||
class RPCClient(object):
|
||||
REQUEST_IDENTIFIER = 0x11223344
|
||||
def __init__(self, port):
|
||||
self.aplc_client = alpc.AlpcClient()
|
||||
self.aplc_client.connect_to_port(port)
|
||||
self.alpc_client = alpc.AlpcClient(port)
|
||||
self.number_of_bind_if = 0 # if -> interface
|
||||
self.if_bind_number = {}
|
||||
|
||||
def bind(self, IID_str, version=(1,0)):
|
||||
IID = windows.com.IID.from_string(IID_str)
|
||||
request = self._forge_bind_request(buffer(IID)[:], version, self.number_of_bind_if)
|
||||
request = self._forge_bind_request(IID, version, self.number_of_bind_if)
|
||||
response = self._send_request(request)
|
||||
# Parse reponse
|
||||
request_type = self._get_request_type(response)
|
||||
@@ -86,21 +111,31 @@ class RPCClient(object):
|
||||
return response[4 * 6:] # Should be the return value (not completly verified)
|
||||
|
||||
def _send_request(self, request):
|
||||
resp_attr, resp = self.aplc_client.send_receive(request)
|
||||
return resp.data
|
||||
|
||||
def _forge_bind_request(self, rawuuid, syntaxversion, requested_if_nb):
|
||||
version_major, version_minor = syntaxversion
|
||||
data = struct.pack("III16sHHII8I", REQUEST_TYPE_BIND, NOT_USED, NOT_USED, rawuuid, version_major, version_minor, NOT_USED, requested_if_nb, *[NOT_USED] * 8)
|
||||
return data
|
||||
response = self.alpc_client.send_receive(request)
|
||||
return response.data
|
||||
|
||||
def _forge_call_request(self, interface_nb, method_offset, params):
|
||||
# TODO: differents REQUEST_IDENTIFIER for each req ?
|
||||
# TODO: what is this '0' ? (1 is also accepted) (flags ?)
|
||||
request = struct.pack("<16I", REQUEST_TYPE_CALL, NOT_USED, 0, self.REQUEST_IDENTIFIER, interface_nb, method_offset, *[NOT_USED] * 10)
|
||||
request = struct.pack("<16I", REQUEST_TYPE_CALL, NOT_USED, 1, self.REQUEST_IDENTIFIER, interface_nb, method_offset, *[NOT_USED] * 10)
|
||||
request += params
|
||||
return request
|
||||
|
||||
def _forge_bind_request(self, uuid, syntaxversion, requested_if_nb):
|
||||
# if syntaxversion == (1, 0):
|
||||
# requested_if_nb = 0x10000
|
||||
version_major, version_minor = syntaxversion
|
||||
req = ALPC_RPC_BIND()
|
||||
req.request_type = REQUEST_TYPE_BIND
|
||||
req.target = RPC_SYNTAX_IDENTIFIER(uuid, *syntaxversion)
|
||||
req.flags = BIND_IF_SYNTAX_NDR32
|
||||
req.if_nb_ndr32 = requested_if_nb
|
||||
req.if_nb_ndr64 = 0
|
||||
req.if_nb_unkn = 0
|
||||
req.register_multiple_syntax = False
|
||||
req.some_context_id = 0xB00B00B
|
||||
return buffer(req)[:]
|
||||
|
||||
def _get_request_type(self, response):
|
||||
"raise if request_type == RESPONSE_TYPE_FAIL"
|
||||
request_type = struct.unpack("<I", response[:4])[0]
|
||||
@@ -108,3 +143,11 @@ class RPCClient(object):
|
||||
error_code = struct.unpack("<5I", response)[2]
|
||||
raise ValueError("RPC Response error {0} ({1})".format(error_code, KNOWN_RPC_ERROR_CODE.get(error_code, error_code)))
|
||||
return request_type
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("YOLO")
|
||||
import windows.rpc
|
||||
UAC_UIID = "201ef99a-7fa0-444c-9399-19ba84f12a1a"
|
||||
client = windows.rpc.find_alpc_endpoint_and_connect(UAC_UIID)
|
||||
iid = client.custom_bind(UAC_UIID)
|
||||
client.custom_call(iid, 0, "")
|
||||
Reference in New Issue
Block a user