Windows内核驱动中使用new和delete
2021-07-01
387
1
在Windows驱动中如果要分配内存,我们使用的ExAllocatePoolWithTag,ExAllocatePool,而释放内存时使用的是ExAllocatePoolWithTag和ExFreePool函数。
我们知道,在内核中其实不是不能用C++,而是使用时有很大的限制。如果稍不留神,就会掉进坑里,这时问题其实是很难查的,所以一般情况下我们直接使用C语言编程。但随着驱动的复杂和微软为了加速音视频等,应用层的接口全部换成了COM接口,这样直接导致了驱动就必须直接使用C++来编程。
使用C++编程,首先要解决的一个问题就是内存的分配与释放,这时就必须解决的是new和delete运算符的重载。
这里我们提供一段示例代码,分别实现了new new[],delete,delete[]的重载。
#pragma code_seg("PAGE")
//
// New and delete operators
//
_When_((PoolType & NonPagedPoolMustSucceed) != 0,
__drv_reportError("Must succeed pool allocations are forbidden. "
"Allocation failures cause a system crash"))
void* __cdecl operator new(size_t Size, POOL_TYPE PoolType)
{
PAGED_CODE();
Size = (Size != 0) ? Size : 1;
void* pObject = ExAllocatePoolWithTag(PoolType, Size, BDDTAG);
#if DBG
if (pObject != NULL)
{
RtlFillMemory(pObject, Size, 0xCD);
}
#endif // DBG
return pObject;
}
_When_((PoolType & NonPagedPoolMustSucceed) != 0,
__drv_reportError("Must succeed pool allocations are forbidden. "
"Allocation failures cause a system crash"))
void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType)
{
PAGED_CODE();
Size = (Size != 0) ? Size : 1;
void* pObject = ExAllocatePoolWithTag(PoolType, Size, BDDTAG);
#if DBG
if (pObject != NULL)
{
RtlFillMemory(pObject, Size, 0xCD);
}
#endif // DBG
return pObject;
}
void __cdecl operator delete(void* pObject)
{
PAGED_CODE();
if (pObject != NULL)
{
ExFreePool(pObject);
}
}
void __cdecl operator delete[](void* pObject)
{
PAGED_CODE();
if (pObject != NULL)
{
ExFreePool(pObject);
}
}
其实从代码来看,new和delete运算符的重载只是对ExAllocatePoolWithTag和ExFreePool函数的包装,其本质还是调用的是Windows内核提供的内存分配和释放函数。
new使用示例:
BASIC_DISPLAY_DRIVER* pBDD = new(NonPagedPoolNx) BASIC_DISPLAY_DRIVER(pPhysicalDeviceObject);
if (pBDD == NULL)
{
BDD_LOG_LOW_RESOURCE0("pBDD failed to be allocated");
return STATUS_NO_MEMORY;
}
delete使用示例:
BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
if (pBDD)
{
delete pBDD;
pBDD = NULL;
}
调式模式下堆内存的0xcdcdcdcd
这里说明一下,在dbg模式下,将分配的内存全部置为0xcd,这和应用层在调试模式下堆的内存初始化为致。
0xcd其实这里是int指令的指令,再配合一个cd,就变成了int cd,说明直接行的是中断0xcd,这样CPU执行到此处就会出现中断异常。这和栈上的0xcc,int3的原理一致。
这里附一段相关反汇编指令代码:
00CC0100 CC int 3
00CC0101 CD 05 int 5
00CC0103 CD CD int 0CDh
00CC0105 CD CD int 0CDh
新代码
void* __cdecl operator new(size_t size)
{
return ExAllocatePoolWithTag(NonPagedPool, size, 'yTag');
}
void __cdecl operator delete(void* p,size_t a)
{
ExFreePool(p);
}
void* __cdecl operator new[](size_t size)
{
return ExAllocatePoolWithTag(NonPagedPool, size, 'yTag');
}
void __cdecl operator delete[](void* p)
{
ExFreePool(p);
}
class CBase
{
public:
int a;
};
CBase* p = (CBase*)new CBase(); //operator new(size_t size)
p->a = 10;
delete p; //void __cdecl operator delete(void* p,size_t a)