def find_alpc_endpoints(targetiid,
                        version=(1, 0),
                        nb_response=1,
                        sid=gdef.WinLocalSystemSid):
    """Ask the EPMapper for ALPC endpoints of ``targetiid:version`` (maximum of ``nb_response``)

        :param str targetiid: The IID of the requested interface
        :param (int,int) version: The version requested interface
        :param int nb_response: The maximum number of response
        :param WELL_KNOWN_SID_TYPE sid: The SID used to request the EPMapper

        :returns: [:class:`~windows.rpc.epmapper.UnpackTower`] -- A list of :class:`~windows.rpc.epmapper.UnpackTower`
    """

    if isinstance(targetiid, basestring):
        targetiid = gdef.IID.from_string(targetiid)
    # Connect to epmapper
    client = windows.rpc.RPCClient(r"\RPC Control\epmapper")
    epmapperiid = client.bind("e1af8308-5d1f-11c9-91a4-08002b14a0fa",
                              version=(3, 0))

    # Compute request tower
    ## object
    rpc_object = gdef.RPC_IF_ID(targetiid, *version)
    ## Syntax
    syntax_iid = gdef.IID.from_string("8a885d04-1ceb-11c9-9fe8-08002b104860")
    rpc_syntax = gdef.RPC_IF_ID(syntax_iid, 2, 0)
    ## Forge tower
    tower_array_size, towerarray = construct_alpc_tower(
        rpc_object, rpc_syntax, "ncalrpc", b"", None)

    # parameters
    local_system_psid = windows.utils.get_known_sid(sid)
    context = (0, 0, 0, 0, 0)

    # Pack request
    fullreq = EptMapAuthParameters.pack([
        bytearray(targetiid), (tower_array_size, towerarray),
        local_system_psid, context, nb_response
    ])
    # RPC Call
    response = client.call(epmapperiid, 7, fullreq)
    # Unpack response
    stream = ndr.NdrStream(response)
    unpacked = EptMapAuthResults.unpack(stream)
    # Looks like there is a memory leak here (in stream.data) if nb_response > len(unpacked[2])
    # Parse towers
    return [explode_alpc_tower(obj) for obj in unpacked[2]]
Example #2
0
 def _forge_bind_request(self, uuid, syntaxversion, requested_if_nb):
     version_major, version_minor = syntaxversion
     req = ALPC_RPC_BIND()
     req.request_type = gdef.RPC_REQUEST_TYPE_BIND
     req.target = gdef.RPC_IF_ID(uuid, *syntaxversion)
     req.flags = gdef.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 explode_alpc_tower(tower):
    stream = ndr.NdrStream(bytearray(tower))
    size = stream.partial_unpack("<I")[0]
    if size != len(stream.data):
        raise ValueError(
            "Invalid tower size: indicate {0}, tower size {1}".format(
                size, len(stream.data)))
    floor_count = stream.partial_unpack("<H")[0]
    if floor_count != 4:
        raise ValueError(
            "ALPC Tower are expected to have 4 floors ({0} instead)".format(
                floor_count))

    # Floor 0
    lhs, rhs = parse_floor(stream)
    if not (lhs[0] == 0xd):
        raise ValueError("Floor 0: IID expected")
    iid = gdef.IID.from_buffer_copy(lhs[1:17])
    object = gdef.RPC_IF_ID(iid, lhs[17], lhs[18])

    # Floor 1
    lhs, rhs = parse_floor(stream)
    if not (lhs[0] == 0xd):
        raise ValueError("Floor 0: IID expected")
    iid = gdef.IID.from_buffer_copy(lhs[1:17])
    syntax = gdef.RPC_IF_ID(iid, lhs[17], lhs[18])

    # Floor 2
    lhs, rhs = parse_floor(stream)
    if (len(lhs) != 1 or lhs[0] != 0x0c):
        raise ValueError(
            "Alpc Tower expects 0xc as Floor2 LHS (got {0:#x})".format(lhs[0]))

    lhs, rhs = parse_floor(stream)
    if not (rhs[-1] == 0):
        rhs = rhs[:rhs.find("\x00")]
        # raise ValueError("ALPC Port name doest not end by \\x00")
    return UnpackTower("ncalrpc", bytes(rhs[:-1]), None, object, syntax)