Add some ALPC samples to the documentation

This commit is contained in:
Clement Rouault
2017-08-28 17:09:49 +02:00
parent 1941adc93f
commit 1fe5b912be
6 changed files with 323 additions and 46 deletions
+7
View File
@@ -7,6 +7,13 @@ The :mod:`windows.alpc` module regroups the classes that permits to send and rec
ALPC messages over an ALPC port and the classes representing these messages.
.. note::
See samples:
* :ref:`sample_alpc`
* :ref:`sample_advanced_alpc`
ALPC Message
------------
+119 -1
View File
@@ -730,4 +730,122 @@ Ouput::
File embdeds 2 certificate(s):
* 0) <CertificateContext "Microsoft Windows" serial="33 00 00 01 06 6e c3 25 c4 31 c9 18 0e 00 00 00 00 01 06">
* 1) <CertificateContext "Microsoft Windows Production PCA 2011" serial="61 07 76 56 00 00 00 00 00 08">
* 1) <CertificateContext "Microsoft Windows Production PCA 2011" serial="61 07 76 56 00 00 00 00 00 08">
``windows.alpc``
""""""""""""""""
.. _sample_alpc:
simple alpc communication
'''''''''''''''''''''''''
.. literalinclude:: ..\..\samples\alpc\simple_alpc.py
Ouput::
(cmd λ) python alpc\simple_alpc.py
[SERV] PORT <\RPC Control\PythonForWindowsPORT> CREATED
Client pid = 15044
[SERV] Message type = 0x300a
[SERV] Received data: <>
[SERV] Connection request
[CLIENT] Connected: <windows.alpc.AlpcClient object at 0x0377FDB0>
[SERV] Received message: <Hello world !>
[SERV] Message type = 0x3001
[CLIENT] Response: <REQUEST 'Hello world !' DONE>
BYE
.. _sample_advanced_alpc:
advanced alpc communication
'''''''''''''''''''''''''''
.. literalinclude:: ..\..\samples\alpc\advanced_alpc.py
Output::
(cmd λ) python alpc\advanced_alpc.py
server pid = 13000
[SERV] PORT <\RPC Control\PythonForWindowsPORT_2> CREATED
Client pid = 2100
[CLIENT] == Connecting to port ==
[SERV] == Message received ==
* ALPC connection request: <Connection request client message>
[CLIENT] Connected with response: <Connection message response>
[CLIENT] == Sending a message ==
* Sending Message <Complex Message 1>
[SERV] == Message received ==
* ALPC request: <Complex Message 1>
* view_is_valid <False>
* security_is_valid <False>
* handle_is_valid <False>
* context_is_valid <True>
* message context attribute:
- CTX.PortContext -> 0x11223344
- CTX.MessageContext -> None
- CTX.Sequence -> 0x1L
- CTX.MessageId -> 0x0L
- CTX.CallbackId -> 0x0L
* message token attribute:
- TOKEN.TokenId -> 0x1e4ecaccL
- TOKEN.AuthenticationId -> 0x48989L
- TOKEN.ModifiedId -> 0x48995L
[CLIENT] Server response: <REQUEST 'Complex Message 1' DONE>
[CLIENT] RESP Message Valid ATTRS = [ALPC_MESSAGE_CONTEXT_ATTRIBUTE(0x20000000L)]
[Client] == Sending a message with a handle ==
[SERV] == Message received ==
* ALPC request: <some message with a file>
* view_is_valid <False>
* security_is_valid <False>
* handle_is_valid <True>
* message handle attribute:
- HANDLE.Flags -> 0x0L
- HANDLE.Handle -> 0x260
- HANDLE.ObjectType -> 0x1L
- HANDLE.DesiredAccess -> 0x13019fL
- File: <open file '<fdopen>', mode 'r' at 0x02D529C0>
- content: <Tempfile data <3>
* context_is_valid <True>
* message context attribute:
- CTX.PortContext -> 0x11223344
- CTX.MessageContext -> None
- CTX.Sequence -> 0x2L
- CTX.MessageId -> 0x0L
- CTX.CallbackId -> 0x0L
* message token attribute:
- TOKEN.TokenId -> 0x1e4ecaccL
- TOKEN.AuthenticationId -> 0x48989L
- TOKEN.ModifiedId -> 0x48995L
[Client] == Sending a message with a view ==
[SERV] == Message received ==
* ALPC request: <some message with a view>
* view_is_valid <True>
* message view attribute:
- VIEW.Flags -> 0x0L
- VIEW.SectionHandle -> None
- VIEW.ViewBase -> 0x2770000
- VIEW.ViewSize -> 0x4000
* Reading view content: <The content of the view :)>
* security_is_valid <False>
* handle_is_valid <False>
* context_is_valid <True>
* message context attribute:
- CTX.PortContext -> 0x11223344
- CTX.MessageContext -> None
- CTX.Sequence -> 0x3L
- CTX.MessageId -> 0x0L
- CTX.CallbackId -> 0x0L
* message token attribute:
- TOKEN.TokenId -> 0x1e4ecaccL
- TOKEN.AuthenticationId -> 0x48989L
- TOKEN.ModifiedId -> 0x48995L
BYE
+146
View File
@@ -0,0 +1,146 @@
import multiprocessing
import windows.alpc
from windows.generated_def import LPC_CONNECTION_REQUEST, LPC_REQUEST
import windows.generated_def as gdef
import ctypes
import tempfile
PORT_NAME = r"\RPC Control\PythonForWindowsPORT_2"
PORT_CONTEXT = 0x11223344
def full_alpc_server():
print("server pid = {0}".format(windows.current_process.pid))
server = windows.alpc.AlpcServer(PORT_NAME)
print("[SERV] PORT <{0}> CREATED".format(PORT_NAME))
msg = server.recv()
print("[SERV] == Message received ==")
if msg.type & 0xfff == LPC_CONNECTION_REQUEST:
print(" * ALPC connection request: <{0}>".format(msg.data))
msg.data = "Connection message response"
server.accept_connection(msg, port_context=PORT_CONTEXT)
else:
raise ValueError("Expected connection")
while True:
msg = server.recv()
print("[SERV] == Message received ==")
# print(" * Data: {0}".format(msg.data))
# print("[SERV] RECV Message type = {0:#x}".format(msg.type))
# print("[SERV] RECV Message Valid ATTRS = {0:#x}".format(msg.attributes.ValidAttributes))
# print("[SERV] RECV Message ATTRS = {0:#x}".format(msg.attributes.AllocatedAttributes))
if msg.type & 0xfff == LPC_REQUEST:
print(" * ALPC request: <{0}>".format(msg.data))
print(" * view_is_valid <{0}>".format(msg.view_is_valid))
if msg.view_is_valid:
print(" * message view attribute:")
windows.utils.print_ctypes_struct(msg.view_attribute, " - VIEW", hexa=True)
view_data = windows.current_process.read_string(msg.view_attribute.ViewBase)
print(" * Reading view content: <{0}>".format(view_data))
print(" * security_is_valid <{0}>".format(msg.security_is_valid))
print(" * handle_is_valid <{0}>".format(msg.handle_is_valid))
if msg.handle_is_valid:
if msg.handle_attribute.Handle:
print(" * message handle attribute:")
windows.utils.print_ctypes_struct(msg.handle_attribute, " - HANDLE", hexa=True)
if msg.handle_attribute.ObjectType == 1:
f = windows.utils.create_file_from_handle(msg.handle_attribute.Handle)
print(" - File: {0}".format(f))
print(" - content: <{0}>".format(f.read()))
else:
print(" - unknow object type == {0}".format(msg.handle_attribute.ObjectType))
msg.attributes.ValidAttributes -= gdef.ALPC_MESSAGE_HANDLE_ATTRIBUTE
print(" * context_is_valid <{0}>".format(msg.context_is_valid))
if msg.context_is_valid:
print(" * message context attribute:")
windows.utils.print_ctypes_struct(msg.context_attribute, " - CTX", hexa=True)
if msg.attributes.ValidAttributes & gdef.ALPC_MESSAGE_TOKEN_ATTRIBUTE:
print(" * message token attribute:")
token_struct = msg.attributes.get_attribute(gdef.ALPC_MESSAGE_TOKEN_ATTRIBUTE)
windows.utils.print_ctypes_struct(token_struct, " - TOKEN", hexa=True)
# We can reply by to way:
# - Send the same message with modified data
# - Recreate a Message and copy the MessageId
msg.data = "REQUEST '{0}' DONE".format(msg.data)
server.send(msg)
else:
raise ValueError("Unexpected message type")
def send_message_with_handle(client):
print ""
print("[Client] == Sending a message with a handle ==")
# Craft a file with some data
f = tempfile.NamedTemporaryFile()
f.write("Tempfile data <3")
f.seek(0)
# New message with a Handle
msg = windows.alpc.AlpcMessage()
msg.attributes.ValidAttributes |= gdef.ALPC_MESSAGE_HANDLE_ATTRIBUTE
msg.handle_attribute.Flags = gdef.ALPC_HANDLEFLG_DUPLICATE_SAME_ACCESS
msg.handle_attribute.Handle = windows.utils.get_handle_from_file(f)
msg.handle_attribute.ObjectType = 0
msg.handle_attribute.DesiredAccess = 0
msg.data = "some message with a file"
client.send_receive(msg)
def send_message_with_view(client):
print ""
print("[Client] == Sending a message with a view ==")
# Create View
section = client.create_port_section(0, 0, 0x4000)
view = client.map_section(section[0], 0x4000)
# New message with a View
msg = windows.alpc.AlpcMessage(0x2000)
msg.attributes.ValidAttributes |= gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE
msg.view_attribute.Flags = 0
msg.view_attribute.ViewBase = view.ViewBase
msg.view_attribute.SectionHandle = view.SectionHandle
msg.view_attribute.ViewSize = 0x4000
msg.data = "some message with a view"
windows.current_process.write_memory(view.ViewBase, "The content of the view :)\x00")
client.send_receive(msg)
def alpc_client():
print("Client pid = {0}".format(windows.current_process.pid))
client = windows.alpc.AlpcClient()
# You can create a non-connected AlpcClient and send a custom
# 'AlpcMessage' for complexe alpc port connection.
connect_message = windows.alpc.AlpcMessage()
connect_message.data = "Connection request client message"
print("[CLIENT] == Connecting to port ==")
connect_response = client.connect_to_port(PORT_NAME, connect_message)
print("[CLIENT] Connected with response: <{0}>".format(connect_response.data))
# AlpcClient send/recv/send_receive methods accept both string or
# AlpcMessage for complexe message.
print""
print("[CLIENT] == Sending a message ==")
msg = windows.alpc.AlpcMessage()
msg.data = "Complex Message 1"
print(" * Sending Message <{0}>".format(msg.data))
response = client.send_receive(msg)
print("[CLIENT] Server response: <{0}>".format(response.data))
print("[CLIENT] RESP Message Valid ATTRS = {0}".format(response.valid_attributes))
send_message_with_handle(client)
send_message_with_view(client)
if __name__ == "__main__":
proc = multiprocessing.Process(target=full_alpc_server, args=())
proc.start()
import time; time.sleep(0.5)
alpc_client()
print("BYE")
proc.terminate()
+50
View File
@@ -0,0 +1,50 @@
import multiprocessing
import windows.alpc
from windows.generated_def import LPC_CONNECTION_REQUEST, LPC_REQUEST
PORT_NAME = r"\RPC Control\PythonForWindowsPORT"
def alpc_server():
server = windows.alpc.AlpcServer(PORT_NAME) # Create the ALPC Port
print("[SERV] PORT <{0}> CREATED".format(PORT_NAME))
msg = server.recv() # Wait for a message
print("[SERV] Message type = {0:#x}".format(msg.type))
print("[SERV] Received data: <{0}>".format(msg.data))
assert msg.type & 0xfff == LPC_CONNECTION_REQUEST # Check that message is a connection request
print("[SERV] Connection request")
server.accept_connection(msg)
msg = server.recv() # Wait for a real message
print ""
print("[SERV] Received message: <{0}>".format(msg.data))
print("[SERV] Message type = {0:#x}".format(msg.type))
assert msg.type & 0xfff == LPC_REQUEST
# We can reply by two ways:
# - Send the same message with modified data
# - Recreate a Message and copy the MessageId
msg.data = "REQUEST '{0}' DONE".format(msg.data)
server.send(msg)
def alpc_client():
print("Client pid = {0}".format(windows.current_process.pid))
# Creation an 'AlpcClient' with a port name will connect to the port with an empty message
client = windows.alpc.AlpcClient(PORT_NAME)
print("[CLIENT] Connected: {0}".format(client))
# Send a message / wait for the response
response = client.send_receive("Hello world !")
print("[CLIENT] Response: <{0}>".format(response.data))
# You can also send message without waiting for a response with 'client.send'
if __name__ == "__main__":
proc = multiprocessing.Process(target=alpc_server, args=())
proc.start()
import time; time.sleep(0.5)
alpc_client()
print("BYE")
proc.terminate()
-44
View File
@@ -1,44 +0,0 @@
import multiprocessing
import windows.alpc
from windows.generated_def import LPC_CONNECTION_REQUEST, LPC_REQUEST
PORT_NAME = r"\RPC Control\YOLOPORT"
def alpc_server():
server = windows.alpc.AlpcServer(PORT_NAME) # NtAlpcCreatePort
print("[SERV] PORT CREATED")
msg = server.recv() # NtAlpcSendWaitReceivePort (send_msg = None)
print("[SERV] Message type = {0:#x}".format(msg.u2.s2.Type))
print("[SERV] Received data: <{0}>".format(msg.data))
if msg.type & 0xfff & LPC_CONNECTION_REQUEST:
print("[SERV] Connection request")
msg.data = "WOKAY"
server.accept_connection(msg) # NtAlpcAcceptConnectPort
msg = server.recv() # NtAlpcSendWaitReceivePort (send_msg = None)
print("[SERV] Received message")
print("[SERV] Message type = {0:#x}".format(msg.u2.s2.Type))
if msg.type & 0xfff & LPC_REQUEST:
print("[SERV] ALPC request: <{0}>".format(msg.data))
# We can reply by to way:
# - Send the same message with modified data
# - Recreate a Message and copy the MessageId
msg.data = "REQUEST '{0}' DONE".format(msg.data)
server.send(msg)
def alpc_client():
client = windows.alpc.AlpcClient()
connect_response = client.connect_to_port(PORT_NAME, "COUCOU") # NtAlpcConnectPort
print("[CLIENT] Connected: {0}".format(connect_response.data))
print("[CLIENT] Send Message <POUET>")
response = client.send_receive("POUET") # NtAlpcSendWaitReceivePort
print("[CLIENT] Server response: <{0}>".format(response.data))
if __name__ == "__main__":
proc = multiprocessing.Process(target=alpc_server, args=())
proc.start()
import time; time.sleep(0.5)
alpc_client()
print("BYE")
+1 -1
View File
@@ -404,7 +404,7 @@ class AlpcClient(AlpcTransportBase):
else:
raise ValueError("Don't know how to send <{0!r}> as connect message".format(connect_message))
windows.utils.print_ctypes_struct(port_attr, "port_attr_connect", hexa=True)
# windows.utils.print_ctypes_struct(port_attr, "port_attr_connect", hexa=True)
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 :)