内核DLL编写
导出驱动程序缺少很多完整内核模式驱动应该有的特征。
(1) 可以为 IRP 处理提供支持例程, 但它不接收 IRP, 所以它不包含派遣例程.
(2) 不存在设备堆栈中
(3) 在服务控制管理器中没有入口点函数(不作为系统服务)
(4) 它确实有 DriverEntry 例程, 但仅仅是为了使代码能编译通过而已, 不被调用
(注: 程序编译时 bufferoverflowk.lib 中的 GsDriverEntry 例程引用了我们当前项目中的 DirverEntry 例程, 所以如果不定义 DirverEntry, 程序不能通过。 类似于 MSVCRTD.lib 中的 __tmainCRTStartup 引用了 main, 如果我们在C语言中把 main 给去掉了,结果同样是不能编译通过 )
标准驱动程序也可以作为导出驱动程序使用, 不过该驱动程序必须用导出驱动的方法 build, 按照标准驱动程序的方法加载.
构建方法:
(1) 给 TARGETTYPE 赋值为 EXPORT_DRIVER
TARGETTYPE = EXPORT_DRIVER
(2) 可以使用 DLLDEF 宏指定导出模块定义文件
DLLDEF="c:/export_drv_test/driver.def"
导出模块列表为编译器和连接器提供了导出例程信息.
(3) 在导出函数前面加 DECLSPEC_EXPORT
(4) 编译后 生成文件 Export*.lib 和 Export*.sys 文件
导入函数:
在导入函数的前面加上 DECLSPEC_IMPORT.
导出驱动程序必须安装在 %SystemRoot%/system32/drivers 目录中.在 windows NT 4.0中, 导出驱动程序一旦被加载则只有在系统关闭时才被卸载. Windows 2000 以后, 系统保存着一个引用计数, 这个引用计数表示导出驱动程序的函数被其他驱动函数导入的次数。当每个导入了函数的驱动程序被卸载时OS 就减少引用计数。 如果引用计数为0, OS 卸载导出驱动程序.
导出驱动程序必须包含标准的入口点例程 DllInitialize 和卸载例程 DllUnload. 否则引用计数的机制不会起作用. 没有这 2 个例程导出驱动程序一但被加载则只有在系统关闭时才能卸载.
上面的信息参考了 DDK, 参考下面代码和注释,可以发现上面某些信息不太准确.
导出驱动程序例子源码:
/*================================================================================
KernelDLL.cpp
================================================================================*/
/**************************************************************************************************/
/* */
/* */
/* Notes: */
/* 1) It is not strictly necessary for the executable to be located under the directory */
/* %systemroot%/system32/drivers. It will work if the executable is located in the */
/* same place as that for the driver that causes the DLL to be loaded. Neither is the */
/* DLLDEF statement necessary in the soources file. */
/* */
/* 2) This kernel DLL will be loaded automagically by the OS when the first driver */
/* importing from this DLL is about to be loaded. The DLL will be unloaded by the OS */
/* when the last importing driver has been unloaded. */
/* */
/* 3) For unloading to be done, both DllInitialize() and DllUnload() must be present and */
/* defined in KernelDLLRtns.def. */
/* */
/**************************************************************************************************/
#ifdef __cplusplus // C++ conversion.
extern "C"
{
#endif // End #ifdef C++ conversion.
#include <ntddk.h>
#ifdef __cplusplus // C++ conversion.
}
#endif // End #ifdef C++ conversion.
//***************************************************************************//
// //
// Routine prototypes. //
// //
//***************************************************************************//
/**************************************************************************************************/
/* */
/* DriverEntry */
/* */
/* Notes: */
/* 1) DriverEntry() is required for linking but is never invoked. DllInitialize() and */
/* DllUnload() instead are invoked when the DLL is loaded and unloaded, respectively. */
/* */
/**************************************************************************************************/
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)
{
return STATUS_SUCCESS;
}
/**************************************************************************************************/
/* */
/* Test routine that will be imported and invoked by CallKernelDLL.sys. */
/* */
/**************************************************************************************************/
__declspec(dllexport) NTSTATUS KernelDLLRtnsTest( PDEVICE_OBJECT pDevObj )
{
NTSTATUS status = STATUS_SUCCESS;
DbgPrint(("ExportFun is Called! KernelDLLRtnsTest()/n"));
return status;
}
/**************************************************************************************************/
/* */
/* Routine that is invoked when the DLL is loaded. */
/* */
/* Notes: */
/* 1) Support for this routine appeared in Win2K. */
/* 2) The presence of DllInitialize() and DllUnload() allows the DLL to be unloaded. */
/* */
/**************************************************************************************************/
extern "C" NTSTATUS DllInitialize( PUNICODE_STRING pRegistryPath )
{
NTSTATUS status = STATUS_SUCCESS;
/* COMMONLY INITIALIZE RESOURCES REQUIRED BY OTHER ROUTINES */
DbgPrint(("DllInitialize() is CALLED /n"));
return status;
}
/**************************************************************************************************/
/* */
/* Routine that is invoked when the DLL is unloaded. */
/* */
/* Notes: */
/* 1) Support for this routine appeared in Win2K. */
/* 2) The presence of DllInitialize() and DllUnload() allows the DLL to be unloaded. */
/* */
/**************************************************************************************************/
extern "C" NTSTATUS DllUnload()
{
NTSTATUS status = STATUS_SUCCESS;
DbgPrint(("DllUnload() is CALLED/n"));
return status;
}
/*================================================================================
Sources
================================================================================*/
TARGETNAME=KernelDLL
#TARGETPATH=../lib$(BUILD_ALT_DIR)
TARGETPATH=lib
TARGETTYPE=EXPORT_DRIVER # SET TYPE OF DRIVER: EXPORT FUNCS
DLLDEF="KernelDLLRtns.def" # IT IS NOT NECCESOORY TO HAVE THIS STATEMENT. BY DEFAULT, DEL FILE IS "KernelDLL.def" .
USER_C_FLAGS=$(USER_C_FLAGS) /FAsc
# pick up definitions from external environment
C_DEFINES=$(C_DEFINES)
#
# set up Visual C++ source browsing
#
BROWSER_INFO=1
BROWSERFILE=$(TARGETNAME).bsc -n
INCLUDES=$(BASEDIR)/inc/ddk/wxp
SOURCES= /
KernelDLL.cpp /
/*================================================================================
KernelDLL.def
================================================================================*/
NAME KernelDLL.sys
EXPORTS
; They act to ensure that these 2 routines are known to the OS, with the result that the kernel DLL can be unloaded.
DllInitialize private
DllUnload private
/*================================================================================
makefile
================================================================================*/
!INCLUDE $(NTMAKEENV)/makefile.def