понедельник, 4 октября 2010 г.

RPC servers hijack

Внезапно придумал тут предельно простой и наверняка дико баянистый способ зная UUID RPC интерфейса найти его DispatchTable с адресами функций и сделать с ними всякое.
Для начала давайте внимательно посмотрим на прототип функции RpcServerRegisterIf2

Первым параметром передается RPC_IF_HANDLE, который описан в RpcDce.h как
typedef void __RPC_FAR * RPC_IF_HANDLE;
Что есс-но неправда. Лучше всего смотреть в серверную часть, сгеренерированную midl - там эта структура описана уже как RPC_SERVER_INTERFACE. Ее определение, взятое из RpcDceP.h:
typedef struct _RPC_SERVER_INTERFACE
{
    unsigned int Length;
    RPC_SYNTAX_IDENTIFIER InterfaceId;
    RPC_SYNTAX_IDENTIFIER TransferSyntax;
    PRPC_DISPATCH_TABLE DispatchTable;
    unsigned int RpcProtseqEndpointCount;
    PRPC_PROTSEQ_ENDPOINT RpcProtseqEndpoint;
    RPC_MGR_EPV __RPC_FAR *DefaultManagerEpv;
    void const __RPC_FAR *InterpreterInfo;
    unsigned int Flags ;
} RPC_SERVER_INTERFACE, __RPC_FAR * PRPC_SERVER_INTERFACE;


RPC_SYNTAX_IDENTIFIER описан в том же файле как
typedef struct _RPC_SYNTAX_IDENTIFIER {
    GUID SyntaxGUID;
    RPC_VERSION SyntaxVersion;
} RPC_SYNTAX_IDENTIFIER, __RPC_FAR * PRPC_SYNTAX_IDENTIFIER;

InterfaceId.SyntaxGUID - это наш UUID, который можно найти например алгоритмом Бойера-Мура
Длина структуры под win32 0x44 байта, под win64 0x60 байт

Итак у нас есть  RPC_SERVER_INTERFACE. Из поля DispatchTable.DispatchTableCount можно узнать количество методов в интерфейсе, но в DispatchTable.DispatchTable хранятся не сами адреса функций, а лишь Ndr-переходники
Нужную нам таблицу можно получить из поля RPC_SERVER_INTERFACE.InterpreterInfo - оно указывает на структуру MIDL_SERVER_INFO. Ее описание, взято из файла RpcNdr.h:

typedef struct  _MIDL_SERVER_INFO_
    {
    PMIDL_STUB_DESC                     pStubDesc;
    const SERVER_ROUTINE *              DispatchTable;
    PFORMAT_STRING                      ProcString;
    const unsigned short *              FmtStringOffset;
    const STUB_THUNK *                  ThunkTable;
    PRPC_SYNTAX_IDENTIFIER              pTransferSyntax;
    ULONG_PTR                           nCount;
    PMIDL_SYNTAX_INFO                   pSyntaxInfo;
} MIDL_SERVER_INFO, *PMIDL_SERVER_INFO;

Вот ее поле DispatchTable - это уже именно то что нужно

Итого алгоритм примерно такой - находим по RPC interface UUID cтруктуру RPC_SERVER_INTERFACE, проверяем ее длину, из RPC_SERVER_INTERFACE.DispatchTable.DispatchTableCount получаем число методов, из RPC_SERVER_INTERFACE.InterpreterInfo.DispatchTable - указатель на таблицу с адресами методов. Просто и надежно как топор

4 комментария:

  1. А как получить RPC_IF_HANDLE по UUID-у для _уже_ запущенного RPC сервера (имея доступ к его хост-процессу)? Относительно простого и документированного способа это сделать я так и не нашел.

    ОтветитьУдалить
  2. наверное исключительно из всяких недокументированных структур rpcrt4.dll

    Но у предложенного способа угона и нет такой задачи - я обычно знаю имя модуля, в которой лежит RPC_IF_HANDLE - мне нужно таблицу найти с обработчиками, а дальше либо проверить что ничего не пропатчено (а для этого все равно таблицу нужно с файла модуля с диска парзить), либо угнать самому

    ОтветитьУдалить
  3. Да, есть такой способ.
    Я им пользуюсь вот здесь crfilter.com.

    Однако, хотя способ будет работать по бегущему процессу, делать это не стоит, чревато.
    Лично я все равно патчу До взлета.

    Есть правда проблемы с патчами системых процессов на 8 ядре, Майкрософт там новую защиту довесила и даже не обьявила.:( Но это уже другая проблема.

    ОтветитьУдалить