|
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме: 5339610
Репутация:
4360
|
|
Это же очень удобно! Достаточно получить лишь один неэкспортируемый адрес 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)
|