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

Note

Since 1.0.3 if the call is an ORPC call, the ORPCTHAT & LOCALTHAT present in the response are parsed and striped from the result.

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, use_memoryview=False)[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'