64位内核开发第十三讲,内核下C++编程 | 您所在的位置:网站首页 › 深圳windows驱动开发培训 › 64位内核开发第十三讲,内核下C++编程 |
目录Windows内核驱动 使用 C++ 代码编程一 丶 C++在Windows内核中的使用1.1 简介1.2 头文件的引用二丶使用C++ 类2.1 介绍内核中的内存申请函数2.2 重载类中的 new delete函数2.3 使用继承以及虚函数重写父类函数2.4 使用虚析构三丶全局new delete 重构3.1 代码四丶建议
Windows内核驱动 使用 C++ 代码编程
一 丶 C++在Windows内核中的使用
1.1 简介
在驱动内核中是可以使用C++来进行编程的.只不过需要你重载一下new delete等函数 你可以看使用类 使用继承等. 但是如果是内核API的时候注意需要对其进行 C函数导出. 否则就会报解析不到名字 最好使用状态就是 c with class 使用基本的类来管理自己的函数. 比直接使用C强 1.2 头文件的引用 #pragma once #ifdef __cplusplus extern "C" { #endif #include #include #include #include #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); } 二丶使用C++ 类 2.1 介绍内核中的内存申请函数如果想在类中使用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 2.2 重载类中的 new delete函数看一下简单的代码吧. #pragma once #ifdef __cplusplus extern "C" { #endif #include #include #include #include #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输出. 最后析构. 2.3 使用继承以及虚函数重写父类函数如果定义一个类继承自父类调用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我们使用的是虚函数,重写了父类. 所以说虚函数是可以进行使用的. 2.4 使用虚析构不重复粘贴代码了.做一下说明 1.父类的析构函数前边加了关键字 virtual 2.子类的析构前边也加了关键字 virtual 调用方式同上 结果: 使用虚析构结果就是正确的了 会发现子类会被析构了.而不会直接析构父类了. 三丶全局new delete 重构 3.1 代码father中的重载代码进行删除 使用全局的new delete一样可以. void *__cdecl operator new(size_t Size, POOL_TYPE PoolType) { PAGED_CODE(); Size = (Size != 0) ? Size : 1; void *pObject = ExAllocatePoolWithTag(PoolType, Size, POOLTAG); #if DBG if (pObject != NULL) { RtlFillMemory(pObject, Size, 0xCC); } #endif // DBG return pObject; } void *__cdecl operator new[](size_t Size, POOL_TYPE PoolType) { PAGED_CODE(); Size = (Size != 0) ? Size : 1; void *pObject = ExAllocatePoolWithTag(PoolType, Size, POOLTAG); #if DBG if (pObject != NULL) { RtlFillMemory(pObject, Size, 0xCC); } #endif // DBG return pObject; } void __cdecl operator delete(void *pObject) { PAGED_CODE(); if (pObject != NULL) { ExFreePoolWithTag(pObject, POOLTAG); } } void __cdecl operator delete[](void *pObject) { PAGED_CODE(); if (pObject != NULL) { ExFreePoolWithTag(pObject, POOLTAG); } } extern "C" NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pReg) { UNREFERENCED_PARAMETER(pReg); NTSTATUS status = STATUS_UNSUCCESSFUL; pDriverObj->DriverUnload = DriverUnLoad; PCHAR pszBuffer = NULL; PWCHAR pwzBuffer = NULL; father *pFather = NULL; pszBuffer = new (NonPagedPool) CHAR[100]; pwzBuffer = new (NonPagedPool) WCHAR[100]; pFather = new (NonPagedPool) father; // check ... delete pFather; delete[] pszBuffer; delete[] pwzBuffer; return STATUS_SUCCESS; } 四丶建议 可使用 DBG宏判断是否是DBG版本下编译,如果是可以初始化内存为0XCC 作者:IBinary 出处:https://www.cnblogs.com/iBinary/坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。 详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html 本文来自博客园,作者:iBinary,未经允许禁止转载 转载前可联系本人.对于爬虫人员来说如果发现保留起诉权力.https://www.cnblogs.com/iBinary/p/15779751.html 欢迎大家关注我的微信公众号.不定期的更新文章.更新技术. 关注公众号后请大家养成 不白嫖的习惯.欢迎大家赞赏. 也希望在看完公众号文章之后 不忘 点击 收藏 转发 以及点击在看功能. QQ群: |
CopyRight 2018-2019 实验室设备网 版权所有 |