最近比较忙,其实也就是瞎忙,今天抽出一点时间来给大家补补驱动的课,呵呵~~如果您已经会了,就直接跳过啦,真没什么技术含量,让大哥们笑话了~~但我想对于一些想进军驱动和刚踏入驱动的朋友们,如果能给大家一点小小的帮助我想就足够了!(小弟,也是刚踏入驱动的大门,有误之处,望各位大哥指出
看到论坛上有人问起驱动与应用层之间通信的问题,今天我给大家讲讲驱动与应用程序之间是怎么通信的吧~~
首先说说为什么大部分的驱动程序都需要与应用层程序之间进行通信,其实原因很简单,就是为了用应用层软件去控制电脑底层~~不过如果某些特殊功能的驱动,比如病毒中的某个驱动程序进行某种隐蔽的操作(病毒或木马之类的),也可以不用与用户通信,因为它的安装就是为了某项工作,完成就行了~~不过我想大部分的驱动都需要与应用程序进行通信吧~~个人观点!

那么怎么样才能使我们的驱动与应用程序之间进行通信呢?
目前比较流行的两种方法是:
第一种:使用WriteFile和ReadFile分别从驱动中读取和写入数据,然后用不同的IRP来传递信息。
第二种:使用DeviceIoControl通信

编程工具:RadASM
编程语言:Win32汇编
使用WriteFile和ReadFile进行通信
首先用RadASM建立一个Driver工程Connection
Connection.asm的代码如下:
.386
.model flat,stdcall
option casemap:none

include D:\RadASM\masm32\include\w2k\ntstatus.inc        ;根据自己的安装路径进行配置
include D:\RadASM\masm32\include\w2k\ntddk.inc
include D:\RadASM\masm32\include\w2k\ntoskrnl.inc

includelib D:\RadASM\masm32\lib\w2k\ntoskrnl.lib

include D:\RadASM\masm32\macros\Strings.mac

include Connection.inc

.const
CCOUNTED_UNICODE_STRING "\\Device\\Connection",g_usDeviceName,4
CCOUNTED_UNICODE_STRING "\\DosDevice\\Connection",g_usSymbolicLinkName,4

.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DispatchCreateClose
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
  
  
  mov eax,pIrp
  assume eax:PTR _IRP
  mov [eax].IoStatus.Status,STATUS_SUCCESS
  and [eax].IoStatus.Information,0
  assume eax:nothing
  
  fastcall IofCompleteRequest,pIrp,IO_NO_INCREMENT
  
  mov eax,STATUS_SUCCESS
  ret

DispatchCreateClose endp



;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DriverUnload
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DriverUnload proc pDriverObject:PDRIVER_OBJECT
  
  ;删除符号符连接
  invoke IoDeleteSymbolicLink,addr g_usSymbolicLinkName
  
  mov eax,pDriverObject
  
  ;删除设备对象
  invoke IoDeleteDevice,(DRIVER_OBJECT PTR[eax]).DeviceObject
  ret

DriverUnload endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DispatchWrite
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DispatchWrite proc uses esi edi pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
  
  LOCAL status:NTSTATUS
  
  mov esi,pIrp
  assume esi:PTR _IRP
  
  IoGetCurrentIrpStackLocation esi
  
  mov edi,eax
  assume edi:PTR IO_STACK_LOCATION
  
  invoke DbgPrint,$CTA0("[Test]%d"),[edi].Parameters.Write._Length
  invoke DbgPrint,$CTA0("[Test]%s"),[esi].AssociatedIrp.SystemBuffer
  
  push status
  pop  [esi].IoStatus.Status
  
  push [edi].Parameters.Write._Length
  pop  [esi].IoStatus.Information
  
  assume edi:nothing
  assume esi:nothing
  
  fastcall IofCompleteRequest,esi,IO_NO_INCREMENT
  
  mov eax,status
  ret

DispatchWrite endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DispatchRead
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DispatchRead proc pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
  
  
  LOCAL status:NTSTATUS
  
  mov esi,pIrp
  assume esi:PTR _IRP
  
  IoGetCurrentIrpStackLocation esi
  
  mov edi,eax
  assume edi:PTR IO_STACK_LOCATION
  
  invoke DbgPrint,$CTA0("[Test]%d"),[edi].Parameters.Read._Length
  invoke DbgPrint,$CTA0("[Test]%s"),[esi].AssociatedIrp.SystemBuffer
  
  push status
  pop  [esi].IoStatus.Status
  
  push [edi].Parameters.Read._Length
  pop  [esi].IoStatus.Information
  
  assume edi:nothing
  assume esi:nothing
  
  fastcall IofCompleteRequest,esi,IO_NO_INCREMENT
  
  mov eax,status
  
  ret

DispatchRead endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DriverEntry
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DriverEntry proc pDriverObject:PDRIVER_OBJECT,pusRegistryPath:PUNICODE_STRING
  
  LOCAL status:NTSTATUS
  LOCAL pDeviceObject:PDEVICE_OBJECT
  
  mov status,STATUS_DEVICE_CONFIGURATION_ERROR
  
  ;创建设备对象
  invoke IoCreateDevice,pDriverObject,0,addr g_usDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,addr pDeviceObject
  
  .if eax == STATUS_SUCCESS
  

    ;创建符号连接
    invoke IoCreateSymbolicLink,addr g_usSymbolicLinkName,addr g_usDeviceName
    .if eax == STATUS_SUCCESS
      mov eax,pDriverObject
      assume eax:PTR DRIVER_OBJECT
      or  [eax].Flags,DO_BUFFERED_IO
      mov [eax].DriverUnload,offset DriverUnload
      mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)],offset DispatchCreateClose
      mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],offset DispatchCreateClose
      mov [eax].MajorFunction[IRP_MJ_WRITE*(sizeof PVOID)],offset DispatchWrite
      mov [eax].MajorFunction[IRP_MJ_READ*(sizeof PVOID)],offset DispatchRead
      assume eax:nothing
      
      mov status,STATUS_SUCCESS
    .else
      invoke IoDeleteDevice,pDeviceObject
    .endif
  .endif
  
  mov eax,status
  ret
DriverEntry endp
end DriverEntry

代码很简单,应用层的例子就不用多说了吧,只需要在应用层代码创建一个文件,然后调用WriteFile和ReadFile进行文件操作,驱动层就会响应应用层的操作进行相关处理,我这里的代码很简单只是输出了缓冲区中的内容,其实可以在其中加入更加复杂的操作,请读者自行研究~~

使用DeviceIoControl进行通信
前面我们使用的方法,使得我们每建行一次操作都要分别调用ReadFile和WriteFile进行操作,很麻烦,在这里我们就用一个比较通用的方法DeviceIoControl函数。
DeviceIoControl函数会使操作系统产生一个IRP_MJ_DEVICE_CONTROL类型的IRP,然后这个IRP会被分发到相应的派遣例程中
先来看看DeviceIoControl函数的原型声明:
BOOL DeviceIoControl(
  HANDLE  hDevice,
  DWORD   dwIoControlCode,           //进行的操作代码
  LPVOID     lpInBuffer,
  DWORD    nInBufferSize,
  LPVOID    lpOutBuffer,
  DWORD    nOutBufferSize,
  LPDWORD  lpBytesReturned,
  LPOVERLAPPED  lpOverlapped
  )
主要看第二个参数,它是一个I/O控制码,即IOCTL值,是一个32位的无符号整型数值。
什么是IOCTL?
IO控制指令(IOCTLs)主要用于用户态应用程序和驱动之间的沟通或者设备栈内驱动之间的沟通,这种指令通过IRP来进行传送。对DeviceIoControl的调用会促使I/O管理器产生一个IRP_MJ_DEVICE_CONTROL请求并且发送给当前设备栈最顶端的驱动程序。另外,上层驱动程序可以通过产生和发送IRP_MJ_DEVICE_CONTROL或者IRP_MJ_INTERNAL_DEVICE_CONTROL请求的方式向下层驱动程序发送IO控制指令。驱动程序在DispatchDeviceControl和DispatchInternalDeviceControl这两个例程中处理这些请求。
首先我们用RadASM建立一个名为DeviceControl的Driver工程
DeviceControl.inc的代码如下:
IOCTL_DEVICEIOCONTROL equ CTL_CODE(FILE_DEVICE_UNKNOWN,800h,METHOD_BUFFERED,FILE_READ_ACCESS + FILE_WRITE_ACCESS)

DeviceControl.asm的代码如下:
.386
.model flat,stdcall
option casemap:none

include D:\RadASM\masm32\include\w2k\ntstatus.inc        ;根据自己的安装路径进行配置
include D:\RadASM\masm32\include\w2k\ntddk.inc
include D:\RadASM\masm32\include\w2k\ntoskrnl.inc

includelib D:\RadASM\masm32\lib\w2k\ntoskrnl.lib

include D:\RadASM\masm32\macros\Strings.mac

include DeviceControl.inc

.const
CCOUNTED_UNICODE_STRING "\\Device\\DeviceControl",g_usDeviceName,4
CCOUNTED_UNICODE_STRING "\\??\\DeviceControl",g_usSymbolicLinkName,4


.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DispatchCreateClose
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
  
  
  mov eax,pIrp
  assume eax:PTR _IRP
  mov [eax].IoStatus.Status,STATUS_SUCCESS
  and [eax].IoStatus.Information,0
  assume eax:nothing
  
  fastcall IofCompleteRequest,pIrp,IO_NO_INCREMENT
  
  mov eax,STATUS_SUCCESS
  ret

DispatchCreateClose endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DispatchControl
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DispatchControl proc pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
  
  LOCAL status:NTSTATUS
  
  mov esi,pIrp
  assume esi:PTR _IRP
  
  IoGetCurrentIrpStackLocation esi
  mov edi,eax
  assume edi:PTR IO_STACK_LOCATION
  
  .if [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_DEVICEIOCONTROL
    invoke DbgPrint,$CTA0("IOCTL_DEVICEIOCONTROL IS CALL")    ;演示之用,请读者自行扩展
  ;.elseif [edi].Parameters.DeviceIoControl.IoControlCode == ....   如果还有其它的请求进行处理
  .else
    mov status,STATUS_INVALID_DEVICE_REQUEST
  .endif
  
  assume edi:nothing
  
  push status
  pop [esi].IoStatus.Status
  
  push 0
  pop [esi].IoStatus.Information
  assume esi:nothing
  
  fastcall IofCompleteRequest,pIrp,IO_NO_INCREMENT
  
  mov eax,status
  ret

DispatchControl endp


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DriverUnload
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DriverUnload proc pDriverObject:PDRIVER_OBJECT
  
  ;删除符号符连接
  invoke IoDeleteSymbolicLink,addr g_usSymbolicLinkName
  
  mov eax,pDriverObject
  
  ;删除设备对象
  invoke IoDeleteDevice,(DRIVER_OBJECT PTR[eax]).DeviceObject
  ret

DriverUnload endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DriverEntry
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
  LOCAL status:NTSTATUS
  LOCAL pDeviceObject:PDEVICE_OBJECT
  
  mov status,STATUS_DEVICE_CONFIGURATION_ERROR
  
  invoke IoCreateDevice,pDriverObject,0,addr g_usDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,addr pDeviceObject
  
  .if eax == STATUS_SUCCESS
    invoke IoCreateSymbolicLink,addr g_usSymbolicLinkName,addr g_usDeviceName
    .if eax == STATUS_SUCCESS
      mov eax,pDriverObject
      assume eax:PTR DRIVER_OBJECT
      mov [eax].DriverUnload,offset DriverUnload
      mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)],offset DispatchCreateClose
      mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],offset DispatchCreateClose
      mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)],offset DispatchControl
      assume eax:nothing
      
      mov status,STATUS_SUCCESS
    .else
      invoke IoDeleteDevice,pDeviceObject
    .endif
  .endif
  
  mov eax,status
  ret

DriverEntry endp
end DriverEntry

好了,代码很简单,我就不多讲了,现在我们来看看应用层的代码吧!
我们用RadASM建立一个应用程序DeviceControlExe
DeviceControlExe.inc的代码如下:
IOCTL_DEVICEIOCONTROL equ CTL_CODE(FILE_DEVICE_UNKNOWN,800h,METHOD_BUFFERED,FILE_READ_ACCESS + FILE_WRITE_ACCESS)

DeviceControlExe.asm的代码如下:
.386
.model flat,stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc
include advapi32.inc

includelib user32.lib
includelib kernel32.lib
includelib advapi32.lib

include D:\RadASM\masm32\include\winioctl.inc       ;当使用IOCTL时必须包含这个头文伯

include D:\RadASM\masm32\macros\Strings.mac

include DeviceControlExe.inc

.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;ControlConnection
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ControlConnection proc uses esi edi
  
  LOCAL hDevice:HANDLE
  LOCAL dwBytesReturned:DWORD
  invoke CreateFile,$CTA0("\\\\.\\DeviceControl"),GENERIC_READ + GENERIC_WRITE,\
    0,NULL,OPEN_EXISTING,0,NULL
    
  .if eax != INVALID_HANDLE_VALUE
    
    mov hDevice,eax
        
    invoke DeviceIoControl,hDevice,IOCTL_DEVICEIOCONTROL,\
       NULL,NULL,NULL,NULL,addr dwBytesReturned,NULL
    .if (eax != 0 ) && (dwBytesReturned == 0)
      invoke MessageBox,NULL,$CTA0("Send Control Code is Success"),$CTA0("Success"),MB_OK
    .else
      invoke MessageBox,NULL,$CTA0("Send Control Code is Failed"),$CTA0("Failed"),MB_OK
    .endif
  .else
    invoke MessageBox,NULL,$CTA0("Device Connection failed"),$CTA0("Failed"),MB_OK + MB_ICONSTOP
  .endif
  
  ret

ControlConnection endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;InstallDriver
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
InstallDriver proc
  
  LOCAL hSCManager:HANDLE
  LOCAL hService:HANDLE
  LOCAL acModulePath[MAX_PATH]:CHAR
  LOCAL _ss:SERVICE_STATUS
  
  invoke OpenSCManager,NULL,NULL,SC_MANAGER_ALL_ACCESS
  
  .if eax != NULL
    mov hSCManager,eax
    
    push eax
    
    invoke GetFullPathName,$CTA0("DeviceControl.sys"),sizeof acModulePath,addr acModulePath,esp
    
    pop eax
    
    invoke CreateService,hSCManager,$CTA0("DeviceControl"),$CTA0("DeviceControl"),\
      SERVICE_START + SERVICE_STOP + DELETE,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,\
      SERVICE_ERROR_IGNORE,addr acModulePath,NULL,NULL,NULL,NULL,NULL
    
    .if eax != NULL
      mov hService,eax
      
      invoke StartService,hService,0,NULL
      
      .if eax != 0
        invoke ControlConnection
        invoke ControlService,hService,SERVICE_CONTROL_STOP,addr _ss
      .else
        invoke MessageBox,NULL,$CTA0("Cann't start driver"),$CTA0("Failed"),MB_OK + MB_ICONSTOP
      .endif
    .else
      invoke MessageBox,NULL,$CTA0("Can't register driver"),$CTA0("Failed"),MB_OK + MB_ICONSTOP
    .endif
    
    invoke DeleteService,hService
    invoke CloseServiceHandle,hSCManager
  .else
    invoke MessageBox,NULL,$CTA0("Cann't connect to Service Control Manager"),$CTA0("Failed"),MB_OK + MB_ICONSTOP
  .endif
  ret

InstallDriver endp

start proc
  
  invoke InstallDriver
  invoke ExitProcess,NULL
  ret

start endp
end start
呵呵,这样我们就完成了应用层的代码了,代码很简单,仅作为演示之用,如您有其它的需要自行添加其它功能~~
程序运行如图所示(将程序与驱动放在同一个目录下)
图1

好了,就先讲到这里,争取在过年之前,将驱动的相关编程全部讲完,申明:我只会讲方法,至于具体你要实现什么功能,由你自己完成,有句话说的好“师傅领进门,修行在各人”没有师傅也行,不过我想有的话可能会更快点,虽然我不算“师傅”级的人,仅是想和大家一起学习,才有这个想法,下次再见~~
(本来想把附件也传上,不过想想还是让大家多上机操作吧,熟能生巧,不要总是CTRL+C加CTRL+V的~~)