杀毒软件为了能实时检测到系统中任何变化,并进一步进行判断该操作是否存在危害,均采用挂钩系统关键调用方式实现该流程,该技术称为主动防御技术。

功能方面(检测和保护)有如下方面

比如监控文件变化、监控注册表变化、监控内存加载、监控进程\线程变化、实现自身进程保护、实现自身窗体保护、安全输入等。

涉及到的关键系统服务表 SSDT 、Shadow SSDT,为了更好的兼容性,一般不会直接去替换服务表中例程,而选择挂钩 KiFastCallEntry,好处有很多,至少可以自己重载一份关键系统例程,防止被在前面拦截掉。

实现时需要保证能在ring3下获取到ring0拦截到的信息,并且做出判断返回给ring0程序,继续执行下面的操作,也即保证ring3 、 ring0 程序同步。

采用方案如下:

 

1 ring3程序CreateEvent 两个事件( E1 、E2),把句柄发送给ring0

2 ring0程序调用 ObReferenceObjectByHandle 获取到事件对象

3 ring3程序创建一个线程在里面 WaitForSingleObject ( E1 )

4 ring0程序拦截到一次调用,SetEvent( E1 ),此时 ring3 程序继续执行

ring0程序 KeWaitForSingleObject( E2 )

5 ring3程序进行判断该请求,将信息发给ring0 ,并SetEvent( E2 )

6 ring0 已经有信息了,可以继续执行。
 

最后

本程序未挂钩KifastCallEntry 以及 HOOK 任何函数,只是一个小的demo,里面用到

CreateProcessNotifyFunction来实现拦截进程创建信息,后续如是要扩展,挂钩KifastCallEntry, Inline HOOK 某些API,封装事件消息,并设置一个队列来存放,依次反馈给ring3,并实现一个黑、白名单机制。
 

代码:

这里给一个简单 DEMO 关键代码:

驱动部分

.h

#include "ntddk.h"

#include <ntstrsafe.h>


#define SIOCTL_TYPE FILE_DEVICE_UNKNOWN


#define IOCTL_START \

CTL_CODE( SIOCTL_TYPE, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS )


#define IOCTL_STOP \

CTL_CODE( SIOCTL_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS )


#define IOCTL_GET_DATA \

CTL_CODE( SIOCTL_TYPE, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS )


#define IOCTL_SET_REPLY \

CTL_CODE( SIOCTL_TYPE, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS )


#define DRIVERNAMEL "\\Device\\KernelHandle"

#define SYMBOLICNAMEL "\\DosDevices\\KernelHandle"

#define G_EVENTL "\\BaseNamedObjects\\MyEvent" /* 应用层 触发 */


typedef struct _PROCESSINFO

{
ULONGPID;

charname[16];

charPATH[256];
}PROCERSSINFO, *PPROCESSINFO;


typedef struct _HANDLEINFO

{
HANDLEarg1; /* 这个是 内核层 SET */

HANDLEarg2; /* 这个是 应用层 SET */
}HANDLEINFO, *PHANDLEINFO;


__declspec( dllimport )


NTSTATUS NTAPI

ZwTerminateProcess( IN HANDLE ProcessHandle OPTIONAL,

IN NTSTATUS ExitStatus );


NTSTATUS

PsLookupProcessByProcessId(

IN HANDLE ProcessId,

OUT PEPROCESS *Process

);

.sys


#include "zhudongfangyu.h"

BOOLEAN g_bIsNotifyRoutineSetted;

PKEVENT g_pEventObject0 = NULL; /* 内核层触发 */

PKEVENT g_pEventObject3 = NULL; /* 应用层触发 */

HANDLEg_hEvent = NULL;


BOOLEANg_bREPLY;

UNICODE_STRINGEventName;


OBJECT_HANDLE_INFORMATION g_ObjectHandleInfo;


VOID PrintIrpInfo( PIRP Irp );


VOID MyUnload( PDRIVER_OBJECT pDerverObject )


{
PDEVICE_OBJECTdevObj = pDerverObject->DeviceObject;

UNICODE_STRINGsymbolicName;

RtlInitUnicodeString( &symbolicName, SYMBOLICNAME );

IoDeleteSymbolicLink( &symbolicName );

if ( devObj != NULL )

{
IoDeleteDevice( devObj );
}

DbgPrint( "MyUnload" );
}


NTSTATUS SioctlCreateClose( PDEVICE_OBJECT DeviceObject, PIRP irp )

{
irp->IoStatus.Status = STATUS_SUCCESS;

irp->IoStatus.Information = 0;

IoCompleteRequest( irp, IO_NO_INCREMENT );

return(STATUS_SUCCESS);
}


/*
*
* PID信息
*
* CHAR g_szPIDInfo[20];
*
*/


PROCERSSINFO pi;


VOID CreateProcessNotifyFunction( IN HANDLE hParentId, IN HANDLE hProcessId, IN BOOLEAN bCreate )

{
PEPROCESSlProcess;

ANSI_STRINGExePath;

/*POBJECT_NAME_INFORMATION ExePath;*/

/* 如果是进程创建 */

if ( bCreate )

{
PsLookupProcessByProcessId( hProcessId, &lProcess );


/*
*
* 格式化字符串
*
* RtlZeroMemory(g_szPIDInfo, 20);
*
* RtlStringCchPrintfA(g_szPIDInfo, 20, "%d", (int)hProcessId);
*
*/


GetProcPath( hProcessId, &ExePath );

RtlCopyBytes( (PVOID) pi.name, (PVOID) ( (char *) lProcess + 0x16c), 15 );

RtlCopyBytes( pi.PATH, ExePath.Buffer, ExePath.Length );

pi.PID = hProcessId;


DbgPrint( " %s", pi.name );

DbgPrint( "%s", pi.PATH );

DbgPrint( "%x", pi.PID );


/*RtlStringCchPrintfA( pi.PATH, ExePath->Length, "%s" , ExePath->Buffer ); */


/* 设置事件为有信号,通知应用层 接收 数据 */

KeSetEvent( g_pEventObject0, 0, FALSE );

/* 等待应用层确认。。 */

KeClearEvent( g_pEventObject3 );

DbgPrint( "-- Ring3 应该 反馈 --" );


KeWaitForSingleObject( g_pEventObject3, Executive, KernelMode, FALSE, NULL );


DbgPrint( "-- RIng3 来了反馈--" );

if ( g_bREPLY != TRUE )

{
DbgPrint( "-- Ring3 决定结束进程 --" );


/*
*
*
*
* .... 其他操作
*
*
*
*/
}

DbgPrint( "-- Ring3 决定 放行 --" );

KeClearEvent( g_pEventObject3 );
}
}


NTSTATUS SioctlDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP irp )


{
PIO_STACK_LOCATIONirpSp;

ULONGinputBuffLength;

NTSTATUSstatus = STATUS_SUCCESS;

PCHARinBuf, outBuf;

PCHARbuffer = NULL;

ULONGOutputBuffLength;

HANDLEINFOhi;

irpSp = IoGetCurrentIrpStackLocation( irp );

inputBuffLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;

OutputBuffLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;


inBuf = (PCHAR) irp->AssociatedIrp.SystemBuffer;

outBuf = (PCHAR) irp->AssociatedIrp.SystemBuffer;


/*
*
* DbgPrint("-- SioctlDeviceControl --");
*
* PrintIrpInfo(irp);
*
*/


/*
*
* DbgPrint("-- 1 --");
*
* DbgPrint("IOCTL_START : %x ",IOCTL_START);
*
*/


/*
*
* if(!inputBuffLength || ! OutputBuffLength)
*
* {
*
* status = STATUS_INVALID_PARAMETER;
*
* goto END;
*
* }*/


/*
*
* DbgPrint("-- 2 --");
*
* DbgPrint("IOCTL_START : %x ",IOCTL_START);
*
*/


switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )

{
case IOCTL_START:

{
DbgPrint( " -- START --" );

/* 取得句柄对象 */

hi = *(PHANDLEINFO ) inBuf;

status = ObReferenceObjectByHandle( hi.arg1, \

GENERIC_ALL, NULL, KernelMode, (PVOID *) &g_pEventObject0, &g_ObjectHandleInfo );


status = ObReferenceObjectByHandle( hi.arg2, \

GENERIC_ALL, NULL, KernelMode, (PVOID *) &g_pEventObject3, &g_ObjectHandleInfo );


KdPrint( ("g_pEventObject0 = 0x%X , g_pEventObject3 = 0x%X\n", g_pEventObject0, g_pEventObject3) );


if ( !g_bIsNotifyRoutineSetted )

{
PsSetCreateProcessNotifyRoutine( CreateProcessNotifyFunction, FALSE );

g_bIsNotifyRoutineSetted = TRUE;
}


break;
}


case IOCTL_STOP:

{
DbgPrint( " -- STOP --" );

if ( g_bIsNotifyRoutineSetted )

{
/* 移除进程创建通知函数 */

PsSetCreateProcessNotifyRoutine( CreateProcessNotifyFunction, TRUE );

g_bIsNotifyRoutineSetted = FALSE;
}


/* 释放对象引用 */

if ( g_pEventObject0 != NULL )

{
ObDereferenceObject( g_pEventObject0 );

g_pEventObject0 = NULL;
}


if ( g_pEventObject3 != NULL )

{
ObDereferenceObject( g_pEventObject3 );

g_pEventObject3 = NULL;
}


break;
}


case IOCTL_GET_DATA:

{
ULONG nLength = sizeof(pi);

DbgPrint( " -- GET_DATA --" );

if ( outBuf == NULL && (OutputBuffLength < nLength) )

{
KdPrint( ("OutputBufferSize is too small ~!\n") );

break;
}


/*复制进程PID到输出缓冲区 */

RtlCopyBytes( (PCHAR) outBuf, (PVOID) &pi, nLength );

OutputBuffLength = nLength;

break;
}


case IOCTL_SET_REPLY:

{
RtlCopyBytes( (PVOID) &g_bREPLY, inBuf, inputBuffLength ); /* 1 字节 */

DbgPrint( "IOCTL_SET_REPLY: %d ", g_bREPLY );

break;
}
}


END:

irp->IoStatus.Status = STATUS_SUCCESS;


irp->IoStatus.Information = OutputBuffLength;

IoCompleteRequest( irp, IO_NO_INCREMENT );


return(STATUS_SUCCESS);
}


NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObject, PUNICODE_STRING RegPath )


{
NTSTATUS status;


UNICODE_STRING DriverName;


UNICODE_STRING symbolicName;


PDEVICE_OBJECT deviceObject;


RtlInitUnicodeString( &DriverName, DRIVERNAME );


RtlInitUnicodeString( &symbolicName, SYMBOLICNAME );


/* */


DbgPrint( "DriverEntry" );


/* RtlInitUnicodeString(&EventName, G_EVENT); */

status = IoCreateDevice(

pDriverObject, /* Our Driver Object */

0, /* We don't use a device extension */

&DriverName, /* Device name "\Device\SIOCTL" */

FILE_DEVICE_UNKNOWN, /* Device type */

0, /* Device characteristics */

TRUE, /* Not an exclusive device */

&deviceObject ); /* Returned ptr to Device Object */


if ( !NT_SUCCESS( status ) )


{
DbgPrint( ("Couldn't create the device object %x \n"), status );


return(status);
}

g_bIsNotifyRoutineSetted = FALSE;

pDriverObject->MajorFunction[IRP_MJ_CREATE] = SioctlCreateClose;

pDriverObject->MajorFunction[IRP_MJ_CLOSE] = SioctlCreateClose;

pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SioctlDeviceControl;

pDriverObject->DriverUnload = MyUnload;

status = IoCreateSymbolicLink( &symbolicName, &DriverName );

if ( !NT_SUCCESS( status ) )

{
DbgPrint( ("Couldn't create the symboliclink \n") );

IoDeleteDevice( deviceObject );

return(status);
}
return(STATUS_SUCCESS);
}

VOID
PrintIrpInfo(
PIRP Irp )
{
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation( Irp );
PAGED_CODE();
DbgPrint( "\tIrp->AssociatedIrp.SystemBuffer = 0x%p\n",Irp->AssociatedIrp.SystemBuffer );


DbgPrint( "\tIrp->UserBuffer = 0x%p\n", Irp->UserBuffer );


DbgPrint( "\tirpSp->Parameters.DeviceIoControl.Type3InputBuffer = 0x%p\n",irpSp->Parameters.DeviceIoControl.Type3InputBuffer );


DbgPrint( "\tirpSp->Parameters.DeviceIoControl.InputBufferLength = %d\n",irpSp->Parameters.DeviceIoControl.InputBufferLength );


DbgPrint( "\tirpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n",irpSp->Parameters.DeviceIoControl.OutputBufferLength );


DbgPrint( "\t irpSp->Parameters.DeviceIoControl.IoControlCode = %x\n",
irpSp->Parameters.DeviceIoControl.IoControlCode );


return;
}

APP

.h

typedef struct _PROCESSINFO

{
ULONGPID;

charname[16];

charPATH[256];
}PROCERSSINFO, *PPROCESSINFO;


typedef struct _HANDLEINFO

{
HANDLEarg1; /* 这个是 内核层 SET */

HANDLEarg2; /* 这个是 应用层 SET */
}HANDLEINFO, *PHANDLEINFO;


/* 全局事件 */

HANDLE g_EventHandle;

HANDLE g_hkEvent; /* 内核层句柄 */

bool g_bIsRunnig;

start函数

DWORD dwRet;

HANDLEINFO hi ;

hi.arg1 = g_EventHandle;

hi.arg2 = g_hkEvent;

bool bRet = IOControl(IOCTL_START,&hi ,sizeof(HANDLEINFO) ,NULL , 1024 ,&dwRet);

//创建监听线程

HANDLE hThread = CreateThread(NULL , 0 , (LPTHREAD_START_ROUTINE)&WorkThread ,NULL ,0, NULL);

g_bIsRunnig = true;

CloseHandle(hThread);

Sleep(1);

IOControl 函数

bool IOControl( int Ctl_code, LPVOID InputBuffer, int InputLen, LPVOID OutputBuffer, int OutputLen, LPDWORD dwRet )

{
bool bRet = false;

HANDLE hDevice = CreateFile("\\\\.\\KernelHandle", GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

if ( hDevice == INVALID_HANDLE_VALUE )
{
MessageBox( 0, "Failed To Open Device!", NULL, 0 );
return(false);
}

bRet = DeviceIoControl( hDevice, Ctl_code, InputBuffer, InputLen, OutputBuffer, OutputLen, dwRet, NULL );
CloseHandle( hDevice );
return(bRet);
}

线程函数

DWORD WINAPI WorkThread( LPVOID lParam )

{
DWORD dRet;

InitializeCriticalSection( &g_cs );

while ( g_bIsRunnig )

{
/* 等待同步时间 */

WaitForSingleObject( g_EventHandle, INFINITE ); /* 等待 驱动程序 发出 信号 */

char szBuffer[20] = { 0 };

WCHAR szMsgBuffer[100] = { 0 };

DWORD dwRet, nProcessId = 0;

EnterCriticalSection( &g_cs );

/* 接收到信号后 发出获取 本次信息 */

IOControl( IOCTL_GET_DATA, NULL, 0, &pi, sizeof(pi), &dwRet );


CString cs;

MsgDialog dlg;

UCHARdata = 0;

cs.Format( "%d ", pi.PID );

dlg.m_id = cs;

cs.Format( "%s ", pi.PATH );

dlg.m_path = cs;

cs.Format( "%s ", pi.name );

dlg.m_name = cs;

if ( IDOK == dlg.DoModal() ) /* 这个是一个对话框类 */

{
/* 允许 */

data = 1;

/* MessageBox ( 0, "允许" , "提示" ,MB_OK); */
}

IOControl( IOCTL_SET_REPLY, &data, 1, szBuffer, 20, &dwRet ); /* 设置好 用户 选择 */


LeaveCriticalSection( &g_cs );

SetEvent( g_hkEvent ); /* 通知内核 */


/* 设置同步事件为无信号,等待下一次通知 */

ResetEvent( g_EventHandle );
}

DeleteCriticalSection( &g_cs );


return(0);
}