翻出来了两个小工具,发出来共享一下,没什么技术含量,大家不喜勿喷
第一个是imageLoadMonitor主要用来获取驱动源文件的,有的驱动装载后会马上删掉自己,
使用这个小工具能在删除操作发生前将驱动源文件拷贝出去,至今还没有发现不能成功拷贝的例子,嘿嘿
原理呢主要就是利用PsSetLoadImageNotifyRoutine注册一个模块装载的通知回调
这个回调会在模块的DLLMAIN或DRVER ENTRY被执行前调用,所以利用这一点就能把我们对模块的拷贝操作插在删除操作之前进行
下面看一下源码:
头文件:
#ifndef IMAGELOADMONITOR_H
#define IMAGELOADMONITOR_H
#endif
#include <ntddk.h>
#include <ntstrsafe.h>
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath);
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH DispatchDeviceIoControl;
NTSTATUS DispatchDeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);
__drv_dispatchType_other
DRIVER_DISPATCH DispatchCompletion;
NTSTATUS DispatchCompletion(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);
DRIVER_UNLOAD Unload;
VOID Unload(PDRIVER_OBJECT pDriverObject);
#include "imageLoadMonitor.h"
#pragma alloc_text (INIT,DriverEntry)
#pragma alloc_text (PAGE,DispatchDeviceIoControl)
#pragma alloc_text (PAGE,Unload)
#pragma alloc_text (PAGE,DispatchCompletion)
#define DEVICE_NAME L"\\Device\\imageLoadMonitory"
#define DEVICE_SYMBOLICLINK_NAME L"\\DosDevices\\imageLoadMonitorSymLink"
#define IOCTL_BEGIN_MONITOR (CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,FILE_ANY_ACCESS,METHOD_BUFFERED))
#define IOCTL_STOP_MONITOR (CTL_CODE(FILE_DEVICE_UNKNOWN,0X802,FILE_ANY_ACCESS,METHOD_BUFFERED))
BOOLEAN NotifyHasBeenSet = FALSE;
VOID
LoadImageNotifyRoutine( PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo )
{
HANDLE hSourceFile;
HANDLE hDestFile;
HANDLE hSection;
PVOID pvSectionBase = NULL;
PVOID pBuf = NULL;
OBJECT_ATTRIBUTES fileObject;
UNICODE_STRING DestString;
NTSTATUS status;
IO_STATUS_BLOCK ioStatusBlock;
LARGE_INTEGER sectionSize;
if ( !(ImageInfo->SystemModeImage) ) //检测第9位即是否是载入了系统空间
{
return ;
}
if ( ImageInfo->ImageSize == 0 ) return ;
KdPrint(("%wZ",FullImageName));
InitializeObjectAttributes(&fileObject,FullImageName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
//打开驱动的源文件
status = ZwCreateFile(&hSourceFile,
GENERIC_READ | SYNCHRONIZE,
&fileObject,
&ioStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN, //存在则打开 不存在则返回错误码
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,0);
if (!NT_SUCCESS(status)) return ;
#define SEC_COMMIT 0x8000000
sectionSize.HighPart = 0;
sectionSize.LowPart = (ULONG)ImageInfo->ImageSize;
//映射文件
status = ZwCreateSection(&hSection,
SECTION_MAP_READ | SECTION_MAP_WRITE,
NULL,
§ionSize,
PAGE_READWRITE,
SEC_COMMIT,
hSourceFile);
if (!NT_SUCCESS(status))
{
ZwClose(hSourceFile);
return ;
}
//创建映射视图
status = ZwMapViewOfSection(hSection,
ZwCurrentProcess(),
&pvSectionBase, //接受映射的基址
0,
(ULONG)ImageInfo->ImageSize, //节区大小
NULL, //section起始至这里的偏移
&(ULONG)ImageInfo->ImageSize,
ViewUnmap,
MEM_TOP_DOWN,
PAGE_READWRITE);
pBuf = ExAllocatePoolWithTag(PagedPool,64,645212); //准备文件名缓冲
if ( !NT_SUCCESS(status)||(pvSectionBase == NULL)||(pBuf == NULL) )
{
ZwClose(hSection);
ZwClose(hSourceFile);
return ;
}
RtlZeroMemory(pBuf,64);
RtlStringCchPrintfW(pBuf,64,L"\\DosDevices\\C:\\%x",(ULONG)ImageInfo->ImageBase);
RtlInitUnicodeString(&DestString,(PWCHAR)pBuf);
InitializeObjectAttributes(&fileObject,&DestString,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
//打开目标文件
status = ZwCreateFile(&hDestFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&fileObject,
&ioStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SUPERSEDE, //存在则覆盖 不存在则创建
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,0);
if (!NT_SUCCESS(status)) goto __exit1;
status = ZwWriteFile(hDestFile,NULL,NULL,NULL,&ioStatusBlock,pvSectionBase,(ULONG)ImageInfo->ImageSize,NULL,NULL);
if (!NT_SUCCESS(status)) goto __exit2;
__exit2:
ZwClose(hDestFile);
__exit1:
ExFreePool(pBuf);
pBuf = NULL;
ZwUnmapViewOfSection(hSection,pvSectionBase);
pvSectionBase = NULL;
ZwClose(hSection);
ZwClose(hSourceFile);
return ;
}
NTSTATUS
DispatchDeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
ULONG ulIoControlCode; //控制代码
PVOID pvBuf = NULL;
PIO_STACK_LOCATION pIrpStatck = NULL;
NTSTATUS status = STATUS_SUCCESS;
pIrpStatck = IoGetCurrentIrpStackLocation(pIrp);
ulIoControlCode = pIrpStatck->Parameters.DeviceIoControl.IoControlCode; //取IO 控制代码
pvBuf = pIrp->AssociatedIrp.SystemBuffer; //取缓冲指针
switch ( ulIoControlCode )
{
case IOCTL_BEGIN_MONITOR:
if (NotifyHasBeenSet == TRUE) break;
status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine);
if ( NT_SUCCESS(status) )
{
NotifyHasBeenSet = TRUE;
}
else
{
NotifyHasBeenSet = FALSE;
status = STATUS_UNSUCCESSFUL;
}
break;
case IOCTL_STOP_MONITOR:
if (NotifyHasBeenSet == FALSE) break;
status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
if ( (NT_SUCCESS(status))||(status = STATUS_PROCEDURE_NOT_FOUND ) )
{
NotifyHasBeenSet = FALSE;
status = STATUS_SUCCESS;
}
else
{
status = STATUS_UNSUCCESSFUL;
}
break;
default:
KdPrint(("接收到非法命令\n"));
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
VOID
Unload(PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING SymLinkName;
RtlInitUnicodeString(&SymLinkName,DEVICE_SYMBOLICLINK_NAME);
IoDeleteSymbolicLink(&SymLinkName);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS
DispatchCompletion(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
PDEVICE_OBJECT pMyDeviceObject = NULL;
PWSTR pBuf = NULL;
UNICODE_STRING SymLinkName;
UNICODE_STRING MyDeviceName;
NTSTATUS status = STATUS_SUCCESS;
ULONG i;
UNREFERENCED_PARAMETER(pRegPath);
for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriverObject->MajorFunction[i] = DispatchCompletion;
}
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceIoControl;
pDriverObject->DriverUnload = Unload;
//创建设备对象
RtlInitUnicodeString(&MyDeviceName,DEVICE_NAME);
status = IoCreateDevice(pDriverObject,0,&MyDeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pMyDeviceObject);
if (!NT_SUCCESS(status)){
KdPrint(("创建设备对象失败\n"));
return status;
}
//创建符号链接
RtlInitUnicodeString(&SymLinkName,DEVICE_SYMBOLICLINK_NAME);
status = IoCreateSymbolicLink(&SymLinkName,&MyDeviceName);
if (!NT_SUCCESS(status)){
IoDeleteDevice(pMyDeviceObject);
KdPrint(("创建符号链接失败\n"));
return status;
}
pMyDeviceObject->Flags |= DO_BUFFERED_IO;
pMyDeviceObject->Flags = pMyDeviceObject->Flags &~ DO_DEVICE_INITIALIZING;
return status;
}
我们主要看一下回调例程
WDK中给出了PLOAD_IMAGE_NOTIFY_ROUTINE回调的格式:
VOID
(*PLOAD_IMAGE_NOTIFY_ROUTINE) (
IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo
);
其中FullImageName指示了模块的全路径,我们可以直接根据这个路径来打开源文件
当装载的是用户空间的模块时ProcessId指示了进程ID,当是一个驱动被装载时ProcessId为0
ImageInfo是一个_IMAGE_INFO结构,描述了模块的一些详细信息
typedef struct _IMAGE_INFO {
union {
ULONG Properties;
struct {
ULONG ImageAddressingMode : 8;
ULONG SystemModeImage : 1;
ULONG ImageMappedToAllPids : 1;
ULONG Reserved : 22;
};
};
PVOID ImageBase;
ULONG ImageSelector;
ULONG ImageSize;
ULONG ImageSectionNumber;
} IMAGE_INFO, *PIMAGE_INFO;
详细的结构成员描述可以从WDK中获得,我们主要用到这个结构中的两个域:
SystemModeImage:此位为1时表示装载的是驱动文件,为0时表示装载模块在用户空间,
因为我们的目的是监测驱动的装载所以我们根据此标志位来进行过滤
ImageSize:指示了模块的大小,我们根据此域创建新文件
有了这些信息就能做出这个小驱动了,余下的工作就是进行文件拷贝,都是最常用的API,这里就不多说了
这里我们没有进行动态的系统目录判断,直接就将文件放在了C盘根目录,文件名称就是驱动装载的基址
拦截到的xt的驱动文件
那么这跟内存拷贝的驱动文件相比有什么好处吗?我们在IDA中看一下
下面的是内存拷贝出来的驱动中的代码片段:
下面是同样地址处的通过工具拷贝出的驱动中的代码片段:
因为内存dump出来的驱动文件涉及到地址的地方都已经计算成了线性地址,我们要根据这个地址来找到操作的目标要通过计算,很麻烦
不过这样也有它的好处,因为已经装载并初始化完毕,所以驱动中使用的一些全局变量都已经被赋值,这样在逆向过程中也能通过观察它们的值来得到一些启发
各有各的长处,大家还是把两种形式的文件结合起来观察使用才更有效率,至于内存dump功能,几乎每个ark都有提供,我就不说了,嘿嘿
//********************************
第二个小工具是用来监控RING3程序与驱动通讯的,通过SSDT HOOK来实现,先看一下效果:
监控了一下我另外一个程序:
监控xt的程序:
这里只打印出了进程ID,IO控制代码,输入缓冲长,输出缓冲长
如果不嫌麻烦,你也可以打印出其缓冲中的内容,呵呵,有点邪恶了..
因为程序是通过SSDT HOOK NtDeviceIoControl来实现的,所以不能拦截到非常规通讯手段的信息
下面看一下源码:
#include "deviceControlIoMonitor.h"
#pragma alloc_text (INIT,DriverEntry)
#pragma alloc_text (PAGE,DispatchDeviceIoControl)
#pragma alloc_text (PAGE,Unload)
#pragma alloc_text (PAGE,DispatchCompletion)
#define DEVICE_NAME L"\\Device\\deviceIoControlMonitor"
#define DEVICE_SYMBOLICLINK_NAME L"\\DosDevices\\deviceIoControlMonitorSymLink"
#define IOCTL_BEGIN_HOOK (CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,FILE_ANY_ACCESS,METHOD_BUFFERED))
#define IOCTL_STOP_HOOK (CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,FILE_ANY_ACCESS,METHOD_BUFFERED))
BOOLEAN globe_HookInstalled = FALSE;
NTSTATUS
DispatchDeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
ULONG IoControlCode = 0;
PIO_STACK_LOCATION pIrpStatck = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
pIrpStatck = IoGetCurrentIrpStackLocation(pIrp);
IoControlCode = pIrpStatck->Parameters.DeviceIoControl.IoControlCode;
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
//DbgBreakPoint();
switch ( IoControlCode )
{
case IOCTL_BEGIN_HOOK:
if ( globe_HookInstalled == TRUE )
{
pIrp->IoStatus.Status = status = STATUS_SUCCESS;
break;
}
if ( Hook() )
{
pIrp->IoStatus.Status = status = STATUS_SUCCESS;
KdPrint(("成功Hook \n"));
globe_HookInstalled = TRUE;
}
break;
case IOCTL_STOP_HOOK:
if ( globe_HookInstalled == FALSE )
{
pIrp->IoStatus.Status = status = STATUS_SUCCESS;
break;
}
if ( RestoreHook() )
{
pIrp->IoStatus.Status = status = STATUS_SUCCESS;
KdPrint(("成功恢复Hook \n"));
globe_HookInstalled = FALSE;
}
break;
default:
KdPrint(("接收到非法命令\n"));
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
VOID
Unload(PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING SymLinkName;
RtlInitUnicodeString(&SymLinkName,DEVICE_SYMBOLICLINK_NAME);
IoDeleteSymbolicLink(&SymLinkName);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS
DispatchCompletion(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
PDEVICE_OBJECT pMyDeviceObject = NULL;
UNICODE_STRING SymLinkName;
UNICODE_STRING MyDeviceName;
NTSTATUS status = STATUS_SUCCESS;
ULONG i;
for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
pDriverObject->MajorFunction[i] = DispatchCompletion;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceIoControl;
pDriverObject->DriverUnload = Unload;
//创建设备对象
RtlInitUnicodeString(&MyDeviceName,DEVICE_NAME);
status = IoCreateDevice(pDriverObject,0,&MyDeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pMyDeviceObject);
if (!NT_SUCCESS(status)){
KdPrint(("创建设备对象失败\n"));
return status;
}
//创建符号链接
RtlInitUnicodeString(&SymLinkName,DEVICE_SYMBOLICLINK_NAME);
status = IoCreateSymbolicLink(&SymLinkName,&MyDeviceName);
if (!NT_SUCCESS(status)){
IoDeleteDevice(pMyDeviceObject);
KdPrint(("创建符号链接失败\n"));
return status;
}
pMyDeviceObject->Flags |= DO_BUFFERED_IO;
pMyDeviceObject->Flags = pMyDeviceObject->Flags & ~ DO_DEVICE_INITIALIZING;
return status;
}
头文件:
#ifndef HOOK_H
#define HOOK_H
#endif
#pragma once
#include <ntddk.h>
//自定义结构,简单实现了一个白名单
typedef struct _ProcessWhiteList{
PULONG WhiteProcessIdList_svchost;
ULONG WhiteListCount_svchost;
PULONG WhiteProcessIdList_TM;
ULONG WhiteListCount_TM;
PULONG WhiteProcessIdList_taskmgr;
ULONG WhiteListCount_taskmgr;
}ProcessWhiteList,*PProcessWhiteList;
typedef enum {
StateInitialized,
StateReady,
StateRunning,
StateStandby,
StateTerminated,
StateWait,
StateTransition,
StateUnknown
} THREAD_STATE;
typedef struct _SYSTEM_THREADS_INFORMATION { // Information Class 5
LARGE_INTEGER KernelTime; //内核模式下运行时间
LARGE_INTEGER UserTime; //用户模式下运行时间
LARGE_INTEGER CreateTime; //线程创建时间
ULONG WaitTime; //总的等待时间
PVOID StartAddress; //线程起始地址
CLIENT_ID ClientId; //线程标识符,包含线程标识符和进程标识符
KPRIORITY Priority; //线程优先级
KPRIORITY BasePriority; //线程的基本优先级
ULONG ContextSwitchCount; //线程的切换次数
THREAD_STATE State; //线程的运行状态,枚举结构,参下
KWAIT_REASON WaitReason; //
ULONG Unknow;
} SYSTEM_THREADS_INFORMATION, *PSYSTEM_THREADS_INFORMATION;
typedef struct _SYSTEM_PROCESSES_INFORMATION { // Information Class 5
ULONG NextEntryDelta; //由此结构开始距离下一个结构的偏移,如果为0表示没有下一个结构了
ULONG ThreadCount; //进程中的线程数
ULONG Reserved1[6]; //保留
LARGE_INTEGER CreateTime; //进程的创建时间(从1601 1 1)
LARGE_INTEGER UserTime; //用户模式下运行的时间
LARGE_INTEGER KernelTime; //内核模式下运行的时间
UNICODE_STRING ProcessName; //进程名
KPRIORITY BasePriority; //进程的线程的基本优先级
ULONG ProcessId; //进程标识符
ULONG InheritedFromProcessId; //
ULONG HandleCount; //进程打开的总的句柄数
ULONG Reserved2[2]; //
VM_COUNTERS VmCounters; //一个结构,描述了虚拟内存的使用情况
IO_COUNTERS IoCounters; // Windows 2000 only
SYSTEM_THREADS_INFORMATION Threads[1]; //进程的线程结构数组
} SYSTEM_PROCESSES_INFORMATION, *PSYSTEM_PROCESSES_INFORMATION;
typedef struct _tagSSDT{
PVOID pvSSDTBase;
PVOID pvServiceCounterTable;
ULONG ulNumberOfServices;
PVOID pvParamTableBase;
} SystemServiceDescriptorTable,*PSystemServiceDescriptorTable;
extern PSystemServiceDescriptorTable KeServiceDescriptorTable;
//定义函数类型指针
typedef
NTSTATUS
(__stdcall *NTDEVICEIOCONTROLFILE)(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength);
//声明代理函数
NTSTATUS MyDeviceIoControlFIle(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength);
NTKERNELAPI
NTSTATUS
ZwQuerySystemInformation(ULONG SystemInformationClass, PVOID SystemInformation,
ULONG SystemInformationLength, PULONG ReturnLength);
BOOLEAN Hook();
BOOLEAN RestoreHook();
#include "Hook.h"
#pragma alloc_text (PAGE,Hook)
#pragma alloc_text (PAGE,RestoreHook)
#define DEBUGVIEW_NAME L"\\Driver\\DBGV"
ProcessWhiteList globe_WhiteList;
ULONG globe_RealNtDeviceIoControlFileAddress = 0;
ULONG globe_Proxy_NtDeviceIoControlFile_BusyNow = 0;
//通过文件句柄获取驱动对象<如果存在的话>
#pragma PAGECODE
PDRIVER_OBJECT GetDriverObjectByFileHandle(HANDLE FileHandle)
{
NTSTATUS status = STATUS_SUCCESS;
PFILE_OBJECT pFileObject = NULL;
PDRIVER_OBJECT pDriverObject = NULL;
PDEVICE_OBJECT pDeviceObject = NULL;
status = ObReferenceObjectByHandle(FileHandle,0,*IoFileObjectType,KernelMode,&pFileObject,NULL);
if (!NT_SUCCESS(status)) return NULL;
pDeviceObject = pFileObject->DeviceObject;
if ( pDeviceObject != NULL )
{
pDriverObject = pDeviceObject->DriverObject;
}
ObDereferenceObject(pFileObject);
return pDriverObject;
}
//自己的代理函数
NTSTATUS MyDeviceIoControlFIle(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength)
{
NTSTATUS status;
HANDLE ProcessId;
KPROCESSOR_MODE mode;
PDRIVER_OBJECT pDriverObject = NULL;
UNICODE_STRING DestUniString;
ULONG i;
//DbgBreakPoint();
InterlockedIncrement(&globe_Proxy_NtDeviceIoControlFile_BusyNow); //引用计数+1
mode = ExGetPreviousMode();
if ( mode == KernelMode )
{
__sss:
status = ((NTDEVICEIOCONTROLFILE)globe_RealNtDeviceIoControlFileAddress)(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,InputBuffer,InputBufferLength,OutputBuffer,OutputBufferLength);
InterlockedDecrement(&globe_Proxy_NtDeviceIoControlFile_BusyNow);
return status;
}
pDriverObject = GetDriverObjectByFileHandle(FileHandle);
if (pDriverObject == NULL) goto __sss;
RtlInitUnicodeString(&DestUniString,DEBUGVIEW_NAME);
if ( RtlEqualUnicodeString(&DestUniString,&pDriverObject->DriverName,TRUE) == TRUE ) goto __sss;
ProcessId = PsGetCurrentProcessId();
if ( globe_WhiteList.WhiteListCount_svchost != 0 )
{
for ( i = 0; i < globe_WhiteList.WhiteListCount_svchost; i++ )
{
if ( (ULONG)ProcessId == globe_WhiteList.WhiteProcessIdList_svchost[i] )
goto __sss;
}
}
if ( globe_WhiteList.WhiteListCount_TM != 0 )
{
for ( i = 0; i < globe_WhiteList.WhiteListCount_TM; i++ )
{
if ( (ULONG)ProcessId == globe_WhiteList.WhiteProcessIdList_TM[i] )
goto __sss;
}
}
if ( globe_WhiteList.WhiteListCount_taskmgr != 0 )
{
for ( i = 0; i < globe_WhiteList.WhiteListCount_taskmgr; i++ )
{
if ( (ULONG)ProcessId == globe_WhiteList.WhiteProcessIdList_taskmgr[i] )
goto __sss;
}
}
KdPrint(("当前进程-----------------:%d \n控制代码-----------------:%x \n输入缓冲-----------------:%x \n输出缓冲-----------------:%x \n目标驱动-----------------:%wZ \n",ProcessId,IoControlCode,InputBufferLength,OutputBufferLength,&pDriverObject->DriverName));
status = ((NTDEVICEIOCONTROLFILE)globe_RealNtDeviceIoControlFileAddress)(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,InputBuffer,InputBufferLength,OutputBuffer,OutputBufferLength);
//KdPrint(("当前进程:%d \n完成状态:%x",ProcessId,status));
InterlockedDecrement(&globe_Proxy_NtDeviceIoControlFile_BusyNow); //引用计数-1
return status;
}
//通过ZwQuerySystemInformation查询系统进线程信息,缓冲由本函数分配调用方释放
#pragma PAGECODE
BOOLEAN GetSystemProcessInformationByZwQuerySystemInformation(PVOID* pvBuf)
{
ULONG ulBufLen = 0x2000;
NTSTATUS status;
do{
*pvBuf = ExAllocatePoolWithTag(PagedPool,ulBufLen,1542);
if (*pvBuf == NULL)
return FALSE;
status = ZwQuerySystemInformation(5,*pvBuf,ulBufLen,NULL);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
if (*pvBuf!=NULL)
{
ExFreePool(*pvBuf);
*pvBuf = NULL;
}
ulBufLen += 0x2000;
}
else if (!NT_SUCCESS(status))
{
if (*pvBuf!=NULL)
{
ExFreePool(*pvBuf);
*pvBuf = NULL;
}
return FALSE;
}
}while(status == STATUS_INFO_LENGTH_MISMATCH);
return TRUE;
}
//通过进程名查找进程ID,对于同名的进程将返回一个包含进程ID的缓冲,本函数分配缓冲,调用方负责释放,函数返回同名进程数量
#pragma PAGECODE
ULONG GetProcessIdByProcessName(PWCHAR pProcessName, PULONG* pBufForProcId)
{
PVOID pProcessListInfo = NULL;
PSYSTEM_PROCESSES_INFORMATION pProcessInfo = NULL;
UNICODE_STRING DestString;
PULONG pBuf = NULL;
ULONG Count;
ULONG MaxCount = 10;
if ( pProcessName == NULL ) return 0;
if ( pBufForProcId == NULL ) return 0;
if ( GetSystemProcessInformationByZwQuerySystemInformation(&pProcessListInfo) == FALSE ) return 0;
RtlInitUnicodeString(&DestString,pProcessName);
//KdPrint(("目标进程名:%wZ",&DestString));
__repeat:
pProcessInfo = (PSYSTEM_PROCESSES_INFORMATION)pProcessListInfo;
Count = 0;
pBuf = ExAllocatePoolWithTag(PagedPool,MaxCount*sizeof(ULONG),612545); //分配临时缓冲
if ( pBuf == NULL ) goto __exit1;
while(TRUE)
{
if ( RtlEqualUnicodeString(&DestString,&pProcessInfo->ProcessName,TRUE) )
{
*(PULONG)((ULONG)pBuf + Count*sizeof(ULONG)) = pProcessInfo->ProcessId;
Count++;
if ( Count >= MaxCount )
{
MaxCount = MaxCount * 2;
if ( pBuf != NULL ) ExFreePool(pBuf);
pBuf = NULL;
goto __repeat;
}
}
pProcessInfo = (PSYSTEM_PROCESSES_INFORMATION)((ULONG)pProcessInfo + pProcessInfo->NextEntryDelta);
if ( pProcessInfo->NextEntryDelta != 0 ) continue;
if ( RtlEqualUnicodeString(&DestString,&pProcessInfo->ProcessName,TRUE) )
{
*(PULONG)((ULONG)pBuf + Count*sizeof(ULONG)) = pProcessInfo->ProcessId;
Count++;
if ( Count >= MaxCount )
{
MaxCount = MaxCount * 2;
if ( pBuf != NULL ) ExFreePool(pBuf);
pBuf = NULL;
goto __repeat;
}
}
break;
}
if ( Count != 0 )
{
*pBufForProcId = ExAllocatePoolWithTag(PagedPool,Count * sizeof(ULONG),56326);
if ( *pBufForProcId == NULL )
{
Count = 0;
goto __exit1;
}
RtlMoveMemory(*pBufForProcId,pBuf,Count*sizeof(ULONG));
}
__exit1:
if ( pProcessListInfo != NULL ) ExFreePool(pProcessListInfo);
pProcessListInfo = NULL;
if ( pBuf != NULL ) ExFreePool(pBuf);
pBuf = NULL;
return Count;
}
//通过名称获取已导出SSDT函数地址及索引
#pragma CODEPAGE
BOOLEAN GetSSDTFuncAddressAndIndexByFuncName(PWCHAR pSSDTFuncName, PULONG funcAddress, PULONG funcIndex)
{
UNICODE_STRING destString;
ULONG FuncAddress; //zw
if (pSSDTFuncName == NULL) return FALSE;
RtlInitUnicodeString(&destString,pSSDTFuncName);
FuncAddress = (ULONG)MmGetSystemRoutineAddress(&destString);
if ( FuncAddress == 0 ) return FALSE;
//是否是mov指令
if ( *(PUCHAR)FuncAddress != 0xB8 ) return FALSE;
if ( funcIndex != NULL )
{
*funcIndex = *(PULONG)(FuncAddress+1);
if ( *funcIndex > KeServiceDescriptorTable->ulNumberOfServices) return FALSE;
}
if ( funcAddress != NULL )
*funcAddress = *(PULONG)((ULONG)KeServiceDescriptorTable->pvSSDTBase+(*funcIndex * sizeof(ULONG)));
return TRUE;
}
//通过SSDT函数索引进行ssdt hook
BOOLEAN HookSSDTByIndex(ULONG funcIndex, ULONG NewFuncAddress, PULONG OldFuncAddress)
{
ULONG FunctionAddress;
ULONG temp;
ULONG ulCr0;
if ( funcIndex > KeServiceDescriptorTable->ulNumberOfServices) return FALSE;
if ( !MmIsAddressValid((PVOID)NewFuncAddress) ) return FALSE;
FunctionAddress = (ULONG)KeServiceDescriptorTable->pvSSDTBase + funcIndex * sizeof(ULONG);
__asm{
cli
push eax
mov eax, CR0
mov ulCr0,eax
and eax,0xFFFEFFFF
mov CR0,eax
pop eax
}
temp = InterlockedExchange((PULONG)FunctionAddress,NewFuncAddress);
__asm{
push eax
mov eax,ulCr0
mov CR0,eax
pop eax
sti
}
if ( OldFuncAddress != NULL ) *OldFuncAddress = temp;
return TRUE;
}
#pragma PAGECODE
BOOLEAN HookSSDTByName(PWCHAR pSSDTFuncName, ULONG NewFuncAddress, PULONG oldFuncAddress)
{
ULONG Index = 0;
if ( pSSDTFuncName == NULL ) return FALSE;
if ( !MmIsAddressValid((PVOID)NewFuncAddress) ) return FALSE;
if ( GetSSDTFuncAddressAndIndexByFuncName(pSSDTFuncName,NULL,&Index) == FALSE ) return FALSE;
return HookSSDTByIndex(Index,NewFuncAddress,oldFuncAddress);
}
BOOLEAN Hook()
{
ULONG Count = 0;
PULONG pBuf = NULL;
PVOID pTemp = NULL;
ULONG Temp = 0;
RtlZeroMemory(&globe_WhiteList,sizeof(ProcessWhiteList));
Count = GetProcessIdByProcessName((PWCHAR)L"svchost.exe",&pBuf);
if ( Count != 0 )
{
globe_WhiteList.WhiteProcessIdList_svchost = ExAllocatePoolWithTag(NonPagedPool,Count*sizeof(ULONG),00011);
if ( globe_WhiteList.WhiteProcessIdList_svchost != NULL )
{
RtlMoveMemory(globe_WhiteList.WhiteProcessIdList_svchost,pBuf,Count*sizeof(ULONG));
globe_WhiteList.WhiteListCount_svchost = Count;
}
ExFreePool(pBuf);
pBuf = NULL;
}
Count = GetProcessIdByProcessName((PWCHAR)L"TM.exe",&pBuf);
if ( Count != 0 )
{
globe_WhiteList.WhiteProcessIdList_TM = ExAllocatePoolWithTag(NonPagedPool,Count*sizeof(ULONG),045);
if ( globe_WhiteList.WhiteProcessIdList_TM != NULL )
{
RtlMoveMemory(globe_WhiteList.WhiteProcessIdList_TM,pBuf,Count*sizeof(ULONG));
globe_WhiteList.WhiteListCount_TM = Count;
}
ExFreePool(pBuf);
pBuf = NULL;
}
Count = GetProcessIdByProcessName((PWCHAR)L"taskmgr.exe",&pBuf);
if ( Count != 0 )
{
globe_WhiteList.WhiteProcessIdList_taskmgr = ExAllocatePoolWithTag(NonPagedPool,Count*sizeof(ULONG),045);
if ( globe_WhiteList.WhiteProcessIdList_taskmgr != NULL )
{
RtlMoveMemory(globe_WhiteList.WhiteProcessIdList_taskmgr,pBuf,Count*sizeof(ULONG));
globe_WhiteList.WhiteListCount_taskmgr = Count;
}
ExFreePool(pBuf);
pBuf = NULL;
}
return ( HookSSDTByName((PWCHAR)L"ZwDeviceIoControlFile", (ULONG)&MyDeviceIoControlFIle, &globe_RealNtDeviceIoControlFileAddress) );
}
BOOLEAN RestoreHook()
{
KTIMER timer;
LARGE_INTEGER DueTime;
ULONG i;
if ( HookSSDTByName((PWCHAR)L"ZwDeviceIoControlFile",globe_RealNtDeviceIoControlFileAddress,NULL) == FALSE )
return FALSE;
if ( globe_Proxy_NtDeviceIoControlFile_BusyNow > 1 ) //如果代理函数正忙,等待一下
{
DueTime.QuadPart = 0;
KeInitializeTimerEx(&timer,SynchronizationTimer);
KeSetTimerEx(&timer,DueTime,100,NULL);
for ( i = 0; i < 200; i++ )
{
KeWaitForSingleObject(&timer,Executive,KernelMode,FALSE,NULL);
if ( globe_Proxy_NtDeviceIoControlFile_BusyNow <= 1 ) break;
}
KeCancelTimer(&timer);
}
if ( globe_WhiteList.WhiteProcessIdList_svchost != NULL ) ExFreePool(globe_WhiteList.WhiteProcessIdList_svchost);
globe_WhiteList.WhiteProcessIdList_svchost = NULL;
if ( globe_WhiteList.WhiteProcessIdList_TM != NULL ) ExFreePool(globe_WhiteList.WhiteProcessIdList_TM);
globe_WhiteList.WhiteProcessIdList_TM = NULL;
if ( globe_WhiteList.WhiteProcessIdList_taskmgr != NULL ) ExFreePool(globe_WhiteList.WhiteProcessIdList_taskmgr);
globe_WhiteList.WhiteProcessIdList_taskmgr = NULL;
globe_WhiteList.WhiteListCount_svchost = 0;
globe_WhiteList.WhiteListCount_TM = 0;
globe_WhiteList.WhiteListCount_taskmgr = 0;
return TRUE;
}
大家可以像HS一样将这个改为一个白名单链表,更容易扩展,我偷懒就写成固定形式了,虽然起名为whitelist....
像GetDriverObjectByFileHandle等函数我都封装成了独立的模块,大家可以抽取出来引入到自己的驱动中,都十分简单,不多说了,看一下代理函数:
NTSTATUS MyDeviceIoControlFIle(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength)
{
NTSTATUS status;
HANDLE ProcessId;
KPROCESSOR_MODE mode;
PDRIVER_OBJECT pDriverObject = NULL;
UNICODE_STRING DestUniString;
ULONG i;
//DbgBreakPoint();
InterlockedIncrement(&globe_Proxy_NtDeviceIoControlFile_BusyNow);
mode = ExGetPreviousMode();
if ( mode == KernelMode )
{
__sss:
status = ((NTDEVICEIOCONTROLFILE)globe_RealNtDeviceIoControlFileAddress)(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,InputBuffer,InputBufferLength,OutputBuffer,OutputBufferLength);
InterlockedDecrement(&globe_Proxy_NtDeviceIoControlFile_BusyNow);
return status;
}
pDriverObject = GetDriverObjectByFileHandle(FileHandle);
if (pDriverObject == NULL) goto __sss;
RtlInitUnicodeString(&DestUniString,DEBUGVIEW_NAME);
if ( RtlEqualUnicodeString(&DestUniString,&pDriverObject->DriverName,TRUE) == TRUE ) goto __sss;
ProcessId = PsGetCurrentProcessId();
if ( globe_WhiteList.WhiteListCount_svchost != 0 )
{
for ( i = 0; i < globe_WhiteList.WhiteListCount_svchost; i++ )
{
if ( (ULONG)ProcessId == globe_WhiteList.WhiteProcessIdList_svchost[i] )
goto __sss;
}
}
if ( globe_WhiteList.WhiteListCount_TM != 0 )
{
for ( i = 0; i < globe_WhiteList.WhiteListCount_TM; i++ )
{
if ( (ULONG)ProcessId == globe_WhiteList.WhiteProcessIdList_TM[i] )
goto __sss;
}
}
if ( globe_WhiteList.WhiteListCount_taskmgr != 0 )
{
for ( i = 0; i < globe_WhiteList.WhiteListCount_taskmgr; i++ )
{
if ( (ULONG)ProcessId == globe_WhiteList.WhiteProcessIdList_taskmgr[i] )
goto __sss;
}
}
KdPrint(("当前进程-----------------:%d \n控制代码-----------------:%x \n输入缓冲-----------------:%x \n输出缓冲-----------------:%x \n目标驱动-----------------:%wZ \n",ProcessId,IoControlCode,InputBufferLength,OutputBufferLength,&pDriverObject->DriverName));
status = ((NTDEVICEIOCONTROLFILE)globe_RealNtDeviceIoControlFileAddress)(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,IoControlCode,InputBuffer,InputBufferLength,OutputBuffer,OutputBufferLength);
//KdPrint(("当前进程:%d \n完成状态:%x",ProcessId,status));
InterlockedDecrement(&globe_Proxy_NtDeviceIoControlFile_BusyNow);
return status;
}
因为Hook成功之后我们的代理函数就会随时运行在不同的进程环境中,
所以当我们要卸载这个Hook的时候如果不加以检测很容易因为代理函数没有执行完毕就强行退出,从而导致蓝屏
在这里我山寨了一下HS的做法:
每当代理函数被调用一次,就增加一次引用计数,相应的,在函数执行完毕之后进行递减,
这样当我们卸载Hook的时候可以通过检测这个引用计数来判断我们的代理函数是否还处于被调用中,
如果引用计数降至1,我们就可以安全地卸载它了.<为什么是1而不是0呢?大家自己想想吧>
其中:
mode = ExGetPreviousMode();
这个函数用来判断之前处理器的模式,是内核模式还是用户模式,可以通过这里栏判断调用来自哪里,进行简单过滤
另外因为我们要通过debugview来观察输出结果,而debugview也会非常频繁地与驱动交互,所以为了方便我们观察也对它进行了过滤
RestoreHook中我注册了一个DPC TIMER来循环等待未完成的调用,也是山寨了HS的做法,嘿嘿
其他的应该没有什么理解上的难度了
最后声明一下,这两个小程序都是在Win7下开发测试的,xp系统也用过,不过相对较少,如果有什么问题的话大家对照这里的源码自己修改下把~~
- 标 题:发两个监测小工具~~
- 作 者:thisIs
- 时 间:2011-10-14 08:46:00
- 链 接:http://bbs.pediy.com/showthread.php?t=141397
代码:
代码:
代码:
代码:
代码:
代码:
代码:
代码:
代码: