1 // test_exe.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include <windows.h> 6 #include "ctl_code.h" 7 8 int add(HANDLE hDevice, int a,int b) 9 { 10 11 int port[2]; 12 int bufret; 13 ULONG dwWrite; 14 port[0]=a; 15 port[1]=b; 16 17 DeviceIoControl(hDevice, add_code , &port, 8, &bufret, 4, &dwWrite, NULL); 18 return bufret; 19 20 } 21 22 int main(int argc, char* argv[]) 23 { 24 25 //CreateFile 打開設備 獲取hDevice 26 HANDLE hDevice = 27 CreateFile("\\\\.\\Templet", //\\??\\My_DriverLinkName 28 GENERIC_READ | GENERIC_WRITE, 29 0, // share mode none 30 NULL, // no security 31 OPEN_EXISTING, 32 FILE_ATTRIBUTE_NORMAL, 33 NULL ); // no template 34 35 printf("start\n"); 36 37 if (hDevice == INVALID_HANDLE_VALUE) 38 { 39 printf("獲取驅動句柄失敗: %s with Win32 error code: %d\n","MyDriver", GetLastError() ); 40 getchar(); 41 return -1; 42 } 43 int a=11; 44 int b=33; 45 int r=add(hDevice,a,b); 46 printf("%d+%d=%d \n",a,b,r); 47 getchar(); 48 CloseHandle(hDevice); 49 return 0; 50 }
.hwindows
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_IN_DIRECT,FILE_ANY_ACCESS)
sys驅動層核心代碼:app
#pragma code_seg("PAGE") NTSTATUS DispatchRoutine_DeviceIoControl(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 Direct Mode \n")); //緩衝區方式IOCTL //獲取緩衝區數據 a,b int * InputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer; //KdPrint(("%d,%d\n",cbin,cbout)); _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; UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); KdPrint(("MmGetSystemAddressForMdlSafe=%x",OutputBuffer)); _asm { mov eax,a mov ebx,OutputBuffer mov [ebx],eax //bufferet=a+b } KdPrint(("a+b=%d \n",a)); //設置實際操做輸出緩衝區長度 info = cbout; break; } case sub_code: { break; } }//end code switch break; } case IRP_MJ_CREATE: { break; } case IRP_MJ_CLOSE: { break; } case IRP_MJ_READ: { break; } } //對相應的IPR進行處理 pIrp->IoStatus.Information = info;//設置操做的字節數 pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功 IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP KdPrint(("離開派遣函數\n"));//調試信息 return STATUS_SUCCESS; //返回成功 }
緩衝區內存模式IOCTL函數
強調下:在驅動中最好不要直接訪問用戶模式下的內存地址,緩衝區方式能夠避免程序猿訪問內存模式下的內存地址。測試
#pragma code_seg("PAGE") NTSTATUS DispatchRoutine_DeviceIoControl(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 Buffered Mode \n")); //緩衝區方式IOCTL //獲取緩衝區數據 a,b int * InputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer; //KdPrint(("%d,%d\n",cbin,cbout)); _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、驅動層返回數據至用戶層 //Buffered Mode UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer; //Direct Mode //UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); KdPrint(("MmGetSystemAddressForMdlSafe=%x",OutputBuffer)); _asm { mov eax,a mov ebx,OutputBuffer mov [ebx],eax //bufferet=a+b } KdPrint(("a+b=%d \n",a)); //設置實際操做輸出緩衝區長度 info = cbout; break; } case sub_code: { break; } default: status = STATUS_INVALID_VARIANT; //其餘的控制碼 }//end code switch } case IRP_MJ_CREATE: { break; } case IRP_MJ_CLOSE: { break; } case IRP_MJ_READ: { break; } } //對相應的IPR進行處理 pIrp->IoStatus.Information = info;//設置操做的字節數 pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功 IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP KdPrint(("離開派遣函數\n"));//調試信息 return STATUS_SUCCESS; //返回成功 }
二者不一樣的地方:spa
1) 定義CTL_CODE宏時的method參數,操作系統
direct mode(直接方式)是METHOD_IN_DIRECT,指針
buffered mode(緩衝區方式)是METHOD_BUFFERED.調試
固然,exe和sys都須要修改。code
2)在操做輸出緩衝區的時候,orm
//Buffered Mode UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer; //Direct Mode UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
IDE:VS2010+WDK VC++6.0
測試環境:XP SP3
最後固然是保證可以不藍屏,可以輸出correct。
over~