首页
社区
课程
招聘
[原创]Delphi研究之驱动开发篇(六)--利用Section与用户模式程序通讯
发表于: 2008-6-10 00:45 15955

[原创]Delphi研究之驱动开发篇(六)--利用Section与用户模式程序通讯

2008-6-10 00:45
15955

在进入主题之前,先来简单地看一下结构化异常处理(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);

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
2
呵呵,我坐沙发学习。
2008-6-10 00:53
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
3
楼上的动作好快。
我坐板凳上学习:)
2008-6-10 06:58
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
4
跟着学习。。。
2008-6-10 08:31
0
雪    币: 217
活跃值: (91)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
期待以久...
2008-6-10 14:15
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
这都能让你写出来,学习
2008-6-10 15:02
0
雪    币: 266
活跃值: (60)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
7
做地下室学习了。。支持。。
2008-6-11 12:38
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
驱动的大牛,不错的文章,一直都在看...
也说说驱动方面的免杀吧.
2008-6-11 19:41
0
雪    币: 312
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
终于编通了一个Driver.太牛了,看到新的希望.
2008-6-12 13:52
0
雪    币: 196
活跃值: (35)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
很好的文章,我可以转载吗?
2008-6-21 14:41
0
雪    币: 1004
活跃值: (75)
能力值: ( LV9,RANK:570 )
在线值:
发帖
回帖
粉丝
11
只要注明来自看雪论坛就行。
2008-6-21 20:00
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
Make 时出现 command arguments too long
如何解决啊
2009-12-2 15:21
0
雪    币: 163
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
要坚持学下去。楼主加油
2010-12-15 15:40
0
游客
登录 | 注册 方可回帖
返回
//