常识:
IRP:I/O Request Package  即输入输出请求包
exe和sys通信时,exe会发出I/O请求。操作系统会将I/O请求转化为相应的IRP数据,
不同类型传递到不同的dispatch function
 
过程:
DeviceIoControl函数产生IRP_MJ_DEVICE_CONTROL 派遣例程
DeviceIoControl函数是用来向指定设备发送控制码,当指定的设备接收到DeviceIoControl函数发来的控制码后
会调用IRP_MJ_DEVICE_CONTROL对应的派遣例程,针对不同的控制码进行处理。
 
BOOL DeviceIoControl(  HANDLE hDevice,              // handle to device
  DWORD dwIoControlCode,       // operation control code
  LPVOID lpInBuffer,           // input data buffer
  DWORD nInBufferSize,         // size of input data buffer
  LPVOID lpOutBuffer,          // output data buffer
  DWORD nOutBufferSize,        // size of output data buffer
  LPDWORD lpBytesReturned,     // byte count
  LPOVERLAPPED lpOverlapped    // overlapped information);
 
 
 
直接内存模式IOCTL:
DDK中有CTL_CODE定义,应用层中没有CTL_CODE定义
即驱动程序中使用CTL_CODE需要只需要包含ntddk.h头文件,
而在应用程序中需要包含winioctl.h头文件
 
#define CTL_CODE(DeviceType, Function, Method, Access)  直接看MSDN
DeviceType应和IoCreateDevice的类型相匹配。形如:FILE_DEVICE_XX的宏
Function:这是驱动程序定义的IOCTL码,0x800到0xFFFF由程序猿自己定义
mothod参数:应该指定METHOD_IN_DIRECT
 
效果:同样可以避免驱动程序访问用户模式的内存地址。
 
例如:
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_IN_DIRECT,FILE_ANY_ACCESS)
 
Direct Mode:
exe应用层代码:
cpp
 // test_exe.cpp : Defines the entry point for the console application.
// #include "stdafx.h"
#include <windows.h>
#include "ctl_code.h" int add(HANDLE hDevice, int a,int b)
{ int port[];
int bufret;
ULONG dwWrite;
port[]=a;
port[]=b; DeviceIoControl(hDevice, add_code , &port, , &bufret, , &dwWrite, NULL);
return bufret; } int main(int argc, char* argv[])
{ //CreateFile 打开设备 获取hDevice
HANDLE hDevice =
CreateFile("\\\\.\\Templet", //\\??\\My_DriverLinkName
GENERIC_READ | GENERIC_WRITE,
, // 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();
return -;
}
int a=;
int b=;
int r=add(hDevice,a,b);
printf("%d+%d=%d \n",a,b,r);
getchar();
CloseHandle(hDevice);
return ;
}

.h

#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 	0x800, 	METHOD_IN_DIRECT,FILE_ANY_ACCESS)

 

sys驱动层核心代码:

#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; //返回成功
}

两者不同的地方:

1) 定义CTL_CODE宏时的method参数,

  direct mode(直接方式)是METHOD_IN_DIRECT,

  buffered mode(缓冲区方式)是METHOD_BUFFERED.

  当然,exe和sys都需要修改。

2)在操作输出缓冲区的时候,

  //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~

 

DeviceIoControl方式 sys和exe通信的更多相关文章

  1. C# 以嵌入到窗体的方式打开外部exe

    using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using S ...

  2. Python程序退出方式(sys.exit() os._exit() os.kill() os.popen(...))

    对于如何结束一个Python程序或者用Python操作去结束一个进程等,Python本身给出了好几种方法,而这些方式也存在着一些区别,对相关的几种方法看了并实践了下,同时也记录下. 参考: Pytho ...

  3. AutoCAD.NET 不使用P/Invoke方式调用acad.exe或accore.dll中的接口(如acedCommand、acedPostCommand等)

    使用C#进行AutoCAD二次开发,有时候由于C#接口不够完善,或者低版本AutoCAD中的接口缺少,有些工作不能直接通过C#接口来实现,所以需要通过P/Invoke的方式调用AutoCAD的其他DL ...

  4. VirtualBox NAT方式与主机互相通信

    之前说过,桥接方式适合在统一的网络环境中使用(一样的网关和许可). 如果网络环境发生改变,那就难堪了 -- 这就是我遇到的问题,公司里每人的IP都是固定的. 解决办法,改为NAT网络地址转换模式. 但 ...

  5. WebService与RMI(远程调用方式实现系统间通信)

    前言 本文是<分布式java应用基础与实践>读书笔记:另外参考了此博客,感觉讲的挺好的,尤其是其中如下内容: 另外,消息方式实现系统间通信本文不涉及.RMI则只采用spring RMI框架 ...

  6. 7z 命令行方式生成自解压exe

    一.下载 7z是一个免费的工具,除了通过命令行的方式提供各种文件.压缩包相关的操作外,还提供了一种方式可以打出自解压的exe程序.该程序从运行到结束经历了三个流程: (1) 解压文件到用户临时目录: ...

  7. 2种方式(线程间通信/互斥锁)实现两个线程,一个线程打印1-52,另一个线程打印字母A-Z,打印顺序为12A34B56C......5152Z

    //2019/06/13 本周HT面试遇到的问题,答得不是很好,自己重新做一下.面试只需要写出线程间通信的方式,//我当时大致知道思路,因为之前看过马士兵老师的多线程视频,但是代码写出来估计编译都是报 ...

  8. exe文件打开方式(恢复EXE文件关联)

    文件关联损坏常常是计算机病毒造成的,目前网络上有很多相关修复工具,相对来说,System Repair Engineer 支持的修复格式是比较齐全的,这个工具可以在http://www.kztechs ...

  9. andriod开发--使用Http的Get和Post方式与网络交互通信

    package com.example.a350773523.myapplication; import android.os.AsyncTask; import android.support.v7 ...

随机推荐

  1. [ Alcatraz ]管理Xcode插件

    [ Alcatraz 配置 ] 1.包管理器在线安装 Terminal终端 $ curl -fsSL https://raw.githubusercontent.com/supermarin/Alca ...

  2. 直读Innodb datafile

    这两天有空翻了翻大神写的<innodb存储引擎>,手痒亲身实践.由于此书出版了有段时日,没有用其推荐的python工具,通过点滴推敲,略微发现其中冰山一角的奥秘.对于今后对于一些问题查证或 ...

  3. WaitHandle、AutoResetEvent、ManualResetEvent

    多线程中的锁系统(三)-WaitHandle.AutoResetEvent.ManualResetEvent 介绍 本章主要说下基于内核模式构造的线程同步方式,事件,信号量. 目录 一:理论 二:Wa ...

  4. MySQL在Windows和Linux减少数据库

    Linux减少数据库代码: 1,创建一个空数据库cddl mysql> create database cddl; Query OK, 1 row affected (0.00 sec) 2,还 ...

  5. SQL点滴35—SQL语句中的exists

    原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHE ...

  6. 怎样在Upstart机制下的系统中加入upstart事件型的任务

    /*********************************************************************  * Author  : Samson  * Date   ...

  7. CentOS上安装WordPress搭建博客平台

    前两天在服务器上搭建了AMP,今天试着在上面安装了一个WordPress(中文:http://cn.wordpress.org/,英文:http://wordpress.org/),我安装的是英文最新 ...

  8. AJAX入门——工作原理

    同步和异步交互,了解互动 对于一个样本:一般B/S模式(同步)       AJAX技术(异步)        *  同步:       提交请求->等待server处理->处理完成返回 ...

  9. 安装Windows操作系统的驱动程序(驱动精灵版) - 进阶者系列 - 学习者系列文章

    安装完操作系统之后,就需要安装对应的驱动程序了.下面就简要介绍下驱动程序的安装.以驱动精灵驱动安装软件为例. 1.  下载驱动精灵. 从http://www.drivergenius.com/网站下载 ...

  10. 使用Windows2003创建FTP服务器 - 进阶者系列 - 学习者系列文章

    现在有不少的FTP建设软件,比如Server-U软件.不过本文只介绍使用Windows2003来创建FTP服务器. 1.  打开控制面板的添加删除程序. 2.  打开 添加删除Windows组件 3. ...