目录/参考资料:https://www.cnblogs.com/railgunRG/p/14412321.html

在阅读本节前,建议先阅读《Windows内核安全与驱动开发》第五章内容,并自行了解相关背景知识。


R0部分

创建项目,打开:项目属性->链接器->输入->附加依赖项(点开后选择【编辑】),添加:

%(AdditionalDependencies)
$(DDK_LIB_PATH)\wdmsec.lib

参考代码:

#include <ntifs.h>
#include <wdmsec.h> static PDEVICE_OBJECT g_cdo = NULL; const GUID CWK_GUID_CLASS_MYCDO =
{ 0x17a0d1e0L, 0x3249, 0x12e1, {0x92,0x16, 0x45, 0x1a, 0x21, 0x30, 0x29, 0x06} }; #define CWK_CDO_SYB_NAME L"\\??\\slbkcdo_3948d33e" // 从应用层给驱动发送一个字符串。
#define CWK_DVC_SEND_STR \
(ULONG)CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x911,METHOD_BUFFERED, \
FILE_WRITE_DATA) // 从驱动读取一个字符串
#define CWK_DVC_RECV_STR \
(ULONG)CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x912,METHOD_BUFFERED, \
FILE_READ_DATA) // 定义一个链表用来保存字符串
#define CWK_STR_LEN_MAX 512
typedef struct {
LIST_ENTRY list_entry;
char buf[CWK_STR_LEN_MAX];
} CWK_STR_NODE; // 还必须有一把自旋锁来保证链表操作的安全性
KSPIN_LOCK g_cwk_lock;
// 一个事件来标识是否有字符串可以取
KEVENT g_cwk_event;
// 必须有个链表头
LIST_ENTRY g_cwk_str_list; #define MEM_TAG 'cwkr' // 分配内存并初始化一个链表节点
CWK_STR_NODE *cwkMallocStrNode()
{
CWK_STR_NODE *ret = ExAllocatePoolWithTag(
NonPagedPool, sizeof(CWK_STR_NODE), MEM_TAG);
if (ret == NULL)
return NULL;
return ret;
} void cwkUnload(PDRIVER_OBJECT driver)
{
DbgPrint("\r\n准备卸载\r\n");
UNICODE_STRING cdo_syb = RTL_CONSTANT_STRING(CWK_CDO_SYB_NAME);
CWK_STR_NODE *str_node;
//ASSERT(g_cdo != NULL);//bug崩溃?
DbgPrint("准备删除符号链接\r\n");
IoDeleteSymbolicLink(&cdo_syb);
DbgPrint("准备删除驱动对象\r\n");
if(g_cdo!=NULL)IoDeleteDevice(g_cdo);
else {
DbgPrint("\r\n发生严重错误:g_cdo==NULL\r\n");
} DbgPrint("\r\n准备释放内存\r\n");
// 负责的编程态度:释放分配过的所有内核内存。
while (TRUE)
{
str_node = (CWK_STR_NODE *)ExInterlockedRemoveHeadList(
&g_cwk_str_list, &g_cwk_lock);
// str_node = RemoveHeadList(&g_cwk_str_list);
if (str_node != NULL)
ExFreePool(str_node);
else
break;
}; DbgPrint("\r\n卸载完成\r\n");
} NTSTATUS cwkDispatch(
IN PDEVICE_OBJECT dev,
IN PIRP irp)
{
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status = STATUS_SUCCESS;
ULONG ret_len = 0;
while (1)
{
if (irpsp->MajorFunction == IRP_MJ_CREATE || irpsp->MajorFunction == IRP_MJ_CLOSE)
{
break;
} if (irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
// 处理DeviceIoControl。
PVOID buffer = irp->AssociatedIrp.SystemBuffer;
ULONG inlen = irpsp->Parameters.DeviceIoControl.InputBufferLength;
ULONG outlen = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
ULONG len;
CWK_STR_NODE *str_node;
switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
{
case CWK_DVC_SEND_STR: ASSERT(buffer != NULL);
ASSERT(outlen == 0);
if (inlen > CWK_STR_LEN_MAX)
{
status = STATUS_INVALID_PARAMETER;
break;
} DbgPrint("\r\n接收到来自r3的信息:%s\r\n", (char *)buffer);
str_node = cwkMallocStrNode();
if (str_node == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
} //char* tmpBuffer= RTL_CONSTANT_STRING(L"QWQ");//字符缓冲
//strncpy(tmpBuffer, (char *)buffer, CWK_STR_LEN_MAX); strncpy(str_node->buf, (char *)buffer, CWK_STR_LEN_MAX); strncpy(str_node->buf, (char *)buffer, CWK_STR_LEN_MAX); char tmp1[512] = "Hello,Ring3!";
strncpy(str_node->buf, tmp1, CWK_STR_LEN_MAX);
// 插入到链表末尾。用锁来保证安全性。
ExInterlockedInsertTailList(&g_cwk_str_list, (PLIST_ENTRY)str_node, &g_cwk_lock);
// InsertTailList(&g_cwk_str_list, (PLIST_ENTRY)str_node);
// 打印
// DbgPrint((char *)buffer);
// 那么现在就可以认为这个请求已经成功。因为刚刚已经插入了一
// 个,那么可以设置事件来表明队列中已经有元素了。
KeSetEvent(&g_cwk_event, 0, FALSE);//设为TRUE就是等死
//DbgPrint("\r\n信息处理完成!\r\n");
break;
case CWK_DVC_RECV_STR: //ASSERT(buffer != NULL);
//ASSERT(inlen == 0);
if (outlen < CWK_STR_LEN_MAX)
{
DbgPrint("\r\n长度太短..\r\n");
status = STATUS_INVALID_PARAMETER;
break;
}
while (1)
{
// 插入到链表末尾。用锁来保证安全性。
str_node = (CWK_STR_NODE *)ExInterlockedRemoveHeadList(&g_cwk_str_list, &g_cwk_lock);
// str_node = RemoveHeadList(&g_cwk_str_list);
if (str_node != NULL)
{
// 这种情况下,取得了字符串。那就拷贝到输出缓冲中。然后
// 整个请求就返回了成功。
strncpy((char *)buffer, str_node->buf, CWK_STR_LEN_MAX);
ret_len = strnlen(str_node->buf, CWK_STR_LEN_MAX) + 1;
DbgPrint("\r\n准备发送信息,%s\r\n", str_node->buf);
ExFreePool(str_node);
break;
}
else
{
// 对于合法的要求,在缓冲链表为空的情况下,等待事件进行
// 阻塞。也就是说,如果缓冲区中没有字符串,就停下来等待
// 。这样应用程序也会被阻塞住,DeviceIoControl是不会返回
// 的。但是一旦有就会返回。等于驱动“主动”通知了应用。
KeWaitForSingleObject(&g_cwk_event, Executive, KernelMode, 0, 0);
}
}
break;
default:
// 到这里的请求都是不接受的请求。未知的请求一律返回非法参数错误。
status = STATUS_INVALID_PARAMETER; DbgPrint("\r\n出现未知请求!!\r\n");
break;
}
}
break;
}
// 返回结果
irp->IoStatus.Information = ret_len;
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
//DbgPrint("\r\n成功返回结果!\r\n");
return status;
} NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
NTSTATUS status;
ULONG i;
UCHAR mem[256] = { 0 }; // 生成一个控制设备。然后生成符号链接。
UNICODE_STRING sddl = RTL_CONSTANT_STRING(L"D:P(A;;GA;;;WD)");
UNICODE_STRING cdo_name = RTL_CONSTANT_STRING(L"\\Device\\cwk_3948d33e");
UNICODE_STRING cdo_syb = RTL_CONSTANT_STRING(CWK_CDO_SYB_NAME); //KdBreakPoint();
// 生成一个控制设备对象。
status = IoCreateDeviceSecure(
driver,
0, &cdo_name,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE, &sddl,
(LPCGUID)&CWK_GUID_CLASS_MYCDO,
&g_cdo);
if (!NT_SUCCESS(status))
return status; // 生成符号链接.
IoDeleteSymbolicLink(&cdo_syb);
status = IoCreateSymbolicLink(&cdo_syb, &cdo_name);
if (!NT_SUCCESS(status))
{
IoDeleteDevice(g_cdo);
return status;
} // 初始化事件、锁、链表头。
KeInitializeEvent(&g_cwk_event, SynchronizationEvent, TRUE);
KeInitializeSpinLock(&g_cwk_lock);
InitializeListHead(&g_cwk_str_list); // 所有的分发函数都设置成一样的。
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
driver->MajorFunction[i] = cwkDispatch;
}
//DbgPrint("test1\r\n"); // 支持动态卸载。
driver->DriverUnload = cwkUnload;
//DbgPrint("test2\r\n");
// 清除控制设备的初始化标记。
//g_cdo->Flags &= ~DO_DEVICE_INITIALIZING;
//DbgPrint("test3\r\n");
return STATUS_SUCCESS;
}

 

R3部分

参考代码:

#include <stdio.h>
#include <tchar.h>
#include <windows.h> const char* CWK_DEV_SYM = "\\\\.\\slbkcdo_3948d33e"; // 从应用层给驱动发送一个字符串。
#define CWK_DVC_SEND_STR \
(ULONG)CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x911,METHOD_BUFFERED, \
FILE_WRITE_DATA) // 从驱动读取一个字符串
#define CWK_DVC_RECV_STR \
(ULONG)CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x912,METHOD_BUFFERED, \
FILE_READ_DATA) int _tmain(int argc, _TCHAR* argv[])
{
HANDLE device = NULL;
ULONG ret_len;
int ret = 0;
char tmp[] = "Hello driver, this is a message from app.\r\n";
char* msg = tmp;
char tst_msg[1024] = { 0 }; // 打开设备.每次要操作驱动的时候,先以此为例子打开设备
device=CreateFile(CWK_DEV_SYM,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,0);
if (device == INVALID_HANDLE_VALUE)
{
printf("coworker demo: Open device failed.\r\n"); int VAKb;
scanf_s("%d", &VAKb);
return -1;
}
else
printf("coworker demo: Open device successfully.\r\n");
/////// // 这里开始,其实是对驱动的一系列测试。分配3个字符串:
// 1.长度为0.应该可以正常输入。
// 2.长度为511字节,应该可以正常输入。
// 3.长度为512字节,应该返回失败。
// 4.长度为1024字节的字符串,但声明缓冲区长度为128,应该返回失败。
// 5.第一次读取,应该读出msg的内容。
// 5.第一次读取,应该读出长度为511字节的字符串。
// 6.第二次读取,应该读出长度为0的字符串。
do {
if (!DeviceIoControl(device, CWK_DVC_SEND_STR, msg, strlen(msg) + 1, NULL, 0, &ret_len, 0))
{
printf("coworker demo: Send message failed.\r\n");
ret = -2;
}
else
printf("发送信息:%s\n", msg); if (DeviceIoControl(device, CWK_DVC_RECV_STR, NULL, 0, tst_msg, 1024, &ret_len, 0) == 0)
{
ret = -6;
break;
}
else
{
printf("收到的信息:%s\r\n",tst_msg);
}
} while (0); ///////
CloseHandle(device);
int VAKb;
scanf_s("%d", &VAKb);
return ret;
}

虚拟机内可能无法运行。解决方法:选择静态编译。项目属性-配置属性-C/C+±代码生成-运行库-多线程调试(/MTd)。


测试图例:

Windows7下驱动开发与调试体系构建——2.R3与R0的通信示例的更多相关文章

  1. Windows7下驱动开发与调试体系构建——0.概述

    本文集内容为windows7x64下驱动开发与调试体系构建,内容目录如下: 1.驱动开发的环境准备 2.R3与R0的通信示例 3.自建调试体系概述 4.在x64下使用汇编代码 5.实战反调试标记位(N ...

  2. Windows7下驱动开发与调试体系构建——3.调试体系概述

    目录/参考资料:https://www.cnblogs.com/railgunRG/p/14412321.html 调试体系概述 0.什么是自建调试体系? 就是复写windows的调试api,使得调试 ...

  3. Windows7下驱动开发与调试体系构建——1.驱动开发的环境准备

    目录/参考资料:https://www.cnblogs.com/railgunRG/p/14412321.html 系统基础环境 开发环境 win7下开发驱动需要安装vs,这里使用2017. 安装vs ...

  4. Windows7下驱动开发与调试体系构建——5.实战反调试标记位(NtGlobalFlag)

    目录/参考资料:https://www.cnblogs.com/railgunRG/p/14412321.html <加密与解密>P670中,介绍了检查程序是否被调试的第二种方法:查看进程 ...

  5. Windows7下驱动开发与调试体系构建——4.在x64下使用汇编代码(x86下的_asm)

    目录/参考资料:https://www.cnblogs.com/railgunRG/p/14412321.html asm文件设置 在vs x64中无法使用_asm关键字,需要使用.asm文件. 按第 ...

  6. 2013-6-2 [转载自CSDN]如何入门Windows系统下驱动开发

    [序言]很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资料少有关系.大多学的驱动开发资料都以英文为主,这样让很多驱动初学者很头疼.本人从事驱动开发时间不长也不短,大概 ...

  7. 如何正确入门Windows系统下驱动开发领域?

    [作者]猪头三个人网站 :http://www.x86asm.com/ [序言]很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资料少有关系.大多学的驱动开发资料都以英文 ...

  8. 驱动开发 - WDK 调试及 SVN 环境搭建

    由于从公司辞职了,所以以前在公司里搭建的驱动开发环境也就 Game Over 了, 同样由于那环境是很久以前搭建的,自己也有很多记不清楚的地方了, 而且其中还是有很多需要注意的地方的,所以在这里顺便做 ...

  9. Windows7下QT5开发环境搭建 分类: QT开发 2015-03-09 23:44 65人阅读 评论(0) 收藏

    Windows7下QT开法环境常见搭配方法有两种. 第一种是:QT Creator+QT SDK: 第二种是:VS+qt-vs-addin+QT SDK: 以上两种均可,所需文件见QT社区,QT下载地 ...

随机推荐

  1. 算法模板:C++的高精度

    代码是抄别人的:https://blog.csdn.net/code4101/article/details/38705155. 这篇博客只是用来查看保存,非原创. #include<iostr ...

  2. 刷题记录:Codeforces Round #724 (Div. 2)

    Codeforces Round #724 (Div. 2) 20210713.网址:https://codeforces.com/contest/1536. div2明显比div3难多了啊-只做了前 ...

  3. 「CCO 2017」专业网络

    Kevin 正在一个社区中开发他的专业网络.不幸的是,他是个外地人,还不认识社区中的任何人.但是他可以与 N 个人建立朋友关系 . 然而,社区里没几个人想与一个外地人交朋友.Kevin 想交朋友的 N ...

  4. MySQL数据库如何线上修改表结构

    一.MDL元数据锁 在修改表结构之前,先来看下可能存在的问题. 1.什么是MDL锁 MySQL有一个把锁,叫做MDL元数据锁,当对表修改的时候,会自动给表加上这把锁,也就是不需要自己显式使用. 当对表 ...

  5. KingbaseES 工具sys_dump,sys_restore使用介绍

    说明: KingbaseES V8R6版本中自带数据库备份导出sys_dump,和备份恢复sys_restore工具. sys_dump:把KingbaseES数据库抽取为一个脚本文件或其他归档文件. ...

  6. Batch Norm 与 Layer Norm 比较

    一.结论 Batch Norm一般用于CV领域,而Layer Norm一般用于NLP领域 Batch Norm需要计算全局平均,而Layer Norm不需要计算全局平均 二.Batch Norm Ba ...

  7. 【Shashlik.EventBus】.NET 事件总线,分布式事务最终一致性

    [Shashlik.EventBus].NET 事件总线,分布式事务最终一致性 简介 github https://github.com/dotnet-shashlik/shashlik.eventb ...

  8. paddleocr安装与图片识别快速开始

    本文首发我的个人博客:paddleocr安装教程快速开始 1. 安装Python环境 wget https://mirrors.huaweicloud.com/python/3.8.5/Python- ...

  9. 干货分享|使用 Istio 实现灰度发布

    Kubernetes 作为基础平台,提供了强大的容器编排能力.但是在其上部署业务和服务治理上,仍然会面对一些复杂性和局限性.在服务治理上,已经有许多成熟的 ServiceMesh 框架用于扩充其能力, ...

  10. 在logstash中启动X-Pack Management功能后配置logstash的情况说明

    开启X-Pack Management功能后,启动logstsh的时候就不用再配置logstash.conf文件了,启动的时候也不用再使用-f指定这个文件进行启动了 一旦启动了logstash的集中管 ...