• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Windows Data Structures and Callbacks, Part 1

atavism

HalReturnToBorderline
Premium
Регистрация
03.05.2020
Сообщения
150
Реакции
85
Депозит
0.0016
1610120629921.png

У modexp довольно миленькая картиночка в качестве хидера, почему бы её здесь не использовать?


Windows Data Structures and Callbacks, Part 1


Содержание:

1. Вступление
2. Function Table List
3. Event Tracing
4. DLL Notifications
5. Secure Memory
6. Configuration Manager (CM)
7. Vectored Exception Handling (VEH)
8. Windows Error Reporting (WER)
8.1 PEB Header Block​
8.2 Recovery Information​
8.3 Gathers​
8.4 Custom Meta Data​
8.5 Runtime DLL​
8.6 Dump Collections​
8.7 Heap Main Header​

Автор: modexp
Переводчик: Vism

1. Вступление

Процесс может содержать тысячи указателей на исполняемый код, некоторые из них хранятся в "неясных", но "записываемых" структурах, известных лишь только Microsoft, некоторым сторонним компаниям и плохишам, которые хотят спрятать свой вредоносный код от сканеров памяти. Этот пост существует для документирования содержания некоторых структур, а не PoC для демонстрации методов перенаправления и сокрытия кода, о которых, скорее всего, оригинальный автор больше не будет рассказывать. Некоторые названия полей в представленных структурах не совсем точные, но вы можете написать оригинальному автору, если считаете, что нужно что-то исправить. Структуры могут быть найдены на MSDN или получены путем реверса.


2. Dynamic Function Table List

ntdll!RtlpDynamicFunctionTable содержит DYNAMIC_FUNCTION_TABLE записи и callback-функции для сегмента памяти, который может быть установлен с помощью ntdll!RtlInstallFunctionTableCallback. ntdll!RtlGetFunctionTableListHead возвращает указатель на список (PLIST_ENTRY), а поскольку NTDLL.dll использует один и тот же BA (Base Address) для каждого процесса, то вы с легкостью сможете читать записи из удаленного процесса.

C:
typedef enum _FUNCTION_TABLE_TYPE {
    RF_SORTED,
    RF_UNSORTED,
    RF_CALLBACK
} FUNCTION_TABLE_TYPE;

typedef PRUNTIME_FUNCTION (CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK)
  (ULONG_PTR ControlPc, PVOID Context);
   
typedef struct _DYNAMIC_FUNCTION_TABLE {
    LIST_ENTRY                      Links;
    DWORD64                         TableIdentifier;
    LARGE_INTEGER                   TimeStamp;
    DWORD64                         MinimumAddress;
    DWORD64                         MaximumAddress;
    PVOID                           BaseAddress;
    PGET_RUNTIME_FUNCTION_CALLBACK  Callback;
    PCWSTR                          OutOfProcessCallbackDll;
    FUNCTION_TABLE_TYPE             Type;
    ULONG                           EntryCount;
    ULONG64                         UnknownStruct[3];  // referenced by RtlAvlInsertNodeEx        
} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;

3. Event Tracing

Microsoft рекомендует не использовать это, но sechost!SetTraceCallback все еще может получать ETW-события. Записи по типу EVENT_CALLBACK_ENTRY находятся в sechost!EtwpEventCallbackList.

C:
typedef VOID (CALLBACK PEVENT_CALLBACK)(PEVENT_TRACE pEvent);

ULONG WMIAPI SetTraceCallback(
    LPCGUID         pGuid,
    PEVENT_CALLBACK EventCallback);

typedef struct _EVENT_CALLBACK_ENTRY {
    LIST_ENTRY      ListHead;
    GUID            ProviderId;
    PEVENT_CALLBACK Callback;
} EVENT_CALLBACK_ENTRY, *PEVENT_CALLBACK_ENTRY;

4. DLL Notifications

Можно получить уведомление о том, что DLL загружена или выгружена с помощью ntdll!LdrRegisterDllNotification. Используется для подключения API для CLR в ClrGuard. Записи по типу LDR_DLL_NOTIFICATION_ENTRY могут быть найдены в ntdll!LdrpDllNotificationList.

C:
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA {
    ULONG           Flags;             // Reserved.
    PUNICODE_STRING FullDllName;       // The full path name of the DLL module.
    PUNICODE_STRING BaseDllName;       // The base file name of the DLL module.
    PVOID           DllBase;           // A pointer to the base address for the DLL in memory.
    ULONG           SizeOfImage;       // The size of the DLL image, in bytes.
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;

typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA {
    ULONG           Flags;             // Reserved.
    PUNICODE_STRING FullDllName;       // The full path name of the DLL module.
    PUNICODE_STRING BaseDllName;       // The base file name of the DLL module.
    PVOID           DllBase;           // A pointer to the base address for the DLL in memory.
    ULONG           SizeOfImage;       // The size of the DLL image, in bytes.
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;

typedef VOID (CALLBACK *PLDR_DLL_NOTIFICATION_FUNCTION)(
    ULONG                       NotificationReason,
    PLDR_DLL_NOTIFICATION_DATA  NotificationData,
    PVOID                       Context);
   
typedef union _LDR_DLL_NOTIFICATION_DATA {
    LDR_DLL_LOADED_NOTIFICATION_DATA   Loaded;
    LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;

typedef struct _LDR_DLL_NOTIFICATION_ENTRY {
    LIST_ENTRY                     List;
    PLDR_DLL_NOTIFICATION_FUNCTION Callback;
    PVOID                          Context;
} LDR_DLL_NOTIFICATION_ENTRY, *PLDR_DLL_NOTIFICATION_ENTRY;

typedef NTSTATUS(NTAPI *_LdrRegisterDllNotification) (
    ULONG                          Flags,
    PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
    PVOID                          Context,
    PVOID                          *Cookie);
   
typedef NTSTATUS(NTAPI *_LdrUnregisterDllNotification)(PVOID Cookie);


5. Secure Memory

Ring-0 драйверы могут "обезопасить" пользовательскую память используя ntoskrnl!MmSecureVirtualMemory. Это может предотвратить освобождение памяти или "усиление" защиты страницы, т.е PAGE_NOACCESS. Для мониторинга изменений разработчики могут использовать AddSecureMemoryCacheCallback. Записи по типу RTL_SEC_MEM_ENTRY находятся в ntdll!RtlpSecMemListHead.

C:
typedef BOOLEAN (CALLBACK *PSECURE_MEMORY_CACHE_CALLBACK)(PVOID, SIZE_T);

typedef struct _RTL_SEC_MEM_ENTRY {
    LIST_ENTRY                    Links;
    ULONG                         Revision;
    ULONG                         Reserved;
    PSECURE_MEMORY_CACHE_CALLBACK Callback;
} RTL_SEC_MEM_ENTRY, *PRTL_SEC_MEM_ENTRY;

6. Configuration Manager (CM)

Процесс может регистрировать события типа Plug & Play при помощи cfgmgr32!CM_Register_Notification. Microsoft рекомендует в старых системах (до Windows 7) использовать RegisterDeviceNotification, но автор статьи не рассматривал эту функцию. Записи уведомлений по типу _HCMNOTIFICATION находятся в cfgmgr32!EventSystemClientList. _CM_CALLBACK_INFO - структура, которая может быть отправлена в \Device\DeviceApi\CMNotify, когда процесс регистрирует callback. Как видно из поля WnfSubscription, он использует Windows Notification Facility (WNF), для получения ивентов.

C:
typedef DWORD (CALLBACK *PCM_NOTIFY_CALLBACK)(
    _In_     HCMNOTIFICATION       hNotify,
    _In_opt_ PVOID                 Context,
    _In_     CM_NOTIFY_ACTION      Action,
    _In_     PCM_NOTIFY_EVENT_DATA EventData,
    _In_     DWORD                 EventDataSize);
   
typedef struct _CM_CALLBACK_INFO {
    WCHAR              ModulePath[MAX_PATH];
    CM_NOTIFY_FILTER   EventFilter;
};

typedef struct _tagHCMNOTIFICATION {
    USHORT                  Signature;             // 0xF097
    SRWLOCK                 SharedLock;
    CONDITION_VARIABLE      ConditionVar;
    LIST_ENTRY              EventSystemClientList;
    LIST_ENTRY              EventSystemPendingClients;
    BOOL                    Active;
    BOOL                    InProgress;
    CM_NOTIFY_FILTER        EventFilter;
    PCM_NOTIFY_CALLBACK     Callback;
    PVOID                   Context;
    HANDLE                  NotifyFile;    // handle for \Device\DeviceApi\CMNotify
    PWNF_USER_SUBSCRIPTION  WnfSubscription;
    LIST_ENTRY              Links;
} _HCMNOTIFICATION, *_PHCMNOTIFICATION;

7. Vectored Exception Handling (VEH)

Когда выполняется kernelbase!KernelBaseBaseDllInitialize, он устанавливет обработчик исключений (англ. exception handler) kernelbase!UnhandledExceptionFilter через SetUnhandledExceptionFilter. Однако, если после этого не был установлен VEH, то этот обработчик будет выполняется на "верхнем уровне" для любых возникающих неисправностей. VEH callback'и, установленные при помощи AddVectoredExceptionHandler или AddVectoredContinueHandler находятся в ntdll!LdrpVectorHandlerList.

C:
// vectored handler list
typedef struct _RTL_VECTORED_HANDLER_LIST {
    SRWLOCK                    Lock;
    LIST_ENTRY                  List;
} RTL_VECTORED_HANDLER_LIST, *PRTL_VECTORED_HANDLER_LIST;

// exception handler entry
typedef struct _RTL_VECTORED_EXCEPTION_ENTRY {
    LIST_ENTRY                  List;
    PULONG_PTR                  Flag;           // some flag related to CFG
    ULONG                       RefCount;
    PVECTORED_EXCEPTION_HANDLER VectoredHandler;
} RTL_VECTORED_EXCEPTION_ENTRY, *PRTL_VECTORED_EXCEPTION_ENTRY;

8. Windows Error Reporting (WER)

Windows предоставляет API для восстановления приложений, дампа памяти приложения и генерации отчетов через WER-службу. Настройки WER для процесса могут находиться в Process Environment Block (PEB) в WerRegistrationData.

8.1 PEB Header Block

Автор статьи обсудит структуры отдельно, но только те, которые не являются таковыми. Signature (поле структуры) устанавливается внутри kernelbase!WerpInitPEBStore и содержит строку "PEB_SIGNATURE". AppDataRelativePath задается при помощи WerRegisterAppLocalDump. kernelbase!RegisterApplicationRestart может быть использован для установки RestartCommandLine, который используется в качестве командной строки, когда процесс должен быть... перезапущен.

C:
typedef struct _WER_PEB_HEADER_BLOCK {
    LONG                 Length;
    WCHAR                Signature[16];
    WCHAR                AppDataRelativePath[64];
    WCHAR                RestartCommandLine[RESTART_MAX_CMD_LINE];
    WER_RECOVERY_INFO    RecoveryInfo;
    PWER_GATHER          Gather;
    PWER_METADATA        MetaData;
    PWER_RUNTIME_DLL     RuntimeDll;
    PWER_DUMP_COLLECTION DumpCollection;
    LONG                 GatherCount;
    LONG                 MetaDataCount;
    LONG                 DumpCount;
    LONG                 Flags;
    WER_HEAP_MAIN_HEADER MainHeader;
    PVOID                Reserved;
} WER_PEB_HEADER_BLOCK, *PWER_PEB_HEADER_BLOCK;

8.2 Recovery Information

Callback восстановления может быть установлен с помощью kernel32!RegisterApplicationRecoveryCallback. kernelbase!GetApplicationRecoveryCallback прочтет поля Callback, Parameter, PingInterval и Flags из удаленного процесса. kernel32!ApplicationRecoveryFinished может быть "читать", если ивент Finished просигнализировал о том, что он завершен. ApplicationRecoveryInProgress постарается определить, сигнализирует ли ивент InProgress. Started - хэндл, но автор не уверен, для чего он.

C:
typedef struct _WER_RECOVERY_INFO {
    ULONG                Length;
    PVOID                Callback;
    PVOID                Parameter;
    HANDLE               Started;
    HANDLE               Finished;
    HANDLE               InProgress;
    LONG                 LastError;
    BOOL                 Successful;
    DWORD                PingInterval;
    DWORD                Flags;
} WER_RECOVERY_INFO, *PWER_RECOVERY_INFO;

8.3 Gathers

Как некоторая часть отчета, созданного WER, kernelbase!WerRegisterMemoryBlock предоставляет информацию о сегменте памяти, который должна быть включен в отчет. Можно также исключить сегмент памяти используя kernelbase!WerRegisterExcludedMemoryBlock, который устанавливает 15 бит в поле Flags в структуре WER_GATHER. Файлы, которые могли бы быть исключены из отчета, можно сохранить через kernelbase!WerRegisterFile.

C:
typedef struct _WER_FILE {
    USHORT               Flags;
    WCHAR                Path[MAX_PATH];
} WER_FILE, *PWER_FILE;

typedef struct _WER_MEMORY {
    PVOID                Address;
    ULONG                Size;
} WER_MEMORY, *PWER_MEMORY;

typedef struct _WER_GATHER {
    PVOID                Next;
    USHORT               Flags;  
    union {
      WER_FILE           File;
      WER_MEMORY         Memory;
    } v;
} WER_GATHER, *PWER_GATHER;

8.4 Custom Meta Data

Приложения могут регистрировать пользовательские мета-данные используя kernelbase!WerRegisterCustomMetadata.

C:
typedef struct _WER_METADATA {
    PVOID                Next;
    WCHAR                Key[64];
    WCHAR                Value[128];
} WER_METADATA, *PWER_METADATA;

8.5 Runtime DLL

Разработчики могут настраивать процесс создания отчетов, для чего предназначен kernelbase!WerRegisterRuntimeExceptionModule. Он вставляет путь до DLL в данные (регистрационные), которые загружаются через werfault.exe при возникновении исключений. В структуре WER_RUNTIME_DLL, MAX_PATH используется для CallbackDllPath, но корректная длина для структуры и DLL должна быть прочитана из поля Length.

C:
typedef struct _WER_RUNTIME_DLL {
    PVOID                Next;
    ULONG                Length;
    PVOID                Context;
    WCHAR                CallbackDllPath[MAX_PATH];
} WER_RUNTIME_DLL, *PWER_RUNTIME_DLL;

8.6 Dump Collections

Если требуется более одного процесса для дампа, то приложение может использовать kernelbase!WerRegisterAdditionalProcess для указания идентификаторов процессов и потоков. Автор не против, если вы его поправите, но похоже, что API разрешает только один поток на процесс.

C:
typedef struct _WER_DUMP_COLLECTION {
    PVOID                Next;
    DWORD                ProcessId;  
    DWORD                ThreadId;
} WER_DUMP_COLLECTION, *PWER_DUMP_COLLECTION;

8.7 Heap Main Header

Наконец, главный заголовок кучи, используемый для динамической аллокации памяти для WER-структур. Поле Signature должно содержать строку "HEAP_SIGNATURE". Mutex здесь просто для "уникального" доступа во время аллокации. Определение FreeHeap в этой структуре может быть не точным, но, похоже, оно используется для улучшения производительности аллокации. Вместо того, чтоб запрашивать каждый раз у ОС новый блок памяти, WER-функции могут по возможности использовать этот блок.

C:
typedef struct _WER_HEAP_MAIN_HEADER {
    WCHAR                Signature[16];
    LIST_ENTRY           Links;
    HANDLE               Mutex;
    PVOID                FreeHeap;
    ULONG                FreeCount;
} WER_HEAP_MAIN_HEADER, *PWER_HEAP_MAIN_HEADER;

Служба WER может вполне оправданно стать точкой для повышения привелигий. Это можно использовать для кражи конфиденциальной информации путем изменения информации в настройках реестра. Атакующий может быть способен сдампить процесс и отправить отчет на подконтрольный ему сервер с помощью настройки CorporateWERServer. Атакующий также может использовать собственный открытый ключ шифрования этих данных и предотвращения восстановления того, что именно собирается с жертвы. Автор подмечает, что это все конечно чисто гипотетически и не знает можно ли это использовать в таких целях.
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх