1、
实战EXE和SYS通信
A、用户层传入数据-EXE部分代码
B、驱动层接收数据并处理-SYS部分代码
C、驱动层返回数据至用户层
D、用户层获得处理结果
【190】假设驱动部分已经按照我们的思路写好了
【305】创建 VC6 Win32ConsoleApplication 名称为:"test_exe"
【345】选择的是“A "Hello, World" application”,非“An empty project”
【400】写代码(应用层的):
【1290】sys和exe 都需要使用 CTL_CODE来构建 控制码,于是新建一个头文件ctl_code.h,【1415】将 CTL_CODE 相关的(宏)代码写在这个头文件里面
“
#include <winioctl.h> // CTL_CODE
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define sub_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#include <windows.h>
#include "ctl_code.h"
int port[2],bufret;
DWORD dwWrite;
int add(HANDLE hDevice,int a,int b)
{
port[0]=a;
port[1]=b;
DeviceIoControl(hDevice, add_code , &port, 8, &bufret, 4, &dwWrite, NULL);
return bufret;
}
int main(int argc, char* argv[])
{
//CreateFile hDevice
HANDLE hDevice = CreateFile(
"\\\\.\\My_DriverLinkName", // \\??\\My_DriverLinkName
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
printf("start\n");
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("获取驱动句柄失败: %s with Win32 error code: %d\n","MyDriver",
GetLastError() );
getchar(); // system("pause");
return -1;
}
//add_code
int a=55;
int b=33;
int r= add(hDevice, a, b);
printf("%d+%d=%d\n", a, b, r);
getchar();
return 0;
}
”
【2585】驱动层的代码,以 第25课 的代码为例,进行一些修改
【2780】修改符号链接
RtlInitUnicodeString(&symLinkName,L"\\??\\My_DriverLinkName");
【3615】把 刚才 exe项目里面创建的头文件ctl_code.h 复制到 sys项目中
【3935】复制过来的 ctl_code.h 中,要把 “#include <winioctl.h>”注释掉,或者 更通用的做法 这里我们就不讲了...
【3980】在 NTDDK.h 里面已经有了 CTL_CODE的定义(ZC: 可以用 “#ifdef” 来控制是否需要include winioctl.h/NTDDK.h,也可以将 include winioctl.h/NTDDK.h 写在 ctl_code.h的外面)
【4625】ZC: 看到 sys中 输入/输出 缓冲区的获取,都是“pIrp->AssociatedIrp.SystemBuffer” ! ! ! 它会自动映射相应的内存?读的时候就用DeviceIoControl的输入缓冲区,写的时候就用DeviceIoControl的输出缓冲区?
“
#include "ctl_code.h"
NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj, IN PIRP pIrp)
{
ULONG info;
//得到当前栈指针
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
ULONG mf=stack->MajorFunction; // 区分IRP
switch (mf)
{
case IRP_MJ_DEVICE_CONTROL:
{
KdPrint(("Enter myDriver_DeviceIOControl\n"));
NTSTATUS status = STATUS_SUCCESS;
//得到输入缓冲区大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到输出缓冲区大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//得到IOCTL码
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
switch (code)
{
case add_code:
{
int a,b;
KdPrint(("add_code 1111111111111111111\n"));
//缓冲区方式IOCTL
//获取缓冲区数据 a,b
int * InputBuffer = (int*) pIrp->AssociatedIrp.SystemBuffer;
_asm
{
mov eax,InputBuffer
mov ebx,[eax]
mov a,ebx
mov ebx,[eax+4]
mov b,ebx
}
KdPrint(("a=%d,b=%d \n", a,b));
a=a+b;
//C、驱动层返回数据至用户层
//操作输出缓冲区
int* OutputBuffer = (int*) pIrp->AssociatedIrp.SystemBuffer;
_asm
{
mov eax,a
mov ebx,OutputBuffer
mov [ebx],eax
}
KdPrint(("a+b=%d \n",a));
//设置实际操作输出缓冲区长度
info = 4;
break;
}
case sub_code:
{
break;
}
}// switch (code)
break;
} // IRP_MJ_DEVICE_CONTROL
case IRP_MJ_CREATE:
{
break;
}
case IRP_MJ_CLOSE:
{
break;
}
case IRP_MJ_READ:
{
break;
}
}
//对相应的IPR进行处理
pIrp->IoStatus.Information = info;//设置操作的字节数为0,这里无实际意义
pIrp->IoStatus.Status = STATUS_SUCCESS;//返回成功
IoCompleteRequest(pIrp, IO_NO_INCREMENT);//指示完成此IRP
KdPrint(("离开派遣函数\n"));//调试信息
return STATUS_SUCCESS; //返回成功
}
”
【5280】sys 和 exe 放到 虚拟机中,进行测试
【5455】此时运行,exe计算得到了错误的结果,∵变量未初始化(ZC: 貌似不对啊,exe能打开驱动,说明已经存在了相关的符号链接了啊)
【5495】载入驱动
【5535】此时 exe的计算结果还是错误的,可能是刚才已经载入了驱动。先卸载 之前打开的驱动
【5640】此时 报错 获取句柄失败。蓝屏 重新测试
【5745】exe计算结果 还是错误的
【5760】改代码 加调试信息
【6250】卸载例程 中的 符号链接名称 是错误的 没有改过来
【6855】可能是卸载的时候卸载的不干净,点击 DriverMonitor的"STOP"按钮 虚拟机会蓝屏
2、