пятница, 15 октября 2010 г.

port & alpc port owners

Я тут уже писал как можно получить список локальных RPC портов.В этом способе нет абсолютно ничего примечательного - через NtOpenDirectoryObject открываем директорию L"\\RPC control" и читаем с помощью NtQueryDirectoryObject пока не вернется STATUS_NO_MORE_ENTRIES.
Но еще хотелось бы иметь PID процесса-владельца этих ресурсов. Чтение доки не особо помогло - например есть такая официальная функция nt api ZwQueryInformationPort, которая имеет ровно один более чем бессмысленный classinfo PORT_INFORMATION_CLASS
Пришлось как обычно кряхтя слазить с печи и делать все самому
Например начать всегда хорошо с курения сорцов - в данном случае WRK v1.2
В файле base\ntos\lpc\lpcconn.c есть все что нам нужно - можно открыть порт через ObReferenceObjectByName с типом LpcPortObjectType или LpcWaitablePortObjectType и получить внутреннее представление объекта port в виде структуры LPCP_PORT_OBJECT, которая описана в base\ntos\inc\lpc.h так:

#define PORT_TYPE                           0x0000000F
#define SERVER_CONNECTION_PORT              0x00000001
#define UNCONNECTED_COMMUNICATION_PORT      0x00000002
#define SERVER_COMMUNICATION_PORT           0x00000003
#define CLIENT_COMMUNICATION_PORT           0x00000004
#define PORT_WAITABLE                       0x20000000
#define PORT_NAME_DELETED                   0x40000000
#define PORT_DYNAMIC_SECURITY               0x80000000
 

typedef struct _LPCP_PORT_QUEUE {
    PLPCP_NONPAGED_PORT_QUEUE NonPagedPortQueue;
    PKSEMAPHORE Semaphore;      // Counting semaphore that is incremented
                                // whenever a message is put in receive queue
    LIST_ENTRY ReceiveHead;     // list of messages to receive
} LPCP_PORT_QUEUE, *PLPCP_PORT_QUEUE;
 

typedef struct _LPCP_PORT_OBJECT {
    struct _LPCP_PORT_OBJECT *ConnectionPort;
    struct _LPCP_PORT_OBJECT *ConnectedPort;
    LPCP_PORT_QUEUE MsgQueue;
    CLIENT_ID Creator;
    PVOID ClientSectionBase;
    PVOID ServerSectionBase;
    PVOID PortContext;
    PETHREAD ClientThread;                  // only SERVER_COMMUNICATION_PORT
    SECURITY_QUALITY_OF_SERVICE SecurityQos;
    SECURITY_CLIENT_CONTEXT StaticSecurity;
    LIST_ENTRY LpcReplyChainHead;           // Only in _COMMUNICATION ports
    LIST_ENTRY LpcDataInfoChainHead;        // Only in _COMMUNICATION ports
    union {
        PEPROCESS ServerProcess;                // Only in SERVER_CONNECTION ports
        PEPROCESS MappingProcess;               // Only in _COMMUNICATION    ports
    };
    USHORT MaxMessageLength;
    USHORT MaxConnectionInfoLength;
    ULONG Flags;
    KEVENT WaitEvent;                          // Object is truncated for non-waitable ports
} LPCP_PORT_OBJECT, *PLPCP_PORT_OBJECT;


Как видим все довольно просто, но как обычно без засады не обошлось - LpcWaitablePortObjectType не экспортируется. Я плюнул и забил - оказалось что rpc порты и с типом LpcPortObjectType отлично открываются.
По получении PLPCP_PORT_OBJECT проверяем что это именно серверный порт ((Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) и извлекаем PID из поля ServerProcess с помощью функции PsGetProcessId (на w2k работать не будет. Впрочем если верить Русиновичу - смещение на поле EPROCESS.UniqueProcessId равно 0x9c)

Небольшой кусочек лога на xp 32bit:
Port: protected_storage
 Flags: 1, server 988 (C:\WINDOWS\system32\lsass.exe)
Port: audit
 Flags: 1, server 988 (C:\WINDOWS\system32\lsass.exe)
Port: spoolss
 Flags: 1, server 800 (C:\WINDOWS\system32\spoolsv.exe)
Port: securityevent
 Flags: 1, server 988 (C:\WINDOWS\system32\lsass.exe)
Port: IUserProfile
 Flags: 1, server 932 (C:\WINDOWS\system32\winlogon.exe)
Port: DNSResolver
 Flags: 1, server 176 (C:\WINDOWS\system32\svchost.exe)
 Запускаем на vista/w7 - получаем какой-то треш. Долго нервно курим, читаем доку - обретаем просветление - начиная с vista RPC использует другой тип объектов - ALPC Port. Медитация в отладчике говорит, что вместо LPCP_PORT_OBJECT ObReferenceObjectByName возвращает нам  PALPC_PORT (взято с windows 7 64bit):

dt _ALPC_PORT
   +0x000 PortListEntry    : _LIST_ENTRY
   +0x010 CommunicationInfo : Ptr64 _ALPC_COMMUNICATION_INFO
   +0x018 OwnerProcess     : Ptr64 _EPROCESS
   +0x020 CompletionPort   : Ptr64 Void
   +0x028 CompletionKey    : Ptr64 Void
   +0x030 CompletionPacketLookaside : Ptr64 _ALPC_COMPLETION_PACKET_LOOKASIDE
   +0x038 PortContext      : Ptr64 Void
   +0x040 StaticSecurity   : _SECURITY_CLIENT_CONTEXT
   +0x088 MainQueue        : _LIST_ENTRY
   +0x098 PendingQueue     : _LIST_ENTRY
   +0x0a8 LargeMessageQueue : _LIST_ENTRY
   +0x0b8 WaitQueue        : _LIST_ENTRY
   +0x0c8 Semaphore        : Ptr64 _KSEMAPHORE
   +0x0c8 DummyEvent       : Ptr64 _KEVENT
   +0x0d0 PortAttributes   : _ALPC_PORT_ATTRIBUTES
   +0x118 Lock             : _EX_PUSH_LOCK
   +0x120 ResourceListLock : _EX_PUSH_LOCK
   +0x128 ResourceListHead : _LIST_ENTRY
   +0x138 CompletionList   : Ptr64 _ALPC_COMPLETION_LIST
   +0x140 MessageZone      : Ptr64 _ALPC_MESSAGE_ZONE
   +0x148 CallbackObject   : Ptr64 _CALLBACK_OBJECT
   +0x150 CallbackContext  : Ptr64 Void
   +0x158 CanceledQueue    : _LIST_ENTRY
   +0x168 SequenceNo       : Int4B
   +0x16c u1               :
   +0x170 TargetQueuePort  : Ptr64 _ALPC_PORT
   +0x178 TargetSequencePort : Ptr64 _ALPC_PORT
   +0x180 CachedMessage    : Ptr64 _KALPC_MESSAGE
   +0x188 MainQueueLength  : Uint4B
   +0x18c PendingQueueLength : Uint4B
   +0x190 LargeMessageQueueLength : Uint4B
   +0x194 CanceledQueueLength : Uint4B
   +0x198 WaitQueueLength  : Uint4B



Тут все еще проще - никаких флагов проверять не нужно, сразу берем OwnerProcess и суем в PsGetProcessId. Примерчик работы на windows7:
ALPC Port: senssvc
 Flags: 0, server 940 (C:\Windows\System32\svchost.exe)
ALPC Port: lsapolicylookup
 Flags: 0, server 488 (C:\Windows\System32\lsass.exe)
ALPC Port: LSMApi
 Flags: 0, server 496 (C:\Windows\System32\lsm.exe)
ALPC Port: WMsgKRpc0492F0
 Flags: 0, server 400 (C:\Windows\System32\wininit.exe)
ALPC Port: WindowsShutdown
 Flags: 0, server 400 (C:\Windows\System32\wininit.exe)
 Сорцов давать не буду, ибо читателям детского юмористического журнала ксакеп они не помогут, а нормальным гражданам из описания и так все должно быть понятно

Update: под w2k _LPCP_PORT_OBJECT выглядит так:
nt!_LPCP_PORT_OBJECT
   +0x000 Length           : Uint4B
   +0x004 Flags            : Uint4B
   +0x008 ConnectionPort   : Ptr32 _LPCP_PORT_OBJECT
   +0x00c ConnectedPort    : Ptr32 _LPCP_PORT_OBJECT
   +0x010 MsgQueue         : _LPCP_PORT_QUEUE
   +0x020 Creator          : _CLIENT_ID
   +0x028 ClientSectionBase : Ptr32 Void
   +0x02c ServerSectionBase : Ptr32 Void
   +0x030 PortContext      : Ptr32 Void
   +0x034 MaxMessageLength : Uint4B
   +0x038 MaxConnectionInfoLength : Uint4B
   +0x03c ClientThread     : Ptr32 _ETHREAD
   +0x040 SecurityQos      : _SECURITY_QUALITY_OF_SERVICE
   +0x04c StaticSecurity   : _SECURITY_CLIENT_CONTEXT
   +0x088 LpcReplyChainHead : _LIST_ENTRY
   +0x090 LpcDataInfoChainHead : _LIST_ENTRY
   +0x098 ServerProcess    : Ptr32 _EPROCESS
   +0x098 MappingProcess   : Ptr32 _EPROCESS
   +0x09c Reserved         : Uint4B
   +0x0a0 WaitEvent        : _KEVENT

Комментариев нет:

Отправить комментарий