主动防御技术浅析

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

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

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

涉及到的关键系统服务表 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);
}