在驱动内核中是可以使用C++来进行编程的.只不过需要你重载一下new delete等函数
你可以看使用类 使用继承等. 但是如果是内核API的时候注意需要对其进行 C函数导出.
否则就会报解析不到名字 最好使用状态就是 c with class 使用基本的类来管理自己的函数.
比直接使用C强
#pragma once #ifdef __cplusplus extern "C" { #endif #include <ntifs.h> #include <ntddk.h> #include <Ntstrsafe.h> #include <ntimage.h> #ifdef __cplusplus } #endif
在引入头文件的时候使用条件宏包含以下 其中 __cplusplus 的意思是 是否使用 C++的编译方式编译.如果是后缀名为.cpp则此宏就会启作用. 那么就会加入一个 extern "C" 修饰,这样声明的时候就是使用C的方式编译了.也不会遇到解析名称错误了.
对于DriverEntry入口我们也需要进行C修饰
如一个.cpp文件中的内容如下:
extern "C" NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pReg) { UNREFERENCED_PARAMETER(pDriverObj); UNREFERENCED_PARAMETER(pReg); }
如果想在类中使用new和delete 那么我们需要重载一下new和delete 变成内核方式的内存申请. 当然如果你想写一个 string函数 那么你也可以重载 + [] ....等运算符
在内核中申请内存可以使用以下函数
ExAllocatePool ----过时 ExAllocatePoolWithTag ----在windows2004上过时 ExAllocatePool2 ExAllocatePool3 -----2 3 都是在2004 对应释放函数分别就是 ExFreePoolxxxxxx
申请的时候需要指定类型 类型如下:
类型 | 说明以及使用 | 是否常用 |
---|---|---|
NonPagedPool | 非分页内存,申请的内存是读写执行 可以执行ShellCode | 常用 |
PagedPool | 分页内存,分页内存可能会被换出,访问的时候要注意检查 | 一般 |
NonPagedPoolMustSucceed | 指定分贝非分页内存,必须成功. | 不使用 |
DontUseThisType | 未指定 | 不使用 |
NonPagePoolCacheAligned | 分配非分页内存,而且必须内存对齐 | 不使用 |
PagedPoolCacheAligned | 分页内存,必须内存对齐 | 不使用 |
NonPagedPoolCacheAlignedMustS | 非分页内存必须对齐必须成功 | 不使用 |
new的重载就是用ExAllocatePool xxx
看一下简单的代码吧.
#pragma once #ifdef __cplusplus extern "C" { #endif #include <ntifs.h> #include <ntddk.h> #include <Ntstrsafe.h> #include <ntimage.h> #ifdef __cplusplus } #endif class father { public: father(); ~father(); public: void *operator new(size_t size, POOL_TYPE poolType = NonPagedPool); void operator delete(void *pointer); public: virtual void testprint(); private: char szBuffer[1024]; };
cpp实现
#include "test.h" father::father() { DbgPrint("startfather\n"); } father::~father() { DbgPrint("endfather\n"); } void father::testprint() { DbgPrint("father\n"); } void *father::operator new(size_t size, POOL_TYPE poolType) { return ExAllocatePoolWithTag(poolType, size, 'abcd'); } void father::operator delete(void *pointer) { ExFreePoolWithTag(pointer, 'abcd'); }
使用
extern "C" NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pReg) { UNREFERENCED_PARAMETER(pReg); NTSTATUS status = STATUS_UNSUCCESSFUL; pDriverObj->DriverUnload = DriverUnLoad; father *pf = new father; pf->testprint(); delete pf; return STATUS_SUCCESS; }
使用结果:
可以看到先进行构造 然后调用testprintf输出. 最后析构.
如果定义一个类继承自父类调用testprint会怎么样?
代码如下:
class child : public father { public: child(); ~child(); public: void *operator new(size_t size, POOL_TYPE poolType = NonPagedPool); void operator delete(void *pointer); public: void testprint(); private: char szBuffer[1024]; };
使用:
extern "C" NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pReg) { UNREFERENCED_PARAMETER(pReg); NTSTATUS status = STATUS_UNSUCCESSFUL; pDriverObj->DriverUnload = DriverUnLoad; father *pf = new child; pf->testprint(); delete pf; return STATUS_SUCCESS; }
结果
少了一次析构 child没有进行析构 testprintf我们使用的是虚函数,重写了父类. 所以说虚函数是可以进行使用的.
不重复粘贴代码了.做一下说明
1.父类的析构函数前边加了关键字 virtual
2.子类的析构前边也加了关键字 virtual
调用方式同上
结果:
使用虚析构结果就是正确的了 会发现子类会被析构了.而不会直接析构父类了.