SSDT的检测与恢复

为避免检测失效(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;
}

你可能感兴趣的:(工作,exception,object,struct,null,hook)