<学习笔记>Windows驱动开发技术详解__Windows内存管理

Windows 驱动开发:借壳通信技术实践详解 本文详细介绍了 Windows 驱动开发中的借壳通信技术,通过示例代码展示了如何使用 ObReferenceObjectByName 函数实现借壳通信以及如何处理 IRP 控制请求。同时,我们回答了关于驱动对象类型、保存原有处理函数以及处理 IRP 控制请求的问题。希望本文能够帮助您更好地理解和应用借壳通信技术。 阅读详情

作为开发Windows驱动程序的程序员,需要比普通程序员更多了解Windows内部的内存管理机制,并在驱动程序中有效地使用内存。在驱动程序的编写中,分配和管理内存不能使用熟知的Win32 API函数,取而代之的是DDK提供的高效内核函数。C语言和C++中大多数关于内存操作的运行时函数,大多在内核模式下是无法使用的。例如,C语言中的malloc函数和C++中的new操作符等。

 

内存管理的概念:

 

1.物理内存:

PC上有三条总线,分别是数据总线,地址总线和控制总线。32位的CPU寻址能力是4GB。用户最多可以使用4GB的真实物理内存。PC中会拥有许多设备,其中很多设备都拥有自己的设备内存,这部分的设备内存会映射到PC机的物理内存上,读写这段物理地址其实会读写设备内存地址。

 

2虚拟内存:

.虽然可以寻址4GB的内存,而PC里往往没有如此多的真实物理内存。操作系统和硬件为使用者提供了虚拟内存的概念。虚拟内存和物理内存之间的转换暂不讨论。

 

3.用户模式地址和内核模式地址:

虚拟地址在0~0X7FFFFFFF范围内的虚拟内存,即低2GB的虚拟地址,被称为用户模式地址。而0X80000000~0XFFFFFFFF范围内的虚拟内存,即高2GB的虚拟内存,被称为内核模式地址。

 

4.Windows驱动程序和进程的关系:

驱动程序可以看成一个特殊的DLL文件被应用程序加载到虚拟内存中,只不过加载地址是内核模式地址,而不是用户模式地址。

 

5.分页和非分页内存:

Windows规定有些虚拟内存页面是可以交换到文件中的,这类内存成为分页内存。而有些虚拟内存页永远不会交换到文件中,这些内存被称为非分页内存。

当程序的中断请求级在DISPATCH_LEVEL之上时,程序只能使用非分页内存,否则会导致蓝屏死机。

在编译DDK提供的例程时,可以指定某个例程和某个全局变量是载入分页内存还是非分页内存,需要做如下定义:

[cpp]  view plain  copy
  1. #define PAGEDCODE code_seg("PAGE")  
  2. #define LOCKEDCODE code_seg()  
  3. #define INITCODE code_seg("INIT")  
  4.   
  5. #define PAGEDDATA data_seg("PAGE")  
  6. #define LOCKEDDATA data_seg()  
  7. #define INITDATA data_seg("INIT")  


如果将某个函数在入到分页内存,我们需要在函数的实现中加入如下代码:

[cpp]  view plain  copy
  1. #pragma INITCODE  
[cpp]  view plain  copy
  1. VOID SomeFunction()  
  2. {  
  3.       PAGED_CODE();  
  4.       //do something  
  5. }  

如果要让程序加载到非分页内存,需要在函数的实现中加入如下代码:

[cpp]  view plain  copy
  1. #pragma LOCKEDCODE  
  2. VOID SomeFunction()  
  3. {  
  4.       //do something  
  5. }  

还有一种特殊情况,就是某个例程初始化的时候载入内存,然后就可以从内存中卸载掉,例如DriverEntry

[cpp]  view plain  copy
  1. #pragma INITCODE  
  2. extern "C" NTSTATUS DriverEntry(  
  3.                            IN PDRIVER_OBJECT pDriverObject,  
  4.             IN PUNICODE_STRING pRegistryPath  
  5.                              )  
  6. {  
  7.   
  8. }  


 

6.内存的分配:

Windows驱动程序使用的内存资源非常珍贵,局部变量是在栈(stack)空间中,但是驱动程序的栈空间不会像应用程序那么大,所以不适合进行递归调用或者局部变量是大型的结构体,否则请在堆(Heap)中申请。

堆中申请内存的函数有以下几个:

[cpp]  view plain  copy
  1. PVOID   
  2. ExAllocatePool(  
  3.         IN POOL_TYPE PoolType,   
  4.         IN SIZE_T NumberOfBytes  
  5.         );  
  6.   
  7. PVOID   
  8. ExAllocatePoolWithTag(  
  9.         IN POOL_TYPE PoolType,   
  10.         IN SIZE_T NumberOfBytes,   
  11.         IN ULONG Tag   
  12.         );  
  13.   
  14. PVOID   
  15. ExAllocatePoolWithQuota(   
  16.         IN POOL_TYPE PoolType,  
  17.         IN SIZE_T NumberOfBytes   
  18.         );  
  19.   
  20. PVOID   
  21. ExAllocatePoolWithQuotaTag(  
  22.         IN POOL_TYPE PoolType,  
  23.         IN SIZE_T NumberOfBytes,  
  24.         IN ULONG Tag   
  25.         );  


其中有些重要的参数:

PoolType: 是个枚举变量,如果此值为NonPagedPool,则分配非分页内存。如果次值为PagedPool,则分配内存分页内存。

NumberOfBytes:是分配内存的大小,注意最好是4的倍数。

以上四个函数功能类似,函数以WithQuota结尾的代表分配的时候按额分配。以WithTag结尾的函数和ExAllocatePool功能类似,唯一不同的是多了一个Tag参数,

系统要求的内存外又额外地多分配4个字节的标签。在调试的时候,可以找出是否有标有这个标签的内存没有被释放。

 

将分配的内存,进行回收的函数原型如下:

[cpp]  view plain  copy
  1. VOID  
  2. ExFreePool(   
  3.     IN PVOID P  
  4.          );  
  5.   
  6. NTKERNELAPI  
  7. VOID  
  8. ExFreePoolWithTag(  
  9.     IN PVOID P,  
  10.     IN ULONG Tag  
  11.   );  


参数P就是要释放的内存。

 

在内存中使用链表:

链表中可以记录整形,浮点型,字符型或者程序员自定义的数据结构。对于单链表,元素中有一个Next指针指向下一个元素。对于双链表,每个元素有两个指针:BLINK指向前一个元素,FLINK指向下一个元素。

 

1.链表的结构:

DDK提供了标准的双向链表。双向链表可以将链表形成一个环。以下是DDK提供的双向链表的数据结构:

[cpp]  view plain  copy
  1. typedef struct _LIST_ENTRY {  
  2.    struct _LIST_ENTRY *Flink;  
  3.    struct _LIST_ENTRY *Blink;  
  4. } LIST_ENTRY, *PLIST_ENTRY  


这个结构体只有指针没有数据。

 

2.链表的初始化:

每个双向链表都是以链表头作为链表的第一个元素。初次使用链表头需要进行初始化,主要将链表头的Flink和Blink两个指针都指向自己。初始化链表头用InitiallizeListHead宏实现。判断链表头是否为空,DDK提供了一个宏简化这种检查,这就是IsListEmpty。

[cpp]  view plain  copy
  1. IsListEmpty(&head);  


程序员需要自己定义链表中每个元素的数据类型,并将LIST_ENTRY结构作为自定义结构的一个子域。例如:

[cpp]  view plain  copy
  1. typedef struct _MYDATASTRUCT  
  2. {  
  3.     LIST_ENTRY ListEntry;  
  4.     ULONG x;  
  5.     ULONG y;  
  6. }MYDATASTRUCT,*PMYDATASTRCUT;  


3.插入链表:

对链表的插入有两种方式,一种是在链表的头部插入,一种是在链表的尾部插入。

在头部插入链表使用语句InsertHeadList,用法如下:

[cpp]  view plain  copy
  1. InsertHeadList(&head,&mydata->ListEntry);  


在尾部插入链表使用语句InsertTailList,用法如下:

[cpp]  view plain  copy
  1. InsertTailList(&head,&mydata->ListEntry);  

 

4.链表的删除:

和插入链表一样,删除链表也有两种方法。一种从头部删除,一种从尾部删除。分别对应RemoveHeadList和RemoveTailList函数。其使用方法如下:

[cpp]  view plain  copy
  1. PLIST_ENTRY = RemoveHeadList(&head);  
  2.   
  3. PLIST_ENTRY = RemoveTailList(&head);  


 

下面代码完整演示向链表进行插入,删除等操作,其主要代码如下:

[cpp]  view plain  copy
  1. typedef struct _MYDATASTRUCT  
  2. {  
  3.     ULONG number;  
  4.     LIST_ENTRY ListEntry;  
  5. }MYDATASTRUCT,*PMYDATASTRCUT;  
  6.   
  7. #pragma INITCODE  
  8. VOID LinkListTest()  
  9. {  
  10.     LIST_ENTRY linkListHead;  
  11.     //初始化链表  
  12.     InitializeListHead(&linkListHead);  
  13.       
  14.     PMYDATASTRCUT pData;  
  15.     ULONG i = 0;  
  16.     //在链表中插入10个元素  
  17.   
  18.     KdPrint(("Begain insert to link list"));  
  19.     for (i = 0 ; i < 10 ; i++)  
  20.     {  
  21.         pData = (PMYDATASTRCUT)  
  22.                  ExAllocatePool(PagedPool,sizeof(MYDATASTRUCT));  
  23.         pData->number = i;  
  24.         InsertHeadList(&linkListHead,&pData->ListEntry);  
  25.     }  
  26.     //从链表中取出,并显示  
  27.     KdPrint(("Begain remove from link list\n"));  
  28.     while (!IsListEmpty(&linkListHead))  
  29.     {  
  30.         PLIST_ENTRY pEntry = RemoveTailList(&linkListHead);  
  31.         pData = CONTAINING_RECORD(pEntry,  
  32.                           MYDATASTRUCT,  
  33.                           ListEntry);  
  34.         KdPrint(("%d\n",pData->number));  
  35.         ExFreePool(pData);  
  36.     }  
  37. }  


在DebugView中打印log信息:

 

Lookaside结构:

频繁申请和回收内存,会导致在内存上产生大量的内存“空洞”,从而导致最终无法申请内存。DDK为程序员提供了Lookaside结构来解决这个问题。

 

1.使用Lookaside:

Lookaside一般会在一下情况使用:

(1)程序员每次申请固定大小的内存

(2)申请和回收的操作十分频繁

使用Lookaside对象,首先要初始化Lookaside对象,有以下两个函数可以使用:

[cpp]  view plain  copy
  1. VOID  
  2. ExInitializeNPagedLookasideList(  
  3.             IN PNPAGED_LOOKASIDE_LIST Lookaside,   
  4.             IN PALLOCATE_FUNCTION Allocate,   
  5.             IN PFREE_FUNCTION Free,  
  6.             IN ULONG Flags,   
  7.             IN SIZE_T Size,  
  8.             IN ULONG Tag,  
  9.             IN USHORT Depth   
  10.             );  
  11.   
  12. VOID  
  13. ExInitializePagedLookasideList(   
  14.             IN PPAGED_LOOKASIDE_LIST Lookaside,  
  15.             IN PALLOCATE_FUNCTION Allocate,   
  16.             IN PFREE_FUNCTION Free,   
  17.             IN ULONG Flags,  
  18.             IN SIZE_T Size,  
  19.             IN ULONG Tag,  
  20.             IN USHORT Depth  
  21.             );  


这两个函数分别对非分页和分页Lookaside对象进行初始化。

在初始化完Lookaside对象后,可以进行申请内存的操作了,有以下两个函数:

[cpp]  view plain  copy
  1. PVOID  
  2. ExAllocateFromNPagedLookasideList(  
  3.             IN PNPAGED_LOOKASIDE_LIST Lookaside   
  4.                   );  
  5.   
  6. PVOID  
  7. ExAllocateFromPagedLookasideList(  
  8.             IN PPAGED_LOOKASIDE_LIST Lookaside  
  9.                  );  


这两个函数分别是对非分页和分页内存的申请。

对Lookaside对象进行回收内存的操作,有以下两个函数:

[cpp]  view plain  copy
  1. VOID  
  2. ExFreeToNPagedLookasideList(   
  3.                 IN PNPAGED_LOOKASIDE_LIST Lookaside,  
  4.                 IN PVOID Entry  
  5.                 );  
  6.   
  7. VOID  
  8. ExFreeToPagedLookasideList(   
  9.                 IN PPAGED_LOOKASIDE_LIST Lookaside,  
  10.                 IN PVOID Entry   
  11.                 );  

这两个函数分别是对非分页和分页内存的回收。

在使用完Lookaside对象后,需要删除Lookaside对象,有以下两个函数:

[cpp]  view plain  copy
  1. VOID  
  2. ExDeleteNPagedLookasideList(  
  3.                 IN PNPAGED_LOOKASIDE_LIST Lookaside  
  4.                 );  
  5.   
  6. VOID  
  7. ExDeletePagedLookasideList(   
  8.                 IN PPAGED_LOOKASIDE_LIST Lookaside  
  9.                 );  


下面代码完整展示Lookaside对象的使用:

[cpp]  view plain  copy
  1. #pragma INITCODE  
  2. VOID LookasideTest()  
  3. {  
  4.     //初始化Lookaside对象  
  5.     PAGED_LOOKASIDE_LIST pageList;  
  6.     ExInitializePagedLookasideList(&pageList,  
  7.                                  NULL,NULL,0,  
  8.                                  sizeof(MYDATASTRUCT),  
  9.                                  '1234',  
  10.                                  0);  
  11. #define ARRAY_NUMBER 50  
  12.     PMYDATASTRUCT MyObjectArray[ARRAY_NUMBER];  
  13.     //模拟频繁申请内存  
  14.     for (int i = 0 ; i < ARRAY_NUMBER ; i++)  
  15.     {  
  16.         MyObjectArray[i] =   
  17.             (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&pageList);  
  18.     }  
  19.     //模拟频繁回收内存  
  20.     for (i = 0 ; i < ARRAY_NUMBER ; i++)  
  21.     {  
  22.         ExFreeToPagedLookasideList(&pageList,MyObjectArray[i]);  
  23.         MyObjectArray[i] = NULL;  
  24.     }  
  25.     //删除Lookaside对象  
  26.     ExDeletePagedLookasideList(&pageList);  
  27. }  


运行时函数:

 

1.内存间复制(非重叠)

在驱动程序开发中,经常用到内存的复制。DDK为程序员提供了以下函数:

[cpp]  view plain  copy
  1. VOID  
  2. RtlCopyMemory(   
  3.         IN VOID UNALIGNED *Destination,   
  4.         IN CONST VOID UNALIGNED *Source,   
  5.         IN SIZE_T Length  
  6.         );  

Destination:表示要复制内存的目的地址

Source:表示要复制内存的源地址

Length:表示要复制内存的长度,单位是字节

 

2.内存间的复制(可重叠)

函数原型:

[cpp]  view plain  copy
  1. VOID  
  2. RtlMoveMemory(   
  3.         IN VOID UNALIGNED *Destination,  
  4.         IN CONST VOID UNALIGNED *Source,   
  5.         IN SIZE_T Length  
  6.         );  

Destination:表示要复制内存的目的地址

Source:表示要复制内存的源地址

Length:表示要复制内存的长度,单位是字节

 

3.内存填充:

驱动程序开发中,还经常用到对某段内存区域用固定字节填充。DDK为程序员提供了函数RtlFillMemory。它在IA32平台下也是个宏,实际是memset函数。

[cpp]  view plain  copy
  1. VOID  
  2. RtlFillMemory(   
  3.        IN VOID UNALIGNED *Destination,   
  4.        IN SIZE_T Length,  
  5.        IN UCHAR Fill  
  6.        );  


Destination:目的地址

Length:长度

Fill:需要填充的字节

 

在驱动开发中,还经常需要对某段内存填零,DDK提供的宏是RtZeroBytes和RtZeroMemory。

[cpp]  view plain  copy
  1. VOID  
  2. RtlZeroMemory(  
  3.        IN VOID UNALIGNED *Destination,   
  4.        in SIZE_T Length  
  5.        );  


Destination:目的地址

Length:长度

 

4.内存比较:

驱动开发中,还会用到比较两块内存是否一致。该函数是RtlCompareMemory,其申明是:

[cpp]  view plain  copy
  1. ULONG  
  2. RtlEqualMemory(  
  3.       CONST VOID *Source1,  
  4.       CONST VOID *Source2  
  5.       SIZE_T Length  
  6.        );  

Source1:比较的第一个内存地址

Source2:比较的第二个内存地址
Length:比较的长度,单位为字节

 

将这些运行时函数统一做一个实验,代码如下:

[cpp]  view plain  copy
  1. #define BUFFER_SIZE 1024  
  2. #pragma INITCODE  
  3. VOID RtTest()  
  4. {  
  5.     PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);  
  6.     //用零填充内存  
  7.     RtlZeroMemory(pBuffer,BUFFER_SIZE);  
  8.   
  9.     PUCHAR pBuffer2 = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);  
  10.     //用固定字节填充内存  
  11.     RtlFillMemory(pBuffer,BUFFER_SIZE,0xAA);  
  12.   
  13.     //内存拷贝  
  14.     RtlCopyMemory(pBuffer,pBuffer2,BUFFER_SIZE);  
  15.   
  16.     //判断内存是否一致  
  17.     ULONG ulRet = RtlCompareMemory(pBuffer,pBuffer2,BUFFER_SIZE);  
  18.     if (ulRet == BUFFER_SIZE)  
  19.     {  
  20.         KdPrint(("The two blocks are same\n"));  
  21.     }  
  22. }  
Windows系统漏洞修复全攻略:从原理到实战的完整指南 系统漏洞是软件在逻辑设计或代码实现上的缺陷,攻击者可利用其执行非授权操作。其修复原理在于通过补丁程序修正这些缺陷,以消除潜在的安全风险。及时修复漏洞的技术价值在于构建安全基线,是纵深防御体系的关键环节,能有效防范勒索软件、权限提升等网络攻击。在应用场景上,无论是个人电脑还是企业服务器,都需要建立涵盖漏洞评估、补丁管理、故障排查的系统性流程。本文聚焦Windows系统,深入解析其漏洞生命周期、补丁类型及手动与自动修复策略,并探讨了利用WSUS进行企业级补丁管理和第三方软件漏洞的应对方案,旨在帮助用户建立持续安 阅读详情

相关推荐

CVE-2019-0708漏洞复现:从RDP协议原理到实战攻防

远程桌面协议(RDP)作为远程访问的核心技术,其安全性直接关系到系统命脉。协议栈中虚拟通道的内存管理机制若存在缺陷,可引发严重的远程代码执行漏洞。理解此类漏洞的原理,不仅能揭示攻击者如何利用内存越界或释放后重用(UAF)等底层错误实现权限提升,更能为构建主动防御体系提供关键洞察。在实战场景中,通过搭建隔离的靶场环境,安全研究人员可以深入分析漏洞触发条件、利用链构造及后续渗透手法,从而将理论认知转化为有效的检测与防护规则。本文以CVE-2019-0708(BlueKeep)为例,结合【Metasploit】框

congbao6525的博客 486

Windows驱动开发技术详解第四章(驱动程序的基本结构)

重要概念 每个驱动程序都会有一个或多个设备对象 驱动程序中的每个设备对象都有一个指针指向下一个设备对象(也属于当前驱动),最后一个设备对象指向空 驱动程序中尽量不要使用全局变量,而是将全局变量定义在设备扩展里 设备对象记录通用设备的信息,另外一些特殊信息记录在设备扩展(由程序员设计)里 驱动程序中,字符串都使用UNICODE编码(16位为一个字符) 可以使用NT_SUCCESS宏来判断NTSTATUS是否为成功typedef struct _UNICODE_STRING { USHORT Length

冰糖葫芦的夏天的博客 980

Windows驱动开发深入指南

本文还有配套的精品资源,点击获取 简介:Windows驱动开发是IT领域中一项关键的技术工作,它确保操作系统与硬件设备的正确交互。本文将深入探讨Windows驱动开发的不同方面,包括Windows 2000时代的驱动模型、Windows Driver Model (WDM)、文件系统过滤驱动开发,以及驱动程序开发的环境搭建和调试技巧等。开发者将需要掌握C/C++编程,对Wi...

weixin_36382073的博客 2896

《Windows驱动开发技术详解》学习笔记_windows驱动开发技术详解 pdf

其中,native api 对应的 PE 是 ntdll.dll,其 API 一般都以 Nt开头;而“系统服务函数”对应的 PE 是 ntosknrl.exe,其 API 一般都以 Zw 开头。此外,可以通过 Dependency walker.exe 查看其导出函数。

2401_85013892的博客 1495

Windows驱动开发技术详解(pdf书+源代码)

该书是我收藏很久的一本好书,可以作为windows内核驱动开发的入门教材,我个人认为比《寒江独钓》好得多,与大家分享,希望对大家有帮助。

Windows驱动开发技术详解(含源代码)

第1篇 入门篇 第1章 从两个最简单的驱动谈起 2 本章向读者呈现两个最简单的Windows驱动程序,一个是NT式的驱动程序,另一个是WDM式的驱动程序。这两个驱动程序没有操作具体的硬件设备,只是在系统里创建了虚拟设备。在随后的章节中,它们会作为基本驱动程序框架,被本书其他章节的驱动程序开发所复用。笔者将带领读者编写代码、编译、安装和调试程序。 1.1 DDK的安装 2 1.2 第一个驱动程序HelloDDK的代码分析 3 1.2.1 HelloDDK的头文件 4 1.2.2 HelloDDK的入口函数 5 1.2.3 创建设备例程 6 1.2.4 卸载驱动例程 8 1.2.5 默认派遣例程 9 1.3 HelloDDK的编译和安装 9 1.3.1 用DDK环境编译HelloDDK 9 1.3.2 用VC集成开发环境编译HelloDDK 11 1.3.3 HelloDDK的安装 14 1.4 第二个驱动程序HelloWDM的代码分析 16 1.4.1 HelloWDM的头文件 16 1.4.2 HelloWDM的入口函数 17 1.4.3 HelloWDM的AddDevice例程 18 1.4.4 HelloWDM处理PNP的回调函数 20 1.4.5 HelloWDM对PNP的默认处理 22 1.4.6 HelloWDM对IRP_MN_REMOVE_DEVICE的处理 23 1.4.7 HelloWDM对其他IRP的回调函数 23 1.4.8 HelloWDM的卸载例程 24 1.5 HelloWDM的编译和安装 24 1.5.1 用DDK编译环境编译HelloWDM 24 1.5.2 HelloWDM的编译过程 25 1.5.3 安装HelloWDM 25 1.6 小结

Windows核心编程<读书笔记十三>Windows的内存结构

第13章 Windows的内存结构 【文起】蟹儿的鼓励和支持,以及有时候的激励,是我能坚持的源泉,爱你宝贝儿。 1、  进程的虚拟地址空间 每个进程都有自己的虚拟地址空间。32位的进程来说,地址空间为4GB()。而这 个只是虚拟地址空间,只是内存地址的一个范围,而不是真正的物理地址空间。 2、  虚拟地址空间如何分区 每个进程的虚拟地址空间都要划分为各个分区。 2.1、NULL指针分

豆浆爱蟹蟹 975

Windows驱动开发技术详解(pdf书+源代码).part1

目录 第1篇 入门篇 第1章 从两个最简单的驱动谈起 1.1 DDK的安装 1.2 第一个驱动程序HelloDDK的代码分析 1.2.1 HelloDDK的头文件 1.2.2 HelloDDK的入口函数 1.2.3 创建设备例程 1.2.4 卸载驱动例程 1.2.5 默认派遣例程 1.3 HelloDDK的编译和安装 1.3.1 用DDK环境编译HelloDDK 1.3.2 用VC集成开发环境编译HelloDDK 1.3.3 HelloDDK的安装 1.4 第二个驱动程序HelloWDM的代码分析 1.4.1 HelloWDM的头文件 1.4.2 HelloWDM的入口函数 1.4.3 HelloWDM的AddDevice例程 1.4.4 HelloWDM处理PNP的回调函数 1.4.5 HelloWDM对PNP的默认处理 1.4.6 HelloWDM对IRP_MN_REMOVE_DEVICE的处理 1.4.7 HelloWDM对其他IRP的回调函数 1.4.8 HelloWDM的卸载例程 1.5 HelloWDM的编译和安装 1.5.1 用DDK编译环境编译HelloWDM 1.5.2 HelloWDM的编译过程 1.5.3 安装HelloWDM 1.6 小结 第2章 Windows操作驱动的基本概念 第3章 Windows驱动编译环境配置、安装及调试 第4章 驱动程序的基本结构 第5章 Windows内存管理 第6章 Windows内核函数 第7章 派遣函数 第2篇 进阶篇 第8章 驱动程序的同步处理 第9章 IRP的同步 第10章 定时器 第11章 驱动程序调用驱动程序 第12章 分层驱动程序 第13章 让设备实现即插即用 第14章 电源管理 第3篇 实用篇 第15章 I/O端口操作 第16章 PCI设备驱动 第17章 USB设备驱动 第18章 SDIO设备驱动 第19章 虚拟串口设备驱动 第20章 摄像头设备驱动程序 第4篇 提高篇 第21章 再论IRP 第22章 过滤驱动程序 第23章 高级调试技巧

CVE-2020-0796永恒之黑漏洞复现:从SMBv3协议漏洞到远程代码执行实战

缓冲区溢出是软件安全领域的经典漏洞类型,其原理在于程序向固定大小的内存缓冲区写入超出其容量的数据,导致相邻内存区域被覆盖,从而可能改变程序执行流程或执行任意代码。在操作系统内核和网络服务中,这类漏洞往往能绕过常规权限检查,直接获取系统最高控制权,技术价值在于揭示了内存安全机制的重要性。SMB(服务器消息块)协议作为Windows系统中实现文件共享、打印机共享等网络功能的核心协议,其安全性格外关键。CVE-2020-0796(永恒之黑)正是SMBv3.1.1协议解压缩功能中存在的一个高危缓冲区溢出漏洞,攻击者

weixin_30376509的博客 343

【IPAM】Netbox docker模式版本升级

NETBOX 是一个开源的网络资源管理系统,主要用于管理 IP 地址、机架、设备、接口等网络资源信息。下面是 NETBOX 的功能、优点和缺点的详细介绍。

u012153104的博客 1329

stm32学习笔记-启动文件

1、配置栈 Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp EQU:相当于C中的define,定义Stack_Size = 0x00000400。 AREA: 指...

某风吾起的博客 4529

现代C++游戏引擎开发实战:从选型到性能优化的完整指南

游戏引擎是现代游戏开发的核心框架,它封装了渲染、物理、音频等底层系统,为开发者提供高效的工具链。其工作原理基于模块化架构,通过抽象硬件接口和资源管理,实现跨平台部署。掌握引擎开发技术能显著提升游戏性能与开发效率,广泛应用于AAA大作、独立游戏及移动端项目。本文聚焦C++在主流引擎中的深度应用,对比分析Unreal Engine、Godot等平台特性,详解开发环境配置、核心模块实现及性能调优策略,帮助开发者构建高性能游戏逻辑。

weixin_34082854的博客 376

保姆级教程:用Python+Mediapipe实时捕捉手势,驱动Unity虚拟手模型(附完整源码)

本文详细介绍了如何利用Python的Mediapipe库和Unity实现实时手势识别与虚拟手模型驱动。通过OpenCV进行图像采集,Mediapipe提供21个手部关键点识别,结合UDP通信协议实现Python与Unity之间的低延迟数据传输。教程包含完整源码、环境配置、核心代码实现及性能优化技巧,适用于VR教育、游戏开发等需要自然交互的场景。

weixin_42531779的博客 361

windows内核安全与驱动开发 光盘_记《Windows驱动开发技术详解》的一处坑

相对而言,市面上驱动开发的书确实不多,虽然这本书还是以Windows XP进行讲解,但它放到现在仍然是学习驱动开发的不错的选择。我碰到的问题是,第四第五章的内容,即使是用示例代码编译驱动,在安装,启动时都是正常的,但是卸载驱动,驱动执行Unload例程时,里面的IoDeleteSymbolicLink(&pDevExt->ustrSymLinkName) 时,猛然发现:预先保存在DE...

weixin_39608134的博客 366

保姆级教程:用Python+NumPy手把手模拟光学散射与记忆效应(附代码)

本文提供了一份详细的Python+NumPy教程,手把手教你模拟光学散射与记忆效应。从基础光波建模到散射介质实现,再到菲涅尔衍射和光学记忆效应验证,逐步构建完整的仿真系统。通过附带的代码示例,读者可以快速掌握计算光学仿真的核心技术,为医学成像、物理仿真等领域的研究提供实用工具。

weixin_30172941的博客 322

Proteus课设原理图及报告

1. I/O 口:32 个可编程 I/O 引脚,分成 4 个并行 I/O 端口 (P0, P1, P2, P3),P0 功能段选 a、b、c、d、e、f、g、dp 使其中部分点亮,P2 功能为位选 1、2、4.按键操作分析:P3.0-设置时钟的时间,P3.1-确定更改的时钟时间,P3.2-对。时钟设置标志 0 不设置,1 设置时,2 设置分,3 设置秒。P3.0 按下的次数对应 不设置,设置时,设置分,

2303_76688805的博客 1175

Windows驱动开发技术详解第八章(驱动程序的同步处理)

中断请求(IRQ) 中断请求分为两种: 外部中断(硬件产生的中断) 由软件指令int n产生的中断 外部中断 传统PC共可接受16个中断信号,分别对应一个中断号 外部中断分为:不可屏蔽中断(CPU的NMI引脚)和可屏蔽中断(CPU的INTR引脚) 传统CP使用Intel 8259A中断控制器向CPU发出可屏蔽中断 现代x86机器使用高级可编程中断控制器(APIC) APIC兼容传统的16个中断,共24个中断(IRQ) 每个IRQ有各自的优先级别,正在运行的线程可被IRQ打断,进入IRQ的中断处理程序

冰糖葫芦的夏天的博客 987

SAP 生产订单工序删除状态撤回简介

2、我们在前台对于生产订单的状态一个是在生产订单抬头中的状态,另外一个是针对上面一直在测试的是工序的状态,这个两个状态是前台可见的状态,实际生产订单还有一个组件物料的状态,这个状态是不可见的一个状态。生产订单中的0010工序中对应的组件的栏位被标识,表示有物料分配到了0010的工序中,正常情况下0010的工序被分配了工序是不应该被删除的。将已领料的工序删除掉,导致异常的发生。当物料已领料会,用户仍然把已分配的物料的工序删除掉,导致后续业务操作过程中产生异常,如下图中所示,0010的工序被打上了删除标识。

我小时候很黑的博客 1938

windows驱动开发技术详解_RD技术贴|说走就走的Windows

Windows To Go 制作详解1WTG简介这项功能最早推出于2011年9月,并包含在之后发布的Windows 8企业版、Windows 8.1企业版、Windows 10企业版,教育版和1607版本及之后的Windows 10专业版中。通过此功能,你可以将 Windows「浓缩」到一个 USB存储设备上并随身携带,并且由于是储存在外置设备中,所以不用担心本机的容量问题。2WTG硬件...

weixin_39516956的博客 1017

【OpenFOAM】-olaFlow-算例10-wavemakerTank

采用 Flap和Piston两种方式的动网格进行造波

ou_no的博客 2167

LeRobot 入门教程(三)在仿真环境和自定义机器人上部署 LeRobot

本教程详细介绍了基于真实世界机器人和仿真环境的模仿学习实现方法,涵盖数据采集、训练策略和评估全流程。在真实机器人部分,重点讲解了远程操作设置、摄像头配置、数据集记录与管理技巧、策略训练(支持GPU/MPS设备)以及模型评估。仿真环境部分则演示了gym-hil的安装使用、模拟数据采集和策略训练。此外,教程还提供了自定义机器人集成指南,包括电机选择、接口继承、传感器/动作特征定义、连接管理和校准配置等核心步骤。所有方法均支持HuggingFace数据集中心和Weights & Biases工具链,为机器

2506_90492529的博客 2399

Windows驱动开发技术详解第六章(Windows内核函数)

字符串操作 DDK中CHAR对应char,WCHAR对应wchar_t DDK中也是用strcpy,sprintf,strcat等操作字符串,但并不推荐使用 这些字符串操作函数被ntoskrsl.exe导出 DDK推荐使用功能相同的宏 DDK不鼓励使用C语言的字符串,建议使用ANSI_STRING和UNICODE_STRING typedef struct _STRING { USHORT Length; //字符串的长度 USHORT MaximumLength; //字符串缓冲区的最大长度 P

冰糖葫芦的夏天的博客 556

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Windows驱动开发技术详解

32位 1、高2G  内核 进程共享 2、字符串、返回类型、USHORT。。。 3、驱动对象 driver object 、设备对象 Device object, 请求 IRP。  驱动对象生成多个设备对象, 请求发给设备对象 4、 不涉及内存管理、控制台的C Runtime函数 可以使用 但是不提倡 5、开发模型  WDK 6、中断级 Dispatch > Passive 7、字

LostWiFi的博客 2548

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Windows驱动开发重要结构体详解

windows驱动开发中重要结构体

冰糖葫芦的夏天的博客 1024

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: 白话粒子群算法
下一篇: windows内核情景分析笔记------内核对于物理页面的管理
lycommand
博客等级 码龄14年 31粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值