Я пишу драйвер, который читает память модулей режима ядра. В него входит функция: Код (Text): bool SafeRead(void* Dest, const void* Src, size_t Count) { bool bOk = true; __try { DbgPrint("Reading 0x%X-0x%X\n", Src, ((PBYTE)Src) + Count - 1); RtlCopyMemory(Dest, Src, Count); } __except(EXCEPTION_EXECUTE_HANDLER) { bOk = false; } return bOk; } Когда читаю этой функцией секцию INIT (которая discardable), при копировании возникает исключение PAGE_FAULT_IN_NONPAGED_AREA, которое почему-то приводит к BSOD, вместо того, чтобы передать управление обработчику. При этом вещи вроде чтения нулевого указателя она обрабатывает корректно (заходит в обработчик). В программе используются C++ исключения (громко сказано, просто добавлен заглушечный Код (Text): extern "C" EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler ( _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame, _CONTEXT *ContextRecord, void * DispatcherContext ) { KeBugCheckEx(0xCCEC, 0, 0, 0, 0); return ExceptionContinueSearch; } чтобы STL компилировалось).
Перехватывай исключения на уровне прерываний - (перепеши IDT). А то все эти FS:0, не серьезные какието.. BSOD by PAGE_FAULT_IN_NONPAGED_AREA разве это ни очем не говорит? А так делаешь CLI переписываешь IDT, и вперед.. Если Int сработал - значит не повезло... Востанавливаеш его обратно и выходишь.
А если так: Код (Text): bool SafeRead(void* Dest, const void* Src, size_t Count){ bool bOk; __try { DbgPrint("Reading 0x%X-0x%X\n", Src, ((PBYTE)Src) + Count - 1); char probe = *((PCHAR*)Src); probe = *((PCHAR*)Src + Count - 1); } __except(EXCEPTION_EXECUTE_HANDLER) return false; RtlCopyMemory(Dest, Src, Count); return true; }
Да и еще вот - раз такая тема как память сканировать... В GDT энтяры наверно есть место для прописки своих дескрипторов? Там можно установить 4Гб нелимит и чтоб без пэйджа и чтоб адреса совпадали с физическим, чтобы тем самым сканировать адреса начиная с 0?
cresta, спасибо, MmIsAddressValid - скорее всего, то, что нужно (вернусь домой - перепроверю, но в этой статье тоже пишут о необходимости его вызова).
SEH-и в kernel-mode ненадежны вот такой сработает: __try { PULONG ptr = NULL; ULONG bad = *ptr; } __except(EXCEPTION_EXECUTE_HANDLER) { } а такой - нет. будет синька __try { PULONG ptr = NULL-1; ULONG bad = *ptr; } __except(EXCEPTION_EXECUTE_HANDLER) { } надо сразу писАть так чтоб не падало ну почти никогда
Ерунда ваша заливная рыба! Вот так поэкстремальней будет... Код (Text): {$apptype console} program CpuClk; uses windows; procedure printf(a:pchar;b:integer);cdecl;external 'crtdll.dll' name 'printf'; type IDT_descriptor = packed record case integer of 1:(offset_15_0 : word; selector : word; reserved : byte; attrib : byte; offset_31_16 : word;); 2:(int64 : int64) end; interrupt = array [0..255] of IDT_descriptor; var hDrv, b, TimerHi, TimerLo : DWORD; idt: packed record leng:word; (* union *) case integer of 1:( base:integer); 2:( interrupt:^interrupt ); end; //end; old_vect : array [0..128] of int64; var _esp, int_proc:cardinal; _R_:integer = 0; i : byte; procedure Ring0; label todo; begin //procedure int_dispatch;assembler; //asm //end; //_r_ := 255; //exit; asm mov eax, offset @00 mov int_proc, eax jmp @@start @00: mov al, 00h; jmp @@exit;{Divide Error} @01: mov al, 01h; jmp @@exit;{Debug Exception} @02: mov al, 02h; jmp @@exit;{NMI Interrupt} @03: mov al, 03h; jmp @@exit;{Breakpoint} @04: mov al, 04h; jmp @@exit;{INTO-detected Overflow} @05: mov al, 05h; jmp @@exit;{BOUND Range Exceeded} @06: mov al, 06h; jmp @@exit;{Invalid Opcode} @07: mov al, 07h; jmp @@exit;{Device Not Available} @08: mov al, 08h; jmp @@exit;{Double Fault} @09: mov al, 09h; jmp @@exit;{CoProcessor Segment Overrun (reserved)} @10: mov al, 0Ah; jmp @@exit;{Invalid Task State Segment} @11: mov al, 0Bh; jmp @@exit;{Segment Not Present} @12: mov al, 0Ch; jmp @@exit;{Stack Fault} @13: mov al, 0Dh; jmp @@exit;{General Protection} @14: mov al, 0Eh; jmp @@exit;{Page Fault} @15: mov al, 0Fh; jmp @@exit;{Intel reserved. Do not use} @16: mov al, 10h; jmp @@exit;{Floating-Point Error} @17: mov al, 11h; jmp @@exit;{Alignment Check} @18: mov al, 12h; jmp @@exit;{Machine Check*} @19: mov al, 13h; jmp @@exit; @@exit: mov _R_ , eax mov esp, _esp jmp todo @@start: end; //Вырубить прерывания, считать указатель IDT asm cli; sidt[idt] end; //exit; //Сохранить вектора исключительных прерываний for i:=0 to 32 do old_vect[i] := idt.interrupt[i].int64; //Переустановить IDT for i := 0 to 19 do begin idt.interrupt[i].offset_15_0 := int_proc; idt.interrupt[i].offset_31_16 := int_proc shr 16; idt.interrupt[i].selector := 8; idt.interrupt[i].attrib := $8E {dpl0, interrupt_gate_type}; int_proc := int_proc + 4; end; // asm mov _esp, esp; db 90h,90h,90h,90h end; //сделать падже фаулт asm xor eax, eax; mov eax, cs:[eax] end; todo://восстановить всю хрень for i:=0 to 32 do idt.interrupt[i].int64 := old_vect[i]; //и выйти end; begin hDrv := CreateFileA ('\\.\\MicroDrv', $80000000, 0, nil, 3, $80, 0); DeviceIoControl ( hDrv, 0, @Ring0, 4, @Ring0, 0, b, nil); printf ('%X ', _R_);//TimerLo); CloseHandle (hdrv); end.