使用CTL_CODE宏定义来定义一个控制码:
#define MY_PORT CTL_CODE(\ FILE_DEVICE_UNKNOWN, \ 0x801, \ METHOD_BUFFERED, \ FILE_ANY_ACCESS)
//向内核传递一个用户的等待事件
#define IOCTL_SET_EVENT CTL_CODE(\
FILE_DEVICE_UNKNOWN, \
0x802, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
1.驱动层处理:
在 DriverEntry 入口函数中添加:
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DDKDispatchDvCtl;
全局变量:
struct _MY_FUNCTION_INFO { CHAR FunctionName[150]; ULONG FunctionAddr; }; HANDLE hUserEvent = NULL; PKEVENT pEvent = NULL; _MY_FUNCTION_INFO* InputBuffer = NULL;
DDKDispatchDvCtl 函数:
1 #pragma PAGEDCODE 2 NTSTATUS DDKDispatchDvCtl ( 3 IN PDEVICE_OBJECT pDevObj, 4 IN PIRP pIrp) 5 { 6 KdPrint(("Entry DDKDispatchDvCtl\r\n")); 7 NTSTATUS status; 8 PIO_STACK_LOCATION io_stack; 9 io_stack = IoGetCurrentIrpStackLocation(pIrp); 10 11 //得到输入缓冲区大小 12 ULONG cbin = io_stack->Parameters.DeviceIoControl.InputBufferLength; 13 //得到输出缓冲区大小 14 ULONG cbout = io_stack->Parameters.DeviceIoControl.OutputBufferLength; 15 //得到IOCTL码 16 ULONG code = io_stack->Parameters.DeviceIoControl.IoControlCode; 17 18 if (io_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) 19 { 20 switch (code) 21 { 22 case IOCTL_SET_EVENT: 23 //把传递进来的用户层等待事件取出来 24 hUserEvent = *(HANDLE *)pIrp->AssociatedIrp.SystemBuffer; 25 26 //将用户层事件转化为内核等待对象 27 status = ObReferenceObjectByHandle(hUserEvent, EVENT_MODIFY_STATE, 28 *ExEventObjectType, KernelMode, (PVOID*)&pEvent, NULL); 29 30 KdPrint(("[IOCTL_SET_EVENT] status = %d\n", status));//status应该为0才对 31 32 ObDereferenceObject(pEvent); 33 break; 34 case INITIALIZE_TO_R0_PORT: 35 {
//METHOD_BUFFERED 方式: 输入输出都共用一个缓冲区
36 //得到 InputBuffer 37 InputBuffer = (_MY_FUNCTION_INFO*)pIrp->AssociatedIrp.SystemBuffer; 38 //获得从应用层传递的信息 39 KdPrint(("[INITIALIZE_TO_R0_PORT] Initialize Name : %s", InputBuffer->FunctionName)); 40 KdPrint(("[INITIALIZE_TO_R0_PORT] Initialize Addr : 0x%08x", InputBuffer->FunctionAddr)); 41 42 //将需要输出到应用层的信息复制到缓冲区, 系统会自动将缓冲区的内容复制到应用层的输出Buffer 43 CHAR* OutputChar = (CHAR*)pIrp->AssociatedIrp.SystemBuffer;
44 strcpy(OutputChar, "DbgkpMarkProcessPeb"); 45 //激活Event事件 46 KeSetEvent(pEvent, IO_NO_INCREMENT, FALSE); 47 48 //pIrp->IoStatus.Information 设置为 输出缓冲区大小 cbout, METHOD_OUT_DIRECT模式不用设置,设置为0就行了 49 pIrp->IoStatus.Information = cbout; 50 pIrp->IoStatus.Status = STATUS_SUCCESS; 51 KdPrint(("[INITIALIZE_TO_R0_PORT] Success.\r\n")); 52 } 53 break; 54 default: 55 pIrp->IoStatus.Information = 0; 56 pIrp->IoStatus.Status = STATUS_INVALID_PARAMETER; 57 break; 58 } 59 } 60 IoCompleteRequest(pIrp, IO_NO_INCREMENT); 61 return pIrp->IoStatus.Status; 62 }
2.用户层处理:
全局变量:
_MY_FUNCTION_INFO myOutputFuncInfo; CHAR myInputFuncName[150] = {0}; HANDLE hDevice = NULL;
1 void myFunction() 2 { 3 BOOL ret = FALSE; 4 DWORD ret_length = 0; 5 hDevice = CreateFile( 6 L"\\\\.\\Legend1900", //Legend1900为自定义设备名 7 GENERIC_READ | GENERIC_WRITE, 8 0, 9 0, 10 OPEN_EXISTING, 11 FILE_ATTRIBUTE_NORMAL, 12 0); 13 if (hDevice == INVALID_HANDLE_VALUE) 14 { 15 OutputDebugString(L"Open Device Fail"); 16 return FALSE; 17 } 18 19 // 20 // 1. 创建用户层的等待事件,传入内核 21 // 2. 创建线程,用于监测内核事件的到来 22 // 23 HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 24 HANDLE hThread = (HANDLE)_beginthreadex( 25 NULL, 26 0, 27 R3ToR0ThreadProc, //自定义函数 28 hEvent, //自定义函数的参数 29 0, 30 NULL); 31 32 //先将用户层的等待 Event 传入内核 33 DeviceIoControl( 34 hDevice, 35 IOCTL_SET_EVENT, 36 &hEvent, 37 sizeof(hEvent), 38 NULL, 39 0, 40 &ret_length, 41 NULL); 42 43 strcpy_s(myOutputFuncInfo.FunctionName, "我是传奇."); 44 myOutputFuncInfo.FunctionAddr = 0xFFFFFFFF; 45 ret = DeviceIoControl( 46 hDevice, 47 INITIALIZE_TO_R0_PORT, 48 &myOutputFuncInfo, 49 sizeof(_MY_FUNCTION_INFO), 50 &myInputFuncName, 51 150, 52 &ret_length, 53 NULL); 54 if (!ret) 55 { 56 OutputDebugString(L"DeviceIoControl Fail"); 57 return FALSE; 58 } 59 }
1 //通信线程 2 UINT _stdcall R3ToR0ThreadProc(LPVOID para) 3 { 4 BOOL ret = FALSE; 5 TCHAR FuncName[150] = {0}; 6 while (1) 7 { 8 WaitForSingleObject((HANDLE)para, INFINITE); 9 ResetEvent((HANDLE)para); 10 11 OutputDebugStringA("In [R3ToR0ThreadProc]"); 12 //将内核文件名(不包含目录) 由char* 转 wchar_t* 13 MultiByteToWideChar( 14 CP_ACP, 15 0, 16 myInputFuncName, 17 strlen(myInputFuncName) + 1, 18 FuncName, 19 150); 20 OutputDebugString(FuncName); 21 } 22 23 return 0; 24 }
输出打印信息为: