驱动安装,通讯,Hello World

开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回。

驱动程序Hello World

之前总结了驱动环境的搭建,这里就直接继续之前搭建好的环境创建项目,打开vs2015创建一个驱动项目:

写代码之前先配置下编译选项:

然后添加一个项目文件main.c(注意后缀是.c,前面名字无所谓可以不叫main),里面的内容如下(下面模板代码来源于网络,作者:胡文亮,我是在看他的资料学习,感谢这位前辈。)

/*
WIN64驱动开发模板
作者:Tesla.Angela
*///【0】包含的头文件,可以加入系统或自己定义的头文件
#include <ntddk.h>
#include <windef.h>
#include <stdlib.h>//【1】定义符号链接,一般来说修改为驱动的名字即可
#define DEVICE_NAME L"\\Device\\KrnlHW64"
#define LINK_NAME   L"\\DosDevices\\KrnlHW64"
#define LINK_GLOBAL_NAME    L"\\DosDevices\\Global\\KrnlHW64"//【2】定义驱动功能号和名字,提供接口给应用程序调用
#define IOCTL_IO_TEST   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SAY_HELLO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)//【3】驱动卸载的处理例程
VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
{
UNICODE_STRING strLink;
DbgPrint("[KrnlHW64]DriverUnload\n");
//删除符号连接和设备
RtlInitUnicodeString(&strLink, LINK_NAME);
IoDeleteSymbolicLink(&strLink);
IoDeleteDevice(pDriverObj->DeviceObject);
}//【4】IRP_MJ_CREATE对应的处理例程,一般不用管它
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
DbgPrint("[KrnlHW64]DispatchCreate\n");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}//【5】IRP_MJ_CLOSE对应的处理例程,一般不用管它
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
DbgPrint("[KrnlHW64]DispatchClose\n");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}//【6】IRP_MJ_DEVICE_CONTROL对应的处理例程,驱动最重要的函数之一,一般走正常途径调用驱动功能的程序,都会经过这个函数
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIrpStack;
ULONG uIoControlCode;
PVOID pIoBuffer;
ULONG uInSize;
ULONG uOutSize;
DbgPrint("[KrnlHW64]DispatchIoctl\n");
//获得IRP里的关键数据
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
//这个就是传说中的控制码
uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
//输入和输出的缓冲区(DeviceIoControl的InBuffer和OutBuffer都是它)
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
//EXE发送传入数据的BUFFER长度(DeviceIoControl的nInBufferSize)
uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
//EXE接收传出数据的BUFFER长度(DeviceIoControl的nOutBufferSize)
uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch(uIoControlCode)
{
//在这里加入接口
case IOCTL_IO_TEST:
{
DWORD dw=0;
//输入
memcpy(&dw,pIoBuffer,sizeof(DWORD));
//使用
dw++;
//输出
memcpy(pIoBuffer,&dw,sizeof(DWORD));
//返回通信状态
status = STATUS_SUCCESS;
break;
}
case IOCTL_SAY_HELLO:
{
DbgPrint("[KrnlHW64]IOCTL_SAY_HELLO\n");
status = STATUS_SUCCESS;
break;
}
}
//这里设定DeviceIoControl的*lpBytesReturned的值(如果通信失败则返回0长度)
if(status == STATUS_SUCCESS)
pIrp->IoStatus.Information = uOutSize;
else
pIrp->IoStatus.Information = 0;
//这里设定DeviceIoControl的返回值是成功还是失败
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}//【7】驱动加载的处理例程,里面进行了驱动的初始化工作
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrLinkName;
UNICODE_STRING ustrDevName;
PDEVICE_OBJECT pDevObj;
//设置分发函数和卸载例程
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
pDriverObj->DriverUnload = DriverUnload;
//创建一个设备
RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
status = IoCreateDevice(pDriverObj, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
if(!NT_SUCCESS(status)) return status;
//判断支持的WDM版本,其实这个已经不需要了,纯属WIN9X和WINNT并存时代的残留物
if(IoIsWdmVersionAvailable(1, 0x10))
RtlInitUnicodeString(&ustrLinkName, LINK_GLOBAL_NAME);
else
RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
//创建符号连接
status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pDevObj);
return status;
}
DbgPrint("[KrnlHW64]DriverEntry\n");
//返回加载驱动的状态(如果返回失败,驱动讲被清除出内核空间)
return STATUS_SUCCESS;
}

然后右键编译工程,会出现这个错误提示:

然后把这个文件删除:

继续编译,还是不会过:继续改另一个配置文件选项:


然后就可以了:


然后是驱动安装程序:

目前如果没有仔细看上面的那个基本模板代码,需要回去仔细看下。大体了解细节,尤其是里面的注释。

看完代码了,接下来是驱动安装。

驱动安装和服务安装,如果之前写过安装服务的代码看驱动安装代码会很熟悉,都是采用SCM安装。具体流程是:

然后这个函数要仔细看定义:

更详细的细节之前看MSDN吧。

然后还是把资料上的模板代码直接拿过来,注意目前先用这个模板,因为这个安装模板是和上面的那个Hello World对应的,等看懂之后了,在自己定义相关驱动安装和驱动程序的代码,也可以自己写个模板,这里先不自己随便定义,可能会导致链接名字,驱动名字,还有驱动通讯的那个地方的细节自己弄乱了。这个博客看完了再回头定义自己的就行。

创建C++工程,然后直接添加安装代码和安装测试代码:

功能代码:

/*============================
Drvier Control Class (SCM way)
============================*/#pragma comment(lib,"advapi32.lib")class cDrvCtrl
{
public:
cDrvCtrl()
{
m_pSysPath = NULL;
m_pServiceName = NULL;
m_pDisplayName = NULL;
m_hSCManager = NULL;
m_hService = NULL;
m_hDriver = INVALID_HANDLE_VALUE;
}
~cDrvCtrl()
{
CloseServiceHandle(m_hService);
CloseServiceHandle(m_hSCManager);
CloseHandle(m_hDriver);
}
public:
DWORD m_dwLastError;
PCHAR m_pSysPath;
PCHAR m_pServiceName;
PCHAR m_pDisplayName;
HANDLE m_hDriver;
SC_HANDLE m_hSCManager;
SC_HANDLE m_hService;
public:
BOOL Install(PCHAR pSysPath,PCHAR pServiceName,PCHAR pDisplayName);
BOOL Start();
BOOL Stop();
BOOL Remove();
BOOL Open(PCHAR pLinkName);
BOOL IoControl(DWORD dwIoCode, PVOID InBuff, DWORD InBuffLen, PVOID OutBuff, DWORD OutBuffLen, DWORD *RealRetBytes);
private:
BOOL GetSvcHandle(PCHAR pServiceName);
DWORD CTL_CODE_GEN(DWORD lngFunction);
protected:
//null
};BOOL cDrvCtrl::GetSvcHandle(PCHAR pServiceName)
{
m_pServiceName = pServiceName;
m_hSCManager = OpenSCManagerA(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (NULL == m_hSCManager)
{
m_dwLastError = GetLastError();
return FALSE;
}
m_hService = OpenServiceA(m_hSCManager,m_pServiceName,SERVICE_ALL_ACCESS);
if (NULL == m_hService)
{
CloseServiceHandle(m_hSCManager);
return FALSE;
}
else
{
return TRUE;
}
}BOOL cDrvCtrl::Install(PCHAR pSysPath,PCHAR pServiceName,PCHAR pDisplayName)
{
m_pSysPath = pSysPath;
m_pServiceName = pServiceName;
m_pDisplayName = pDisplayName;
m_hSCManager = OpenSCManagerA(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (NULL == m_hSCManager)
{
m_dwLastError = GetLastError();
return FALSE;
}
m_hService = CreateServiceA(m_hSCManager,m_pServiceName,m_pDisplayName,SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,m_pSysPath,NULL,NULL,NULL,NULL,NULL);
if (NULL == m_hService)
{
m_dwLastError = GetLastError();
if (ERROR_SERVICE_EXISTS == m_dwLastError)
{
m_hService = OpenServiceA(m_hSCManager,m_pServiceName,SERVICE_ALL_ACCESS);
if (NULL == m_hService)
{
CloseServiceHandle(m_hSCManager);
return FALSE;
}
}
else
{
CloseServiceHandle(m_hSCManager);
return FALSE;
}
}
return TRUE;
}BOOL cDrvCtrl::Start()
{
if (!StartServiceA(m_hService,NULL,NULL))
{
m_dwLastError = GetLastError();
return FALSE;
}
return TRUE;
}BOOL cDrvCtrl::Stop()
{
SERVICE_STATUS ss;
GetSvcHandle(m_pServiceName);
if (!ControlService(m_hService,SERVICE_CONTROL_STOP,&ss))
{
m_dwLastError = GetLastError();
return FALSE;
}
return TRUE;}BOOL cDrvCtrl::Remove()
{
GetSvcHandle(m_pServiceName);
if (!DeleteService(m_hService))
{
m_dwLastError = GetLastError();
return FALSE;
}
return TRUE;
}BOOL cDrvCtrl::Open(PCHAR pLinkName)//example: \\\\.\\xxoo
{
if (m_hDriver != INVALID_HANDLE_VALUE)
return TRUE;
m_hDriver = CreateFileA(pLinkName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(m_hDriver != INVALID_HANDLE_VALUE)
return TRUE;
else
return FALSE;
}BOOL cDrvCtrl::IoControl(DWORD dwIoCode, PVOID InBuff, DWORD InBuffLen, PVOID OutBuff, DWORD OutBuffLen, DWORD *RealRetBytes)
{
DWORD dw;
BOOL b=DeviceIoControl(m_hDriver,CTL_CODE_GEN(dwIoCode),InBuff,InBuffLen,OutBuff,OutBuffLen,&dw,NULL);
if(RealRetBytes)
*RealRetBytes=dw;
return b;
}DWORD cDrvCtrl::CTL_CODE_GEN(DWORD lngFunction)
{
return (FILE_DEVICE_UNKNOWN * 65536) | (FILE_ANY_ACCESS * 16384) | (lngFunction * 4) | METHOD_BUFFERED;
}

测试代码:

// DriverInstall.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <string>
#include <windows.h>
#include "ScmDrvCtrl.h"#pragma warning(disable:4996)#pragma comment(lib,"user32.lib")using namespace std;void GetAppPath(char *szCurFile) //最后带斜杠
{
GetModuleFileNameA(0, szCurFile, MAX_PATH);
for (SIZE_T i = strlen(szCurFile) - 1; i >= 0; i--)
{
if (szCurFile[i] == '\\')
{
szCurFile[i + 1] = '\0';
break;
}
}
}int main()
{
BOOL b;
cDrvCtrl dc;
//设置驱动名称
char szSysFile[MAX_PATH] = { 0 };
char szSvcLnkName[] = "KrnlHW64";;
GetAppPath(szSysFile);
strcat(szSysFile, "KrnlHW64.sys");
//安装并启动驱动
b = dc.Install(szSysFile, szSvcLnkName, szSvcLnkName);
b = dc.Start();
printf("LoadDriver=%d\n", b);
//“打开”驱动的符号链接
dc.Open("\\\\.\\KrnlHW64");
//使用控制码控制驱动(0x800:传入一个数字并返回一个数字)
DWORD x = 100, y = 0, z = 0;
dc.IoControl(0x800, &x, sizeof(x), &y, sizeof(y), &z);
printf("INPUT=%ld\nOUTPUT=%ld\nReturnBytesLength=%ld\n", x, y, z);
//使用控制码控制驱动(0x801:在DBGVIEW里显示HELLOWORLD)
dc.IoControl(0x801, 0, 0, 0, 0, 0);
//关闭符号链接句柄
CloseHandle(dc.m_hDriver);
//停止并卸载驱动
b = dc.Stop();
b = dc.Remove();
printf("UnloadDriver=%d\n", b);
getchar();
return 0;
}

然后就直接本地尝试调试安装一次,结果先是这个:

不用管它,点击全部允许,但是还是会发现

还是装不上,其实是肯定装不上的。原因是64位机器需要的强制签名加载驱动:

注意最后面那句,各种系统的防护已经被攻克,他没有说win10,不过目前已经亲测win10也已经攻克,之后有机会再说这些东西,这里只讨论正常安装。想在win64上安装无签名驱动也可以,如果是win7,直接cmd 输入  bcdedit /set testsigning on ,然后重启电脑(win7是这样,win10貌似是前面要多输入一条命令,如果是要win10的话自己搜下吧,同时还有其他改设置关掉无签名驱动提示等的设置,加载测试驱动程序,需要的也可以找找,网上很多)。设置后上面的配置之后,重启电脑:

有的时候会有测试模式水印,有的时候没有,可能提示不是正版的话会没这个水印,不过这不重要,只要相面的那个cmd命令执行成功,重启电脑就可以加载无签名64位驱动了。

接下来测试下我们上面的那一套代码(所有程序都右键管理员启动):

先打开dbgview全都选上:

然后启动安装程序:

OK驱动加载成功,并且通讯测试成功。这里基本模板就算完事了,之后就是一些常用的驱动开发,后续再整理。

Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)相关推荐

  1. Win64 驱动内核编程-3.内核里使用内存

    内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...

  2. Win64 驱动内核编程-18.SSDT

    SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...

  3. Win64 驱动内核编程-8.内核里的其他常用

    内核里的其他常用 1.遍历链表.内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖 葫芦一样给串了起来.所以遍历双向链表能获得很多重要的内核数据.举个简单的例子,驱 动对象 Driv ...

  4. Win64 驱动内核编程-10.突破WIN7的PatchGuard

    突破WIN7的PatchGuard WIN64 有两个内核保护机制,KPP 和 DSE.KPP 阻止我们 PATCH 内核,DSE 拦截我们加载驱动.当然 KPP 和 DSE 并不是不可战胜的,WIN ...

  5. Win64 驱动内核编程-34.对抗与枚举MiniFilter

    对抗与枚举MiniFilter MiniFilter 是目前杀毒软件用来实现"文件系统自我保护"和"文件实时监控"的方法. 由于 MiniFilter 模型简单 ...

  6. Win64 驱动内核编程-28.枚举消息钩子

    枚举消息钩子 简单粘贴点百度的解释,科普下消息钩子: 钩子是WINDOWS中消息处理机制的一个要点,通过安装各种钩子,应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之 ...

  7. Win64 驱动内核编程-25.X64枚举和隐藏内核模块

    X64枚举和隐藏内核模块 在 WIN64 上枚举内核模块的人方法:使用 ZwQuerySystemInformation 的第 11 号功能和枚举 KLDR_DATA_TABLE_ENTRY 中的 I ...

  8. Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook

    Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...

  9. Win64 驱动内核编程-20.UnHook SSDT

    UNHOOK SSDT 要恢复 SSDT,首先要获得 SSDT 各个函数的原始地址,而 SSDT 各个函数的原始地址,自然是存储在内核文件里的.于是,有了以下思路: 1.获得内核里 KiService ...

最新文章

  1. LeetCode简单题之单值二叉树
  2. Jsoup:使用Java将爬虫得到的数据写入Excel,Jsoup得到的数据进行持久化,爬虫数据保存到本地Excel中
  3. 深入理解JAVA虚拟机 虚拟机性能监控和故障处理工具
  4. 2020快手汽车行业数据价值报告
  5. 【CCF】201703-1分蛋糕
  6. 你真的懂软件测试人员的痛苦吗?——目前软件测试5大误区
  7. jquery 图像滑块_jQuery缩略图图像滑块– CSS,JavaScript
  8. linux操作系统基础及应用课后答案,Linux操作系统课后习题答案及复习要点
  9. python填空题题库_Python题库——Python笔试填空题
  10. 快速入门丨篇四:如何进行运动控制器与触摸屏通讯?
  11. JavaSwing订餐管理系统
  12. matlab中uigetfile读取图片,MATLAB如何读取图片? 如何用Matlab读入并
  13. win10系统下摄像头无法打开的解决方法
  14. gsm手机影响计算机屏幕会怎么样,手机的辐射对孕妇的危害有多大
  15. gateway网关调用报 reactor.netty.http.client.HttpClient.chunkedTransfer(Z)Lreactor/netty/http/client/HttpC
  16. 高效学英语 - 统计英文书词频
  17. The default interactive shell is now zsh.
  18. 淘宝/天猫、拼多多、1688产品详情页API、SKU信息获取展示
  19. 面向用户界面设计,故障诊断程序集成设计(以CWRU为例)
  20. 模仿淘宝手机号码输入框

热门文章

  1. UWP 文件读写API
  2. Windows 10 安装
  3. JSP中base href=%=basePath%作用
  4. 程序员也要多读些专业之外的书
  5. python paramiko 问题总结
  6. Discuz!NT论坛代码小分析
  7. Silverlight 2.0学习笔记——XAML
  8. select可选择、同时可自行输入
  9. hdu-5900 QSC and Master(区间dp)
  10. 转: 学ppt的网址与素材