In the last two sections, we introduced the buffer and direct access mode for driver-to-Application Communication. Today we will introduce the third method. We can modify the code in the previous section.
First, modify ctl_code.h
#ifndef CTL_CODE#pragma message("\n \n-----------EXEģʽ . Include winioctl.h ") #include<winioctl.h> //CTL_CODE ntddk.h wdm.h #else #pragma message("-\n \n---------SYSģʽ .NO Include winioctl.h ")#endif#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER,FILE_ANY_ACCESS)#define sub_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER,FILE_ANY_ACCESS)
That is, to change the access mode to another mode, the third parameter.
Modify the driver code. The IRP dispatch function is as follows:
// Dispatch function # pragma pagecodentstatus publish (in pdevice_object p1_bj, in pirpirp) {ulong Info; ntstatus status = STATUS_SUCCESS; // obtain the current stack pointer pio_stack_location stack = forward (pirp ); ulong mf = stack-> majorfunction; // differentiate irpswitch (MF) {Case irp_mj_device_control: {kdprint ("Enter mydriver_deviceiocontrol \ n ")); // obtain the size of the input buffer ulong cbin = stack-> parameters. deviceiocontrol. inputbufferlength; // obtain the output buffer size ulong cbout = stack-> parameters. deviceiocontrol. outputbufferlength; // obtain the ioctl code ulong code = stack-> parameters. deviceiocontrol. iocontrolcode; Switch (CODE) {Case add_code: {int A, B; kdprint ("add_code 1111111111111111111 \ n"); // buffer IOCTL // obtain the buffer data, B // int * inputbuffer = (int *) pirp-> associatedirp. systembuffer; int * inputbuffer = (int *) Stack-> parameters. deviceiocontrol. type3inputbuffer ;__ try {probeforread (inputbuffer, cbin ,__ alignof (INT); // judge whether the pointer is readable _ ASM {mov eax, inputbuffermov EBX, [eax] mov, ebxmov EBX, [eax + 4] mov B, EBX} kdprint ("A = % d, B = % d \ n", a, B )); A = a + B; // C. The driver layer returns data to the user layer // operation output buffer // int * outputbuffer = (int *) pirp-> associatedirp. systembuffer; // int outputbuffer = (INT) mmgetsystemaddressformdlsafe (pir-> mdladdress, normalpagepriority); int * outputbuffer = (int *) pir-> userbuffer; probeforwrite (outputbuffer, cbout, 4); // determine whether the pointer can write kdprint ("outputbuffer = % x", outputbuffer) ;__ ASM {mov eax, amov EBX, outputbuffermov [EBX], eax // bufferet = a + B} kdprint ("A + B = % d \ n", a) ;:__ handle T (exception_execute_handler) {kdprint ("the specified address cannot be read or written \ n");} // set the actual output buffer length info = 4; break;} case sub_code: {break ;}// end code switchbreak;} case irp_mj_create: {break;} case irp_mj_close: {break;} case irp_mj_read: {break ;}} // process the corresponding IPR pir-> iostatus. information = Info; // set the number of bytes for the Operation to 0, which has no practical significance here. status = STATUS_SUCCESS; // return successful iocompleterequest (pirp, io_no_increment); // indicates that the irpkdprint is completed ("Exit dispatch function \ n"); // return STATUS_SUCCESS; // return success}
Note that the method for obtaining the input buffer and the output buffer changes. After obtaining the pointer of the input buffer, we need to determine whether the input buffer is readable. After obtaining the pointer of the output buffer, we need to determine whether the input buffer can be written, because the correct pointer may not be obtained frequently.
See the complete source code.