# 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

Note

See samples:

> - Manual UAC
> - Manual LsarEnumeratePrivileges

## 13.1. RPCClient

class `windows.rpc.``RPCClient`(port)

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

  `alpc_client` = None

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

  `bind`(IID_str, version=(1, 0))

    Bind to the `IID_str` with the given `version`

    Returns: | `windows.generated_def.IID`

  `call`(IID, method_offset, params, ipid=None)

    Call method number `method_offset` of interface `IID` with mashalled `params`

    Parameters:

    - IID (IID) – An IID previously returned by `bind()`
    - method_offset (int) –
    - params (str) – The mashalled parameters (NDR32)

    Returns: | `str`

  `forge_alpc_request`(IID, method_offset, params, ipid=None)

    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(0x16L))

  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(0x16L))

  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`
  classmethod `pack`(psid)

    Pack a PSID

    Parameters: | psid (PSID) –

  classmethod `unpack`(stream)

    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`
  classmethod `pack`(data)

    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`
  classmethod `pack`(data)

    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`

    >>> 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`

    >>> 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`

      >>> 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`

    >>> 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)

  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`

class `windows.rpc.ndr.``NdrConformantVaryingArrays`

class `windows.rpc.ndr.``NdrLongConformantArray`

    >>> 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`

    >>> windows.rpc.ndr.NdrByteConformantArray.pack([1,2,3,4])
    '\x04\x00\x00\x00\x01\x02\x03\x04'

class `windows.rpc.ndr.``NdrStructure`

  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)

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

  classmethod `unpack`(stream)

    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`

  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)

  A stream of bytes used for NDR unpacking

  `align`(size)

    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'