为避免检测失效(rootkit惯用的hook,inline hook)一个有效的方法是,我们在进行每一项检测之前都确保自身所使用的函数没有被hook,这样就不得不涉及到ssdt恢复和一些inline hook恢复了.
ssdt是啥?原理之类的网上很多,相信感兴趣的你肯定不缺乏这方面的知识.我这里提供个方便,放个片段,
//枚举SSDT表
typedef struct _tagSSDT {
PVOID pvSSDTBase;
PVOID pvServiceCounterTable;
ULONG ulNumberOfServices;
PVOID pvParamTableBase;
} SSDT, *PSSDT;
NTSTATUS SSDT_IoCtlDispath( IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait, IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject )
{
NTSTATUS ntStatus;
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = 0;
switch ( IoControlCode )
{
case IOCTL_GETSSDT:
{
__try
{
ProbeForWrite( OutputBuffer, sizeof( SSDT ), sizeof( ULONG ) );
RtlCopyMemory( OutputBuffer, KeServiceDescriptorTable, sizeof( SSDT ) );
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
IoStatus->Status = GetExceptionCode();
}
}
break;
case IOCTL_GETPROC:
{
ULONG uIndex = 0;
PULONG pBase = NULL;
__try
{
ProbeForRead( InputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
ProbeForWrite( OutputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
IoStatus->Status = GetExceptionCode();
break;
}
uIndex = *(PULONG)InputBuffer;
if ( KeServiceDescriptorTable->ulNumberOfServices <= uIndex )
{
IoStatus->Status = STATUS_INVALID_PARAMETER;
break;
}
pBase = KeServiceDescriptorTable->pvSSDTBase;
*((PULONG)OutputBuffer) = *( pBase + uIndex );
}
break;
default:
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return IoStatus->Status;
}
当前地址通过与原始地址比较,如果不相同则是被hook了.接下来是SSDT全局恢复工作.(当然你也可以有针对性的恢复)
NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
NTSTATUS status=STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIrpStack=IoGetCurrentIrpStackLocation(pIrp);
ULONG uIoControlCode=pIrpStack->Parameters.DeviceIoControl.IoControlCode;
PVOID pInputBuffer= pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
PVOID pOutputBuffer=pIrp->UserBuffer;
ULONG uInsize=pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG uOutsize=pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch(uIoControlCode)
{
case IOCTL_SETPROC:
{
ULONG uIndex = 0;
PULONG pBase = NULL;
__try
{
ProbeForRead( pInputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
ProbeForWrite( pOutputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
status= GetExceptionCode();
break;
}
uIndex = *(PULONG)pInputBuffer;
if ( KeServiceDescriptorTable->ulNumberOfServices <= uIndex )
{
status= STATUS_INVALID_PARAMETER;
break;
}
pBase = KeServiceDescriptorTable->pvSSDTBase;
DbgPrint("0x%x 0x%x",uIndex,*((PULONG)pOutputBuffer));
__asm
{//关中断
cli
mov eax,cr0
and eax,~0x10000
mov cr0,eax
}
*( pBase + uIndex )=*((PULONG)pOutputBuffer);
__asm
{//开中断
mov eax,cr0
or eax,0x10000
mov cr0,eax
sti
}
status=STATUS_SUCCESS;
}
break;
default:
break;
}
if(status==STATUS_SUCCESS)
pIrp->IoStatus.Information=uOutsize;
else
pIrp->IoStatus.Information=0;
pIrp->IoStatus.Status=status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}