首页
社区
课程
招聘
[原创]Delphi研究之驱动开发篇(七)--利用共享内存与用户模式程序通讯
发表于: 2008-6-16 11:33 17949

[原创]Delphi研究之驱动开发篇(七)--利用共享内存与用户模式程序通讯

2008-6-16 11:33
17949

上篇教程我们学习了通过Section在用户进程和内核驱动程序之间共享信息的方法,但是这种方法有一个缺点,就是驱动程序被硬性限制在具体进程的地址上下文中,即驱动程序所使用的虚拟地址位于此进程的地址空间中。我们在本例中使用的方法将没有这个缺点。对于驱动程序来说,这种方法更为自然些。
首先来看看驱动程序。

unit SharingMemory;

interface

uses
  nt_status, ntoskrnl, native, winioctl, fcall, macros;

function _DriverEntry(pDriverObject:PDRIVER_OBJECT; pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;

implementation

uses
  seh;

var
  g_pSharedMemory: PVOID;
  g_pMdl: PVOID;
  g_pUserAddress: PVOID;
  g_fTimerStarted: boolean;
  g_usDeviceName, g_usSymbolicLinkName: UNICODE_STRING;

{更新系统时间到共享内存}
procedure UpdateTime; stdcall;
var
  SysTime:LARGE_INTEGER;
begin
  KeQuerySystemTime(@SysTime);
  ExSystemTimeToLocalTime(@SysTime, g_pSharedMemory);
end;

procedure TimerRoutine(pDeviceObject:PDEVICE_OBJECT; pContext:PVOID); stdcall;
begin
  UpdateTime;
end;

{清理过程--释放资源}
procedure Cleanup(pDeviceObject:PDEVICE_OBJECT); stdcall;
begin
  if g_fTimerStarted then
  begin
    IoStopTimer(pDeviceObject);
    DbgPrint('SharingMemory: Timer stopped'#13#10);
  end;

  if (g_pUserAddress <> nil) and (g_pMdl <> nil) then
  begin
    MmUnmapLockedPages(g_pUserAddress, g_pMdl);
    DbgPrint('SharingMemory: Memory at address %08X unmapped'#13#10,
             g_pUserAddress);
    g_pUserAddress := nil;
  end;

  if g_pMdl <> nil then
  begin
    IoFreeMdl(g_pMdl);
    DbgPrint('SharingMemory: MDL at address %08X freed'#13#10,
             g_pMdl);
    g_pMdl := nil;
  end;

  if g_pSharedMemory <> nil then
  begin
    ExFreePool(g_pSharedMemory);
    DbgPrint('SharingMemory: Memory at address %08X released'#13#10,
             g_pSharedMemory);
    g_pSharedMemory := nil;
  end;
end;

function DispatchCleanup(pDeviceObject:PDEVICE_OBJECT; p_Irp:PIRP): NTSTATUS; stdcall;
begin
  DbgPrint(#13#10'SharingMemory: Entering DispatchCleanup'#13#10);
  Cleanup(pDeviceObject);

  p_Irp^.IoStatus.Status := STATUS_SUCCESS;
  p_Irp^.IoStatus.Information := 0;
  IofCompleteRequest(p_Irp, IO_NO_INCREMENT);

  DbgPrint('SharingMemory: Leaving DispatchCleanup'#13#10);
  result := STATUS_SUCCESS;
end; 

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
  dwContext:DWORD;
  psl:PIO_STACK_LOCATION;
  IOCTL_GIVE_ME_YOUR_MEMORY: DWORD;
  pSystemBuffer: PVOID;
begin
  DbgPrint(#13#10'SharingMemory: Entering DispatchControl'#13#10);
  IOCTL_GIVE_ME_YOUR_MEMORY := CTL_CODE(FILE_DEVICE_UNKNOWN,
                                        $800, METHOD_BUFFERED,
                                        FILE_READ_ACCESS);
  p_Irp^.IoStatus.Status := STATUS_UNSUCCESSFUL;
  p_Irp^.IoStatus.Information := 0;
  psl := IoGetCurrentIrpStackLocation(p_Irp); {取IRP的stack location的指针}
  if psl^.Parameters.DeviceIoControl.IoControlCode = IOCTL_GIVE_ME_YOUR_MEMORY then
  begin
    {是我们控制码就开始处理}
    if psl^.Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PVOID) then
    begin
      g_pSharedMemory := ExAllocatePool(NonPagedPool, PAGE_SIZE);
      if g_pSharedMemory <> nil then
      begin
        DbgPrint('SharingMemory: %X bytes of nonpaged memory allocated at address %08X'#13#10,
                 PAGE_SIZE, g_pSharedMemory);
        g_pMdl := IoAllocateMdl(g_pSharedMemory, PAGE_SIZE,
                                false, false, nil);
        if g_pMdl <> nil then
        begin
          DbgPrint('SharingMemory: MDL allocated at address %08X'#13#10,
                   g_pMdl);
          MmBuildMdlForNonPagedPool(g_pMdl);
          {安装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;
          g_pUserAddress := MmMapLockedPagesSpecifyCache(g_pMdl,
            UserMode, MmCached, nil, 0, NormalPagePriority);
          if g_pUserAddress <> nil then
          begin
            DbgPrint('SharingMemory: Memory mapped into user space at address %08X'#13#10,
                     g_pUserAddress);
            pSystemBuffer := p_Irp^.AssociatedIrp.SystemBuffer;
            PVOID(pSystemBuffer^) := g_pUserAddress;
            UpdateTime;
            if IoInitializeTimer(p_DeviceObject, @TimerRoutine,
                                 @dwContext) = STATUS_SUCCESS then
            begin
              IoStartTimer(p_DeviceObject);
              g_fTimerStarted := true;
              DbgPrint('SharingMemory: Timer started');
              p_Irp^.IoStatus.Information := sizeof(PVOID);
              p_Irp^.IoStatus.Status := STATUS_SUCCESS;
            end;
          end;
SafePlace:  {发生异常安全退出的地方}
          asm
            pop fs:[0]
            add esp, 4
          end;
        end;
      end;
    end else
    begin
      p_Irp^.IoStatus.Status := STATUS_BUFFER_TOO_SMALL;
    end;
  end else
  begin
    p_Irp^.IoStatus.Status := STATUS_INVALID_DEVICE_REQUEST;
  end;
  if p_Irp^.IoStatus.Status <> STATUS_SUCCESS then
  begin
    DbgPrint('SharingMemory: Something went wrong:'#13#10);
    Cleanup(p_DeviceObject);
  end;
  IofCompleteRequest(p_Irp, IO_NO_INCREMENT);
  DbgPrint('SharingMemory: Leaving DispatchControl'#13#10); 
  result := p_Irp^.IoStatus.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;
  g_pSharedMemory := nil;
  g_pMdl := nil;
  g_pUserAddress := nil;
  g_fTimerStarted := false;

  RtlInitUnicodeString(g_usDeviceName, '\Device\SharingMemory');
  RtlInitUnicodeString(g_usSymbolicLinkName, '\DosDevices\SharingMemory');
  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_CLEANUP] := @DispatchCleanup;
      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.
pDriverObject^.MajorFunction[IRP_MJ_CREATE] := @DispatchCreateClose;
pDriverObject^.MajorFunction[IRP_MJ_CLEANUP] := @DispatchCleanup;
pDriverObject^.MajorFunction[IRP_MJ_CLOSE] := @DispatchCreateClose;
pDriverObject^.MajorFunction[IRP_MJ_DEVICE_CONTROL] := @DispatchControl;
pDriverObject^.DriverUnload := @DriverUnload;
g_pSharedMemory := ExAllocatePool(NonPagedPool, PAGE_SIZE);
if g_pSharedMemory <> nil then
begin
PMDL = ^TMDL;
TMDL=packed record
    Next: PMDL;
    Size: CSHORT;
    MdlFlags: CSHORT;
    Process: PEPROCESS;
    MappedSystemVa: PVOID;
    StartVa: PVOID;
    ByteCount: ULONG;
    ByteOffset: ULONG;
end;
g_pMdl := IoAllocateMdl(g_pSharedMemory, PAGE_SIZE,
                     false, false, nil);
MmBuildMdlForNonPagedPool(g_pMdl);
g_pUserAddress := MmMapLockedPagesSpecifyCache(g_pMdl,
            UserMode, MmCached, nil, 0, NormalPagePriority);
if g_pUserAddress <> nil then
begin
  DbgPrint('SharingMemory: Memory mapped into user space at address %08X'#13#10,
                     g_pUserAddress);
  pSystemBuffer := p_Irp^.AssociatedIrp.SystemBuffer;
  PVOID(pSystemBuffer^) := g_pUserAddress;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
2
吼吼,又抢到沙发
2008-6-16 12:15
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
3
我继续坐板凳!
2008-6-16 12:32
0
雪    币: 312
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
看到就要顶!
2008-6-16 22:32
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
5
有个小标题清楚多了
2008-6-17 08:24
0
雪    币: 1004
活跃值: (75)
能力值: ( LV9,RANK:570 )
在线值:
发帖
回帖
粉丝
6
所有的贴子都加上小标题了
2008-6-17 15:43
0
雪    币: 39
活跃值: (2901)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我用以下命令无法启动驱动程序:
sc create sharemem binPath= "C:\windows\system32\sharingmemory.sys"
type= kernel  start= system
2008-8-16 17:26
0
雪    币: 1004
活跃值: (75)
能力值: ( LV9,RANK:570 )
在线值:
发帖
回帖
粉丝
8
这个驱动要用我写的那个客户端程序去加载的,成功后会显示一个数字时钟。
2008-8-16 18:51
0
雪    币: 218
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
老大,我想请教一下:已经有的sys文件是不是用您的那个加载程序,已就是说用API:OpenSCManager、CreateService这两个加载,然后用createfile、DeviceIoControl就可以操作驱动了?
另外:CTL_CODE这个宏我是这样展开的不知道对不:FILE_DEVICE_EXAM=0x00008501
CTL_CODE( FILE_DEVICE_EXAM, 0x02, METHOD_BUFFERED, FILE_ANY_ACCESS )=0x00008501*(2的16次方)+0x02*2*2+0*(2的14次方)=0x85010000+0x08+0=0x85010008?
还有就是我用你的加载程序加加载之后进行卸载,如果想在进行加载就会出现这样的提示:指定的服务已标记为删除!所以只有把sys文件名改了才能在加载,不知道这个又是为什么,如果我想还用以前的名字加载我该怎么办?
2008-8-18 19:31
0
雪    币: 197
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
全部支持,delphi的好东东,希望能出个文件系统过滤的教程
2009-2-14 04:44
0
雪    币: 163
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
一起加油,一起学习……
2010-12-15 15:43
0
雪    币: 441
活跃值: (1060)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
12
说的好多地方有问题
2018-1-26 15:37
0
雪    币: 9
活跃值: (180)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
13
delphi  转成C会更好
2018-1-27 12:22
0
游客
登录 | 注册 方可回帖
返回
//