Показать сообщение отдельно

  #4  
Старый 07.09.2007, 19:40
_Great_
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме:
5339610

Репутация: 4360


Отправить сообщение для _Great_ с помощью ICQ
По умолчанию

Это же очень удобно! Достаточно получить лишь один неэкспортируемый адрес KdDebuggerDataBlock, как все остальные нужные адреса как на ладони.
Поле ValidBlock должно содержать сигнатуру 'GBDK', а Size должно точно равняться sizeof(KD_DEBUGGER_DATA_BLOCK).

Получить адрес KdDebuggerDataBlock можно через экспортируемый символ KeCapturePersistentThreadState, а именно (для версии xp 2600):
KdDebuggerDataBlock = *(PVOID*)((ULONG)KeCapturePersistentThreadState + *(ULONG*)((ULONG)KeCapturePersistentThreadState + 0xC )+ 0x11);

Не очень симпотично, зато что нам это дает! Множество неэкспортируемых адресов внутренних структур. Оно нам потребуется для заполнения хидера дампа.

Ну а теперь, поскольку мы всё знаем, приведу отрывочный код заполнения заглавной страницы дампа:
Код:
BOOLEAN
InitializeDumpHeader(
	IN	PBYTE HeaderPage
	)
{
	PDUMP_HEADER hdr;
	ULONG* blocks;
	PKD_DEBUGGER_DATA_BLOCK KdDebuggerDataBlock;
	EXCEPTION_RECORD exception;
	PVOID KeCapturePersistentThreadState;
	UNICODE_STRING uKeCapturePersistentThreadState;
	PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
	CONTEXT ctx = {CONTEXT_FULL};
	PEXCEPTION_POINTERS pei;
	
	// Get context
	__asm
	{
		// Common registers
        mov [ctx.Eax], eax
		mov [ctx.Ebx], ebx
		mov [ctx.Ecx], ecx
		mov [ctx.Edx], edx
		mov [ctx.Esi], esi
		mov [ctx.Edi], edi

		// Control registers
		mov [ctx.Esp], esp
		mov [ctx.Ebp], ebp

		call _1
		// This address will appear in kd as crash address:
_1:		pop eax
		mov [ctx.Eip], eax

		pushfd
		pop eax
		mov [ctx.EFlags], eax

		// Debug registers
		__emit 0x0F
		__emit 0x21
		__emit 0xC0 ; mov eax, dr0
		mov [ctx.Dr0], eax
		__emit 0x0F
		__emit 0x21
		__emit 0xC8 ; mov eax, dr1
		mov [ctx.Dr1], eax
		__emit 0x0F
		__emit 0x21
		__emit 0xD0 ; mov eax, dr2
		mov [ctx.Dr2], eax
		__emit 0x0F
		__emit 0x21
		__emit 0xD8 ; mov eax, dr3
		mov [ctx.Dr3], eax
		__emit 0x0F
		__emit 0x21
		__emit 0xF0 ; mov eax, dr6
		mov [ctx.Dr6], eax
		__emit 0x0F
		__emit 0x21
		__emit 0xF8 ; mov eax, dr7
		mov [ctx.Dr7], eax

		// Segment registers
		push cs
		pop eax
        mov [ctx.SegCs], eax
		xor eax,eax
		mov ax, ss
		mov [ctx.SegSs], eax
		mov ax, ds
		mov [ctx.SegDs], eax
		mov ax, es
		mov [ctx.SegEs], eax
		mov ax, fs
		mov [ctx.SegFs], eax
		mov ax, gs
		mov [ctx.SegGs], eax
	}

	// Get KeCapturePersistentThreadState address
	RtlInitUnicodeString( &uKeCapturePersistentThreadState, L"KeCapturePersistentThreadState" );
	KeCapturePersistentThreadState = MmGetSystemRoutineAddress( &uKeCapturePersistentThreadState );

	// Initialize dump header
	hdr = (PDUMP_HEADER) HeaderPage;
	hdr->ValidDump = 'PMUD';
	hdr->MinorVersion = (USHORT) *NtBuildNumber;
    hdr->MajorVersion = (USHORT) 0xF; // checked/free, в идеале нужно брать инфу из реестра; если посмотреть код в приложении к статье - там так и сделано
	hdr->DirectoryTableBase = CR3();

	//
	// Capture KdDebuggerDataBlock
	//
	
	__try {
		hdr->KdDebuggerDataBlock = *(PVOID*)((ULONG)KeCapturePersistentThreadState + *(ULONG*)((ULONG)KeCapturePersistentThreadState + 0xC )+ 0x11);

	} __except( (pei=GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER ) {
		ULONG i;

		DbgPrint("An exception occurred while trying to get KdDebuggerDataBlock address:\n");
		DbgPrint("Exception code: 0x%08x\n", pei->ExceptionRecord->ExceptionCode);
		DbgPrint("Number of arguments: 0x%08x\n", pei->ExceptionRecord->NumberParameters);

		for( i = 0; i < pei->ExceptionRecord->NumberParameters; i++ ) {
			DbgPrint("Argument[%d]: 0x%08x\n", i, pei->ExceptionRecord->ExceptionInformation[i]);
		}

		return FALSE;
	}
	hdr->MachineImageType = 0x14c;
	hdr->NumberProcessors = 1;
	hdr->BugCheckCode = KMODE_EXCEPTION_NOT_HANDLED;
	hdr->BugCheckParameter1 = STATUS_BREAKPOINT;
	hdr->BugCheckParameter2 = ctx.Eip;
	hdr->BugCheckParameter3 = 0;
	hdr->BugCheckParameter4 = 0;
	hdr->PaeEnabled = (CR4() & PAE_ENABLED) ? TRUE : FALSE;

	KdDebuggerDataBlock = (PKD_DEBUGGER_DATA_BLOCK) hdr->KdDebuggerDataBlock;

	// Check KdDebuggerDataBlock
	if( KdDebuggerDataBlock->ValidBlock != 'GBDK' || KdDebuggerDataBlock->Size != sizeof(*KdDebuggerDataBlock) )
	{
		// Invalid debugger data block
		DbgPrint(	"KdDebuggerDataBlock is not valid.\nSignature = 0x%08x (should be 0x%08x)\nSize = 0x%08x (should be 0x%08x)\n",
					KdDebuggerDataBlock->ValidBlock, 'GBDK',
					KdDebuggerDataBlock->Size, sizeof(*KdDebuggerDataBlock) );
		return FALSE;
	}

	DbgPrint("Got valid KdDebuggerDataBlock=0x%08x\n", KdDebuggerDataBlock);
	
	hdr->PfnDataBase = (PULONG) KdDebuggerDataBlock->MmPfnDatabase.VirtualAddress;
	hdr->PsLoadedModuleList = (PLIST_ENTRY) KdDebuggerDataBlock->PsLoadedModuleList.VirtualAddress;
	hdr->PsActiveProcessHead = (PLIST_ENTRY) KdDebuggerDataBlock->PsActiveProcessHead.VirtualAddress;

	DbgPrint("PfnDataBase = 0x%08x\n", hdr->PfnDataBase);
	DbgPrint("PsLoadedModuleList = 0x%08x\n", hdr->PsLoadedModuleList);
	DbgPrint("PsActiveProcessHead = 0x%08x\n", hdr->PsActiveProcessHead);

	blocks = (ULONG*)(ULONG_PTR)HeaderPage;

	//
	// Get physical memory descriptor
	//

	MmPhysicalMemoryBlock = *(KdDebuggerDataBlock->MmPhysicalMemoryBlock.VirtualAddress);

	DbgPrint("MmPhysicalMemoryBlock = 0x%08x\n", MmPhysicalMemoryBlock);

	if( MmPhysicalMemoryBlock->NumberOfRuns == 'EGAP' ) {
		RtlCopyMemory(	&blocks[ DH_PHYSICAL_MEMORY_BLOCK ],
						MmPhysicalMemoryBlock, 
						sizeof(PHYSICAL_MEMORY_DESCRIPTOR)
						);
	} else {
		RtlCopyMemory(	&blocks[ DH_PHYSICAL_MEMORY_BLOCK ],
						MmPhysicalMemoryBlock, 
						sizeof(PHYSICAL_MEMORY_DESCRIPTOR) - sizeof(PHYSICAL_MEMORY_RUN) + 
						sizeof(PHYSICAL_MEMORY_RUN)*MmPhysicalMemoryBlock->NumberOfRuns
						);
	}

	//
	// Save context record
	//

	RtlCopyMemory(	&blocks[ DH_CONTEXT_RECORD ],
					&ctx,
					sizeof(CONTEXT)
					);
	DbgPrint("Context record saved.\n");
	DbgPrint("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx);
	DbgPrint("ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", ctx.Esi, ctx.Edi, ctx.Ebp, ctx.Esp);
	DbgPrint("EIP=%08x CS=%08x FS=%08x DS=%08x\n", ctx.Eip, ctx.SegCs, ctx.SegFs, ctx.SegDs);

	//
	// Create & store exception record
	//

	exception.ExceptionCode = STATUS_BREAKPOINT;
	exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
	exception.ExceptionRecord = NULL;
	exception.ExceptionAddress = (PVOID) ctx.Eip;
	exception.NumberParameters = 0;

	RtlCopyMemory(	&blocks[ DH_EXCEPTION_RECORD ],
					&exception,
					sizeof(EXCEPTION_RECORD)
					);

	//
	// Initialize dump type & size
	//

	blocks[ DH_DUMP_TYPE ] = DUMP_TYPE_COMPLETE;

    ((LARGE_INTEGER*)&blocks[DH_REQUIRED_DUMP_SPACE])->QuadPart = ( MmPhysicalMemoryBlock->NumberOfPages << 12 ) + 0x1000;

	DbgPrint("Header page initialized OK\n");

	return TRUE;
}
На этом всё. В приложении к статье можно найти более новую версию gr8lkd, которую я еще никуда не выкладывал, исходники AnalyseCrashDump и исходники gendump драйвера.

http://gr8.cih.ms/uploads/gr8lkd2.rar (81.1 Kb)
http://gr8.cih.ms/uploads/AnalyseCrashDump.rar (11.6 Kb)
http://gr8.cih.ms/uploads/gendump.rar (10.1 Kb)
 
Ответить с цитированием