KeCapturePersistentThreadState() и crash dump’ы
Я тут обнаружил очень занятную недокументированную функцию, экспортируемую ядром, на которую нет ссылок внутри ядра, но которая делает весьма занятную вещь. А именно, записывает в переданный кусок памяти полноценный minidump на данный момент времени. Весьма полезно с учетом того, что там (в дампе) есть оффсеты неэкспортируемых структур типа PsLoadedModuleList, которые могут пригодиться. Спасибо [b]Freeman[/b] за помощь)
Прототип:
ULONG
NTAPI
KeCapturePersistentThreadState(
PCONTEXT Context,
PKTHREAD Thread,
ULONG BugCheckCode,
ULONG BugCheckParameter1,
ULONG BugCheckParameter2,
ULONG BugCheckParameter3,
ULONG BugCheckParameter4,
PVOID VirtualAddress
);
Входные параметры:
- Context — текущий контекст (можно от балды, нужно лишь заполнить EIP & ESP)
- Thread — текущий поток. можно указать NULL, тогда она сама возьмет текущий
- BugCheckCode, ParametersX — багчек код и аргументы, которые она запишет в дамп.
- VirtualAddress — адрес выделенных 16 страниц памяти (64кб), куда она положит аккуратно готовенький крешдамп.
Пример:
Заголовок дампа:
typedef struct _DUMP_HEADER { /* 00 */ ULONG Signature; /* 04 */ ULONG ValidDump; /* 08 */ ULONG MajorVersion; /* 0c */ ULONG MinorVersion; /* 10 */ ULONG DirectoryTableBase; /* 14 */ PULONG PfnDataBase; /* 18 */ PLIST_ENTRY PsLoadedModuleList; /* 1c */ PLIST_ENTRY PsActiveProcessHead; /* 20 */ ULONG MachineImageType; /* 24 */ ULONG NumberProcessors; /* 28 */ ULONG BugCheckCode; /* 2c */ ULONG BugCheckParameter1; /* 30 */ ULONG BugCheckParameter2; /* 34 */ ULONG BugCheckParameter3; /* 38 */ ULONG BugCheckParameter4; /* 3c */ CHAR VersionUser[32]; /* 5c */ UCHAR PaeEnabled; UCHAR NotUsed[3]; /* 60 */ PVOID KdDebuggerDataBlock; } DUMP_HEADER, *PDUMP_HEADER;
Использование функции:
PVOID Dump; PMDL Mdl; PHYSICAL_ADDRESS LowPhysAddr = {0}, HighPhysAddr = {-1}, SkipBytes = {PAGE_SIZE}; Mdl = MmAllocatePagesForMdl( LowPhysAddr, HighPhysAddr, SkipBytes, 0x10000 ); if( Mdl ) { KdPrint(("Mdl created at %08x\n", Mdl)); Dump = MmMapLockedPagesSpecifyCache( Mdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority ); if( Dump ) { KdPrint(("Mapped at %08x\n", Dump)); CONTEXT ctx = {0}; __asm { call _1 _1: pop [ctx.Eip] mov [ctx.Esp], esp } ULONG Result = KeCapturePersistentThreadState( &ctx;, KeGetCurrentThread(), MANUALLY_INITIATED_CRASH, 0, 0, 0, 0, Dump ); KdPrint(("KeCapturePersistentThreadState = %08x\n", Result)); PDUMP_HEADER DumpHdr = (PDUMP_HEADER) Dump; KdPrint(("MmPfnDatabase = %08x\n", DumpHdr->PfnDataBase)); KdPrint(("PsLoadedModuleList = %08x\n", DumpHdr->PsLoadedModuleList)); KdPrint(("PsActiveProcessHead = %08x\n", DumpHdr->PsActiveProcessHead)); HANDLE hFile; IO_STATUS_BLOCK IoStatus; OBJECT_ATTRIBUTES oa; UNICODE_STRING FileName; NTSTATUS Status; RtlInitUnicodeString( &FileName;, L"\\??\\C:\\dumpfile.dmp" ); InitializeObjectAttributes( &oa;, &FileName;, OBJ_KERNEL_HANDLE, 0, 0 ); Status = ZwCreateFile( &hFile;, GENERIC_WRITE | SYNCHRONIZE, &oa;, &IoStatus;, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_WRITE_THROUGH, NULL, 0 ); if( NT_SUCCESS(Status) ) { KdPrint(("File handle = %08x\n", hFile)); Status = ZwWriteFile( hFile, NULL, NULL, NULL, &IoStatus;, Dump, 0x10000, NULL, NULL ); if( NT_SUCCESS(Status) ) { KdPrint(("%08x bytes written ok\n", IoStatus.Information)); } else { KdPrint(("ZwWriteFile(): Status = %08x\n", Status)); } ZwClose( hFile ); } else { KdPrint(("ZwCreateFile(): Status = %08x\n", Status)); } MmUnmapLockedPages( Dump, Mdl ); } MmFreePagesFromMdl( Mdl ); ExFreePool( Mdl ); }
Кодес получает дамп, показывает адерса MmPfnDatabase, PsActiveProcessHead, PsLoadedModuleList и сбрасывает дамп на диск. Дамп можно спокойно запихать в WinDbg и изучать
Вообщем, весьма занятная штуковина…
[C] Great
Источник WASM.RU /23.11.2008/