最近比较忙,其实也就是瞎忙 ,今天抽出一点时间来给大家补补驱动的课,呵呵~~如果您已经会了,就直接跳过啦,真没什么技术含量,让大哥们笑话了 ~~但我想对于一些想进军驱动和刚踏入驱动的朋友们,如果能给大家一点小小的帮助我想就足够了!(小弟,也是刚踏入驱动的大门,有误之处,望各位大哥指出 )
看到论坛上有人问起驱动与应用层之间通信的问题,今天我给大家讲讲驱动与应用程序之间是怎么通信的吧~~
首先说说为什么大部分的驱动程序都需要与应用层程序之间进行通信,其实原因很简单,就是为了用应用层软件去控制电脑底层~~不过如果某些特殊功能的驱动,比如病毒中的某个驱动程序进行某种隐蔽的操作(病毒或木马之类的),也可以不用与用户通信,因为它的安装就是为了某项工作,完成就行了~~不过我想大部分的驱动都需要与应用程序进行通信吧~~个人观点!
那么怎么样才能使我们的驱动与应用程序之间进行通信呢?
目前比较流行的两种方法是:
第一种:使用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的 ~~)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: