понедельник, 28 марта 2011 г.

Еще один способ детекта скрытых процессов и потоков

Давным-давно появились штуки типа DKOM, позволяющие скрывать потоки/процессы/(да и другие объекты ядра) от посторонних глаз, через удаление их из списков ОС( PsActiveProcessLinks/SessionProcessLinks и т.д. ).

Но так получилось, что теже самые потоки/процессы удаленные из одних мест, вполне себе продолжали жить в других(как списках, так и модулях).
Яркий пример подобного можно было наблюдать в 2008м, когда EP_X0FF опубликовал детект процессов(CsrWalker) через перечисление их в сервере подсистемы вин32(csrss).

Однако скрыв потоки/процессы и в этом месте нужно не забыть скрыть их и в третьем.
Третье место находится в ядре графической подсистемы - в win32k.sys.

Каким образом в этом списке оказываются процессы и потоки?

При конвертации потока в gui-поток, то есть тогда, когда поток делает свой первый вызов из shadow sdt.

Конвертация осуществляется ф-цией PsConvertToGuiThread, которая создает новый, больший по размеру ядерный стек для потока(для механизма рекурсивных вызовов шадоу сервисов) и налету заменяет его, устанавливает у потока поле ServiceTable, а также вызывает 2 коллаута:

typedef NTSTATUS (*PKWIN32_PROCESS_CALLOUT)( IN PEPROCESS Process, IN BOOLEAN Initialize );
typedef NTSTATUS (*PKWIN32_THREAD_CALLOUT)( IN PETHREAD Thread, IN PSW32THREADCALLOUTTYPE CalloutType );

extern PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout;
extern PKWIN32_THREAD_CALLOUT  PspW32ThreadCallout;

Которые и добавляют потоки в списки win32k.sys.

Что такое коллаут и с чем его едят?

При создании сессии smss.exe загружает ядро графической подсистемы win32k.sys через полудокументированный вызов: 

NtSetSystemInformation( SystemLoadAndCallImage, ... ), который маппит win32k.sys в сессинное пространство и вызывает точку входа драйвера.

А в точке входа вызывается ф-ция:

PsEstablishWin32Callouts( W32pProcessCallout,
                              W32pThreadCallout,
                              UserGlobalAtomTableCallout,
                              UserPowerEventCallout,
                              UserPowerStateCallout,
                              UserJobCallout,
                              (PVOID)NtGdiFlushUserBatch);

Которая инициализирует указатели валидными адресами ф-ций.
То есть коллаут это просто указатель который будет проинициализирован при загрузке win32k.sys.

Таким образом при конвертации потока в гуишный вызовется соответствующие коллауты для потока и процесса.
Внутри которых будут выделены новые entry принадлежащие win32k.sys и представленные структурами PROCESSINFO и THREADINFO.
Данные коллауты также вызываются и при уничтожении потока, чтобы соответственно отлинковаться из списков.

PPROCESSINFO gppiList;     // глобальный список процессов
ULONG gdwGuiThreads;       // счетчик гуишных потоков, апдейтится каждый раз при создании нового гуишного треда

Добравшись до процесса можно получить список его потоков:

typedef struct tagPROCESSINFO
{
    W32PROCESS;
    PTHREADINFO     ptiList;
...
}PROCESSINFO;

Ну и соот-но для любого потока есть указатель на структуру процесса:

typedef struct tagTHREADINFO
{
    W32THREAD;
    PTL             ptl;
    PPROCESSINFO    ppi;
...
}THREADINFO;

Кроме того, в данных структурах много интересной информации, такой как очереди сообщений(input/post), Integrity Level (vista+, т.к. UIPI появилась с висты), инфа о win station и десктопе и т.д.

Таким образом, недостаточно хорошо спрятанный процесс/поток может быть найден через перечисление процессов и их потоков в ядре графической подсистемы.
Ограничение: НЕ-gui потоки не будут найдены.

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

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