发信人: fist (星仔迷), 信区: SysInternals WWW-POST
标 题: Kernel Dll的范例(1)
发信站: 武汉白云黄鹤站 (Mon Jul 2 15:11:09 2001) , 转信
目录
1。建立文件
2。编译
3。启动和测试
4。问题与解决方法
内容:
--------------------------------------------------------------------------------
1。建立文件
工程目录结构
Slave存放内核Dll的源文件,Master存放了调用内核Dll的驱动程序,App是一个应用层
测试程序, Include存放的是一个公共头文件MyIoCtl.h.
KernelDll
|
|---------Include-----MyIoCtl.h
|
|---------Slave-------Slave.c SOURCES Makefile,slave.Def
|
|---------Master------Master.c SOURCES Makefile
|
|--------App---------test.c
-------------------------------------------------------------------------------
Include\myIoCtl.h
//MyIoctl.h
//CTL_CODE macro defined in devioctl.h in DDK\inc.
//custom device types (non Microsoft) in range 32768 to 65535
//custom user defined function codes in range 2048 to 4095
#define FILE_DEVICE_FOO 65534
#define IOCTL_CALL_KERNEL_MODE_DLL CTL_CODE(FILE_DEVICE_FOO, 2049,
METHOD_BUFFERED, FILE_ANY_ACCESS)
-------------------------------------------------------------------------------
Kernel Dll部分
[1]Slave.c
#include "ntddk.h"
#include "MYIOCTL.H"
NTSTATUS
DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING
RegistryPath ){
return STATUS_SUCCESS;
}
NTSTATUS
_declspec( dllexport )DoSomethingMeaningless(IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpStack){
USHORT *pw;
/* check to see if this is our ioctl. */
if (pIrpStack->Parameters.DeviceIoControl.IoControlCode !=
IOCTL_CALL_KERNEL_MODE_DLL)
return STATUS_INVALID_PARAMETER;
/* check to see if output buffer size is big enough. */
if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof
(USHORT)) {
pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
pIrp->IoStatus.Information = 0;
return STATUS_BUFFER_TOO_SMALL;
}
/* return a value back to the user. */
pIrp->IoStatus.Information = sizeof( USHORT );
pw = (USHORT *)pIrp->AssociatedIrp.SystemBuffer;
*pw = 0XAA55;
pIrp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
[2]SOURCES
# SOURCES FILE FOR SLAVE.SYS
TARGETNAME=SLAVE
TARGETPATH=obj
TARGETTYPE=EXPORT_DRIVER
INCLUDES=$(BASEDIR)\inc;..\Include
SOURCES=SLAVE.C
C_DEFINES=-DUNICODE -DSTRICT
[3]Makefile
#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the components of NT OS/2
#
!INCLUDE $(NTMAKEENV)\makefile.def
[4]Slave.def-----不知道为什么这一次它非要我写Def文件。:(.
;DEF FILE FOR SLAVE.SYS
NAME SLAVE.SYS
DESCRIPTION 'SLAVE.SYS'
EXPORTS
-------------------------------------------------------------------------------
调用Dll的驱动程序
[1]Master.c
#include "ntddk.h"
#include "myioctl.h"
typedef struct _FOO_DEVICE_EXTENSION {
ULONG Information;
} FOO_DEVICE_EXTENSION, *PFOO_DEVICE_EXTENSION;
// Function declarations
NTSTATUS
MasterDispatchIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS
_declspec( dllimport )DoSomethingMeaningless(IN PIRP pIrp, IN PIO_STACK_LOCATIO
pIrpStack );
NTSTATUS
DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING nameString, linkString;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
//slave.sys needs to start before master.sys
// Create the device object.
RtlInitUnicodeString( &nameString, L"\\Device\\MASTER");
status = IoCreateDevice( DriverObject,
sizeof(FOO_DEVICE_EXTENSION),
&nameString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject );
if (!NT_SUCCESS( status ))
return status;
// Create the symbolic link.
RtlInitUnicodeString( &linkString, L"\\DosDevices\\MASTER");
status = IoCreateSymbolicLink (&linkString, &nameString);
if (!NT_SUCCESS( status )) {
IoDeleteDevice (DriverObject->DeviceObject);
return status;
}
// Initialize the driver object with this device driver's entry points.
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MasterDispatchIoct
;
return STATUS_SUCCESS;
}
NTSTATUS
MasterDispatchIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
// Init to default settings- we only expect 1 type of
// IOCTL to roll through here, all others an error.
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
irpSp = IoGetCurrentIrpStackLocation( Irp );
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_CALL_KERNEL_MODE_DLL:
if ( NT_SUCCESS( DoSomethingMeaningless( Irp , irpSp) )
) {
status = STATUS_SUCCESS;
}
else
status = STATUS_INVALID_PARAMETER;
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER
break;
}
// DON'T get cute and try to use the status field of
// the irp in the return status. That IRP IS GONE as
// soon as you call IoCompleteRequest.
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// We never have pending operation so always return the status code.
return status;
}
[2]SOURCES
# SOURCES FILE FOR MASTER.SYS
TARGETNAME=MASTER
TARGETPATH=obj
TARGETTYPE=DRIVER
TARGETLIBS=$(BASEDIR)\lib\slave.lib
INCLUDES=$(BASEDIR)\inc;..\Include
SOURCES=MASTER.C
C_DEFINES=-DUNICODE -DSTRICT
[3]Makefile
#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the components of NT OS/2
#
!INCLUDE $(NTMAKEENV)\makefile.def
------------------------------------------------------------------------------
测试应用程序
#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "stdlib.h"
#include "myioctl.h"
int main ( void )
{
HANDLE hDriver;
DWORD cbReturned = 0x0;
WORD iobuf = 0x0;
// Try to open the device
if ((hDriver = CreateFile("\\\\.\\MASTER",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL )) != INVALID_HANDLE_VALUE )
printf ("\nRetrieved valid handle for MASTER driver\n");
else {
printf ("Can't get a handle to MASTER driver\n");
return 0;
}
// iobuf initialized to zero, so we better get something different after ca
l.
if ( DeviceIoControl (hDriver,
(DWORD) IOCTL_CALL_KERNEL_MODE_DLL,
&iobuf,
(DWORD)(2*(sizeof (WORD))),
&iobuf,
(DWORD)(2*(sizeof (WORD))),
&cbReturned,
(LPVOID)NULL) )
{
if (iobuf == 0xAA55) {
printf("DeviceIoControl worked and returned the correct
value.\n");
} else {
printf("DeviceIoControl worked but reurned the wrong va
ue %x\n", iobuf);
}
} else {
printf("DeviceIoControl Failed\n");
}
}
CloseHandle(hDriver);
return 1;
}
———————————————————————————————————————?
——
2. 编译
以下的编译过程是用DDK编译的。环境为W2k.
(1)Slave
进入目录slave,键入build -cez
(2)Master
(a) 进入Master,键入build -cez
错误:don't know how to make 'e:\Ntddk\lib\slave.lib'
原因:slave.lib 没有拷贝到制定目录。
(b)把slave.lib拷贝到e:\Ntddk\lib\,继续编译 build -ceZ
通过。
(3)App--->test.exe
-------------------------------------------------------------------------------
(To be continued)
*************************************************************************
printf("DeviceIoControl Failed\n");
}
发信人: fist (星仔迷), 信区: SysInternals WWW-POST
标 题: Kernel Dll的范例(2)
发信站: 武汉白云黄鹤站 (Mon Jul 2 20:37:08 2001) , 转信
3.启动与测试
(1)拷贝slave.sys和master.sys到目录e:\winnt\system32\drivers\
(2)写注册表
master.ini
\registry\machine\system\currentcontrolset\services\MASTER
Type = REG_DWORD 0x00000001
Start = REG_DWORD 0x00000002
Group = Extended base
ErrorControl = REG_DWORD 0x00000001
Tag = REG_DWORD 0x00000002
slave.ini
\registry\machine\system\currentcontrolset\services\SLAVE
Type = REG_DWORD 0x00000001
Start = REG_DWORD 0x00000002
Group = Extended base
ErrorControl = REG_DWORD 0x00000001
Tag = REG_DWORD 0x00000001
Regini slave.ini
Regini master.ini
(3)重启计算机
(4)打开并运行程序test.exe,显示
Retrieved valid handle for MASTER driver
DeviceIoControl worked and returned the correct value.
表明运行成功。
4.问题与解决方案
(1) 加载顺序。
在本例子中要求slave.sys先于master.sys启动,在很多应用中也有这样的需要。在本例子
中
,我们主要的技术是定义一个组”extended base”,然后相同的start,type,唯一的区别?
slave.sys的tag=2>master.sys的tag=1.
加载顺序主要决定于start,(Group)GroupOrderList, DependOnGroup,适当调整这些值就可
以
确定加载顺序了。
(2) 编译需要库文件支持。也就是说编译master.sys时依赖于slave.lib。其实我猜?
s.lib也是一个kernel Dll的形式提供给驱动程序开发者使用的。相类似的在system32\dri
ers下也存在ndis.sys。其他还有什么tdi也是这样的。
(3) 现在考虑一下EDIS用Kernel Dll来实现存在的问题。对于问题1,也许很好决定,
GroupOrderList可以很好地控制kernel Dll的加载顺序。对于库支持,好像久有问题了(?
敢十分确定,我的初略想法,希望各位,特别是老斑竹提出意见)。问题在于如果每增加?
个算法,都得把EDIS的算法管理模块编译一次,以支持新的算法。好像根本就不应该用DLL
的
思想来实现,太不灵活了。这里也许想到EDIS唯一的思路是模仿动态加载,而且是显式调?
应用层Dll ,或者更确切地说是像COM技术,提供一个特殊的接口QueryInterface.通过这?
特殊接口,算法管理模块可以得到Dll到底支持什么算法,那些使用该算法的函数等。这样
控
制算法的加载只需要在应用层或其他地方告诉算法管理模块需要加载或卸载那些提供算法?
sys.。然后管理模块自动加载算法sys,查询接口,并纪录接口信息。这样的好处是不需要?
加算法时重新编译算法管理模块。
当然这种方法和老斑竹的想法有点不同,这里算法管理模块一直是主动,而不是被动。这?
种方法都不是用Kernel Dll来实现,而是一般驱动程序的技巧,更准确的说是一种灵活的?
构。也是写到这里顺便瞎说的,好像与文章主体无关。
******************
--