在进入主题之前,先来简单地看一下结构化异常处理(Structured Exception Handling, SEH),本篇的程序需要这个东东。
结构化异常处理
这里我并不打算详细讲结构化异常处理,关于SEH,在网上你能找到相关的内容,SHE能用于所有的异常处理,也就是说,SEH既能用于用户模式又能用于内核模式。但这两种模式下的异常处理有一个本质上的差别:
在内核模式下,借助于seh,并非所有的异常都能得到处理!比如说,即使使用了seh,用零作除数作除法也会使系统崩溃。最为可怕的是,引用未定义的内核内存也会导致蓝屏死机BSOD。而对未定义的用户模式内存的引用异常,seh却可以轻松处理。因此避免系统崩溃的唯一办法就是所编写的代码不要导致无法处理的异常。
以下是个使用结构化异常的例子:
unit seh;
interface
uses
nt_status;
function _DriverEntry(pDriverObject:PDRIVER_OBJECT;
pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;
implementation
uses
ntoskrnl;
const
SEH_SafePlaceCounter = 0;
SEH_INSTALLED = 0;
type
_SEH = record
SafeEip: DWORD; { 线程继续执行的地方 }
PrevEsp: DWORD; { 以前esp的值 }
PrevEbp: DWORD; { 以前ebp的值 }
end;
var
sseh: _SEH;
function DefaultExceptionHandler(pExcept:PEXCEPTION_RECORD;
pFrame:DWORD;
pContext:PCONTEXT;
pDispatch:DWORD): DWORD; cdecl;
begin
DbgPrint(#13#10'SEH: An exception %08X has occured'#13#10,
pExcept^.ExceptionCode);
if pExcept^.ExceptionCode = $0C0000005 then
begin
{如果发生了EXCEPTION_ACCESS_VIOLATION类型的异常,}
{则输出以下信息.}
DbgPrint(' Access violation at address: %08X'#13#10,
pExcept^.ExceptionAddress);
if pExcept^.ExceptionInformation[0] <> nil then {试图读还是写?}
begin
DbgPrint(' The code tried to write to address %08X'#13#10#13#10,
DWORD(pExcept^.ExceptionInformation[4]));
end else
begin
DbgPrint(' The code tried to read from address %08X'#13#10#13#10,
DWORD(pExcept^.ExceptionInformation[4]));
end;
end;
asm
lea eax, sseh
push (_SEH PTR [eax]).SafeEip
push (_SEH PTR [eax]).PrevEsp
push (_SEH PTR [eax]).PrevEbp
mov eax, pContext
pop (CONTEXT PTR [eax]).regEbp
pop (CONTEXT PTR [eax]).regEsp
pop (CONTEXT PTR [eax]).regEip
end;
result := 0;
end;
procedure BuggyReader; assembler;
asm
xor eax, eax
mov eax, [eax] {!!! 没有SEH的话 - BSOD !!!}
end;
procedure BuggyWriter; assembler;
asm
mov eax, offset MmUserProbeAddress
mov eax, [eax]
mov eax, [eax]
mov byte ptr [eax], 0 {!!!没有SEH的话 - BSOD !!!}
end;
function _DriverEntry(pDriverObject:PDRIVER_OBJECT;
pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;
label
SafePlace;
begin
DbgPrint(#13#10'SEH: Entering DriverEntry'#13#10);
{ "手工"安装SEH }
asm
push offset DefaultExceptionHandler {我们的SEH程序}
push fs:[0]
mov fs:[0], esp
mov sseh.SafeEip, offset SafePlace {SafePlace是处理完异常后继续执行的地方}
mov sseh.PrevEbp, ebp
mov sseh.PrevEsp, esp
end;
BuggyReader;
BuggyWriter;
SafePlace:
asm
pop fs:[0]
add esp, 4
end;
DbgPrint(#13#10'SEH: Leaving DriverEntry'#10#13);
result := STATUS_DEVICE_CONFIGURATION_ERROR;
end;
end.
asm
push offset DefaultExceptionHandler {我们的SEH程序}
push fs:[0]
mov fs:[0], esp
mov sseh.SafeEip, offset SafePlace {SafePlace是处理完异常后继续执行的地方}
mov sseh.PrevEbp, ebp
mov sseh.PrevEsp, esp
end; procedure BuggyReader; assembler;
asm
xor eax, eax
mov eax, [eax] {!!! 没有SEH的话 - BSOD !!!}
end;
function DefaultExceptionHandler(pExcept:PEXCEPTION_RECORD;
pFrame:DWORD;
pContext:PCONTEXT;
pDispatch:DWORD): DWORD; cdecl;
begin
DbgPrint(#13#10'SEH: An exception %08X has occured'#13#10,
pExcept^.ExceptionCode);
if pExcept^.ExceptionCode = $0C0000005 then
begin
{如果发生了EXCEPTION_ACCESS_VIOLATION类型的异常,}
{则输出以下信息.}
DbgPrint(' Access violation at address: %08X'#13#10,
pExcept^.ExceptionAddress);
if pExcept^.ExceptionInformation[0] <> nil then {试图读还是写?}
begin
DbgPrint(' The code tried to write to address %08X'#13#10#13#10,
DWORD(pExcept^.ExceptionInformation[4]));
end else
begin
DbgPrint(' The code tried to read from address %08X'#13#10#13#10,
DWORD(pExcept^.ExceptionInformation[4]));
end;
end;
asm
lea eax, sseh
push (_SEH PTR [eax]).SafeEip
push (_SEH PTR [eax]).PrevEsp
push (_SEH PTR [eax]).PrevEbp
mov eax, pContext
pop (CONTEXT PTR [eax]).regEbp
pop (CONTEXT PTR [eax]).regEsp
pop (CONTEXT PTR [eax]).regEip
end;
result := 0;
end;
asm
lea eax, sseh
push (_SEH PTR [eax]).SafeEip
push (_SEH PTR [eax]).PrevEsp
push (_SEH PTR [eax]).PrevEbp
mov eax, pContext
pop (CONTEXT PTR [eax]).regEbp
pop (CONTEXT PTR [eax]).regEsp
pop (CONTEXT PTR [eax]).regEip
end;
unit SharedSection;
interface
uses
nt_status, ntoskrnl, native, winioctl, fcall, macros;
function _DriverEntry(pDriverObject:PDRIVER_OBJECT; pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;
implementation
uses
seh;
const
SECTION_SIZE = $1000;
var
g_usDeviceName, g_usSymbolicLinkName, g_usSectionName: UNICODE_STRING;
function DispatchCreateClose(p_DeviceObject:PDEVICE_OBJECT; p_Irp:PIRP): NTSTATUS; stdcall;
begin
p_Irp^.IoStatus.Status := STATUS_SUCCESS;
p_Irp^.IoStatus.Information := 0;
IofCompleteRequest(p_Irp, IO_NO_INCREMENT);
result := STATUS_SUCCESS;
end;
function DispatchControl(p_DeviceObject: PDEVICE_OBJECT; p_Irp:PIRP): NTSTATUS; stdcall;
label
SafePlace;
var
status:NTSTATUS;
IOCTL_SHARE_MY_SECTION: DWORD;
psl:PIO_STACK_LOCATION;
oa:OBJECT_ATTRIBUTES;
hSection:HANDLE;
pSectionBaseAddress:PVOID;
liViewSize:LARGE_INTEGER;
begin
IOCTL_SHARE_MY_SECTION := CTL_CODE(FILE_DEVICE_UNKNOWN, $800, 0, 0);
psl := IoGetCurrentIrpStackLocation(p_Irp); {取IRP的stack location的指针}
if psl^.Parameters.DeviceIoControl.IoControlCode = IOCTL_SHARE_MY_SECTION then
begin
{是我们控制码就开始处理}
DbgPrint('SharedSection: Opening section object'#10#13);
RtlInitUnicodeString(g_usSectionName, '\BaseNamedObjects\UserKernelSharedSection');
InitializeObjectAttributes(oa, @g_usSectionName,
OBJ_CASE_INSENSITIVE, 0, nil);
status := ZwOpenSection(@hSection,
SECTION_MAP_WRITE or SECTION_MAP_READ,
@oa);
if status = STATUS_SUCCESS then
begin
DbgPrint('SharedSection: Section object opened'#13#10);
pSectionBaseAddress := nil;
liViewSize.HighPart := 0;
liViewSize.LowPart := 0;
status := ZwMapViewOfSection(hSection, HANDLE(NtCurrentProcess),
pSectionBaseAddress, 0,
SECTION_SIZE, nil,
@liViewSize, ViewShare, 0,
PAGE_READWRITE);
if status = STATUS_SUCCESS then
begin
DbgPrint('SharedSection: Section mapped at address %08X'#13#10,
pSectionBaseAddress);
{安装SEH}
asm
push offset DefaultExceptionHandler
push fs:[0]
mov fs:[0], esp
mov sseh.SafeEip, offset SafePlace
mov sseh.PrevEbp, ebp
mov sseh.PrevEsp, esp
end;
_strrev(pSectionBaseAddress);
p_Irp^.IoStatus.Status := STATUS_SUCCESS;
DbgPrint('SharedSection: String reversed'#13#10);
SafePlace:
asm
pop fs:[0]
add esp, 4
end;
ZwUnmapViewOfSection(HANDLE(NtCurrentProcess), pSectionBaseAddress);
DbgPrint('SharedSection: Section at address %08X unmapped '#13#10,
pSectionBaseAddress);
end else
begin
DbgPrint('SharedSection: Couldn''t map view of section. Status: %08X'#13#10,
status);
end;
ZwClose(hSection);
DbgPrint('SharedSection: Section object handle closed'#13#10);
end else
begin
DbgPrint('SharedSection: Couldn''t open section. Status: %08X'#13#10, status);
end;
end else
begin
status := STATUS_INVALID_DEVICE_REQUEST;
end;
p_Irp^.IoStatus.Status := status;
IofCompleteRequest(p_Irp, IO_NO_INCREMENT);
DbgPrint('SharedSection: Leaving DispatchControl'#13#10);
result := status;
end;
{卸载驱动}
procedure DriverUnload(p_DriverObject:PDRIVER_OBJECT); stdcall;
begin
IoDeleteSymbolicLink(@g_usSymbolicLinkName);
IoDeleteDevice(p_DriverObject^.DeviceObject);
end;
{驱动进入点}
function _DriverEntry(pDriverObject:PDRIVER_OBJECT; pusRegistryPath:PUNICODE_STRING): NTSTATUS;
var
status: NTSTATUS;
pDeviceObject: TDeviceObject;
begin
status := STATUS_DEVICE_CONFIGURATION_ERROR;
RtlInitUnicodeString(g_usDeviceName, '\Device\SharedSection');
RtlInitUnicodeString(g_usSymbolicLinkName, '\DosDevices\SharedSection');
if IoCreateDevice(pDriverObject, 0, @g_usDeviceName,
FILE_DEVICE_UNKNOWN, 0, TRUE,
pDeviceObject) = STATUS_SUCCESS then
begin
if IoCreateSymbolicLink(@g_usSymbolicLinkName,
@g_usDeviceName) = STATUS_SUCCESS then
begin
pDriverObject^.MajorFunction[IRP_MJ_CREATE] := @DispatchCreateClose;
pDriverObject^.MajorFunction[IRP_MJ_CLOSE] := @DispatchCreateClose;
pDriverObject^.MajorFunction[IRP_MJ_DEVICE_CONTROL] := @DispatchControl;
pDriverObject^.DriverUnload := @DriverUnload;
status := STATUS_SUCCESS;
end else
begin
IoDeleteDevice(@pDeviceObject);
end;
end;
result := status;
end;
end.
InitializeObjectAttributes(oa, @g_usSectionName,
OBJ_CASE_INSENSITIVE, 0, nil);
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: