13. windows.rpc – ALPC-based Windows RPC

The windows.rpc allows to perform the basic for MS-RPC:

  • find interface endpoints

  • connect to it

  • bind to interfaces

  • perform call

  • Marshall/Unmarshall NDR

13.1. RPCClient

class windows.rpc.RPCClient(port)[source]

A client for RPC-over-ALPC able to bind to interface and perform calls using NDR32 marshalling

alpc_client

The windows.alpc.AlpcClient used to communicate with the server

bind(iid, version=(1, 0))[source]

Bind to the IID with the given version

Returns:

windows.generated_def.IID

call(IID, method_offset, params, ipid=None)[source]

Call method number method_offset of interface IID with mashalled params. Handle ORPC calls via the ipid parameter.

param IID IID:

An IID previously returned by bind()

param int method_offset:

param str params:

The mashalled parameters (NDR32)

param GUID ipid:

The IPID for ORPC calls

returns:

str

forge_alpc_request(IID, method_offset, params, ipid=None)[source]

Craft an ALPC message containing an RPC request to call method_offset of interface IID` with ``params. Can be used to craft request without directly sending it

13.2. Epmapper

class windows.rpc.epmapper.UnpackTower(protseq, endpoint, address, object, syntax)
address

Alias for field number 2

endpoint

Alias for field number 1

object

Alias for field number 3

protseq

Alias for field number 0

syntax

Alias for field number 4

13.2.1. find_alpc_endpoints()

windows.rpc.find_alpc_endpoints(targetiid, version=(1, 0), nb_response=1, sid=_WELL_KNOWN_SID_TYPE.WinLocalSystemSid(0x16))[source]

Ask the EPMapper for ALPC endpoints of targetiid:version (maximum of nb_response)

Parameters:
  • targetiid (str) – The IID of the requested interface

  • version ((int,int)) – The version requested interface

  • nb_response (int) – The maximum number of response

  • sid (WELL_KNOWN_SID_TYPE) – The SID used to request the EPMapper

Returns:

[UnpackTower] – A list of UnpackTower

Example:

>>> import windows.rpc
>>> UAC_UIID = "201ef99a-7fa0-444c-9399-19ba84f12a1a"
>>> windows.rpc.find_alpc_endpoints(UAC_UIID)
[UnpackTower(protseq='ncalrpc',
                endpoint=bytearray(b'LRPC-c30c67fef2afa1612b'),
                address=None,
                object=<RPC_IF_ID "201EF99A-7FA0-444C-9399-19BA84F12A1A" (1, 0)>,
                syntax=<RPC_IF_ID "8A885D04-1CEB-11C9-9FE8-08002B104860" (2, 0)>)]

13.2.2. find_alpc_endpoint_and_connect()

windows.rpc.find_alpc_endpoint_and_connect(targetiid, version=(1, 0), sid=_WELL_KNOWN_SID_TYPE.WinLocalSystemSid(0x16))[source]

Ask the EPMapper for ALPC endpoints of targetiid:version and connect to one of them.

Parameters:
  • targetiid (str) – The IID of the requested interface

  • version ((int,int)) – The version requested interface

  • sid (WELL_KNOWN_SID_TYPE) – The SID used to request the EPMapper

Returns:

A connected RPCClient

Example:

>>> import windows.rpc
>>> UAC_UIID = "201ef99a-7fa0-444c-9399-19ba84f12a1a"
>>> client = windows.rpc.find_alpc_endpoint_and_connect(UAC_UIID)
>>> client
<windows.rpc.client.RPCClient object at 0x046A1470>
>>> client.alpc_client.port_name
'\\RPC Control\\LRPC-c30c67fef2afa1612b'
>>> iid = client.bind(UAC_UIID)
>>> iid
<IID "201EF99A-7FA0-444C-9399-19BA84F12A1A">

13.3. Ndr

The windows.rpc.ndr module offers some construction to help marshalling types and structures to NDR.

Note

The NDR supported for now is 8a885d04-1ceb-11c9-9fe8-08002b104860 version 2.0

Each NDR class has a function pack().

class windows.rpc.ndr.NdrSID[source]
classmethod pack(psid)[source]

Pack a PSID

Parameters:

psid (PSID)

classmethod unpack(stream)[source]

Unpack a PSID, partial implementation that returns a str and not a PSID

>>> import windows.generated_def as gdef
>>> sid = windows.utils.get_known_sid(gdef.WinLocalSystemSid)
>>> sid
c_void_p(78304040)
>>> psidstr = windows.rpc.ndr.NdrSID.pack(sid)
>>> psidstr
'\x01\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\x12\x00\x00\x00'
>>> windows.rpc.ndr.NdrSID.unpack(windows.rpc.ndr.NdrStream(psidstr))
# Implementation is partial for now and does not return a PSID but a string
'\x01\x01\x00\x00\x00\x00\x00\x05\x12\x00\x00\x00'
class windows.rpc.ndr.NdrWString[source]
classmethod pack(data)[source]

Pack string data. append \x00 if not present at the end of the string

>>> from windows.rpc import ndr
>>> x = ndr.NdrWString.pack("Test-String\x00")
>>> x
'\x0c\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00T\x00e\x00s\x00t\x00-\x00S\x00t\x00r\x00i\x00n\x00g\x00\x00\x00'
>>> ndr.NdrWString.unpack(ndr.NdrStream(x))
u'Test-String\x00'
class windows.rpc.ndr.NdrCString[source]
classmethod pack(data)[source]

Pack string data. append \x00 if not present at the end of the string

>>> from windows.rpc import ndr
>>> x = ndr.NdrCString.pack("Test-String\x00")
>>> x
'\x0c\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00Test-String\x00'
# TODO: implem unpack
class windows.rpc.ndr.NdrLong[source]
>>> from windows.rpc import ndr
>>> x = ndr.NdrLong.pack(0x01020304)
>>> x
'\x04\x03\x02\x01'
>>> hex(ndr.NdrLong.unpack(ndr.NdrStream(x)))
'0x1020304'
class windows.rpc.ndr.NdrHyper[source]
>>> from windows.rpc import ndr
>>> x = ndr.NdrHyper.pack(0x0102030405060708)
>>> x
'\x08\x07\x06\x05\x04\x03\x02\x01'
>>> hex(ndr.NdrHyper.unpack(ndr.NdrStream(x)))
'0x102030405060708L'
class windows.rpc.ndr.NdrShort[source]
>>> from windows.rpc import ndr
>>> x = ndr.NdrShort.pack(0x0102)
>>> x
'\x02\x01'
>>> hex(ndr.NdrShort.unpack(ndr.NdrStream(x)))
'0x102'
class windows.rpc.ndr.NdrByte[source]
>>> from windows.rpc import ndr
>>> x = ndr.NdrByte.pack(0x42)
>>> x
'B'
>>> hex(ndr.NdrByte.unpack(ndr.NdrStream(x)))
'0x42'
class windows.rpc.ndr.NdrUniquePTR(subcls)[source]

Create a UNIQUE PTR around a given Ndr type

>>> from windows.rpc import ndr
>>> ndr.NdrLong.pack(0x11111111)
'\x11\x11\x11\x11'
>>> ndr.NdrUniquePTR(ndr.NdrLong).pack(0x11111111)
'\x02\x02\x02\x02\x11\x11\x11\x11'
class windows.rpc.ndr.NdrConformantArray[source]
class windows.rpc.ndr.NdrConformantVaryingArrays[source]
class windows.rpc.ndr.NdrLongConformantArray[source]
>>> windows.rpc.ndr.NdrLongConformantArray.pack([1,2,3,4])
'\x04\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
class windows.rpc.ndr.NdrByteConformantArray[source]
>>> windows.rpc.ndr.NdrByteConformantArray.pack([1,2,3,4])
'\x04\x00\x00\x00\x01\x02\x03\x04'
class windows.rpc.ndr.NdrStructure[source]

a NDR structure that tries to respect the rules of pointer packing, this class should be subclassed with an attribute MEMBERS describing the members of the class

classmethod pack(data)[source]

Pack data into the struct, data size must equals the number of members in the structure

classmethod unpack(stream)[source]

Unpack the structure from the stream

>>> from windows.rpc import ndr
>>> class NDRTest(ndr.NdrStructure):
...     MEMBERS = [ndr.NdrLong, ndr.NdrLong, ndr.NdrWString]
...
>>> x = NDRTest.pack([1, 2, "Test\x00"])
>>> x
'\x01\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00T\x00e\x00s\x00t\x00\x00\x00PP'
>>> NDRTest.unpack(ndr.NdrStream(x))
[1, 2, u'Test\x00']
class windows.rpc.ndr.NdrParameters[source]

a class to pack NDR parameters together to performs RPC call, this class should be subclassed with an attribute MEMBERS describing the members of the class

13.3.1. NDR STREAM

class windows.rpc.ndr.NdrStream(data)[source]

A stream of bytes used for NDR unpacking

align(size)[source]

Discard some bytes to align the remaining stream on size

>>> from windows.rpc import ndr
>>> x = ndr.NdrStream("AAAABBBBCCCC")
>>> hex(ndr.NdrLong.unpack(x))
'0x41414141'
>>> x.data
'BBBBCCCC'
>>> hex(ndr.NdrShort.unpack(x))
'0x4242'
>>> x.data
'BBCCCC'
>>> x.align(4)
>>> x.data
'CCCC'
>>> hex(ndr.NdrLong.unpack(x))
'0x43434343'