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/


Поделиться в соц сетях

Подписаться
Уведомить о
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Есть идеи, замечания, предложения? Воспользуйтесь формой Обратная связь или отправьте сообщение по адресу replay@sciencestory.ru
© 2017 Истории науки. Информация на сайте опубликована в ознакомительных целях может иметь ограничение 18+