用磁盘类驱动ObjectHook来保护MBR

MBR 是硬盘的主引导记录,它独立于操作系统之外,不管你装 Windows 操作系统还是
Linux 操作系统等等,它都存在,它包括引导程序、分区表、结束标志(0x55AA)。它被
bios将引导程序加载在0x7C00的起始位置,检查最后的两位标志位是否正确,如果正确,
取出活动分区的起始扇区(引导扇区),然后跳转到活动分区的引导扇区,通过引导扇区的
引导程序在找到 NTLDR 区域,如果 NTLDR 文件丢失或者损坏,就会出现一段熟悉的信
息:”NTLDR is missing,please Ctrl+Alt+Del”,然后你就只有重启计算机,或者修复
NTLDR。NTLDR(startup.com +osload), startup.com是16位的程序,它运行在实模式,其
中很重要的工作就是负责将实模式(不支持分页,采取段首址*0x10+偏移,所有读写都是特
权指令)切换到保护模式并且开启分页功能。然后重定位 osload 程序,这个就是核心的启
动程序,它加载核心设备(BOOT 型)的驱动,比如:ftdisk.sys、atapi.sys、disk.sys 等
等,加载后再加载 ntoskrnl.exe,控制权在交给 ntoskrnl.exe 程序,加载一些其他设备驱
动、服务等等,最后进去系统。具体的细节我以后在跟大家讨论。鬼影 2 就是替换
fips.sys驱动,并且替换bios的扩展in113,来接官对MBR的读写。所以MBR是极其重要,
在vista以后的系统,微软也意识到MBR的重要性,所以对MBR采取了保护措施,不能随便
改写,由于微软不在支持windows xp的升级,所以winxp下的MBR经常被病毒、木马利用。
但是目前还有很多用户在使用 winxp,下面我给大街介绍一种保护 MBR 的方式,通过 OBJECT
HOOK来实现。  

通过对磁盘类驱动的IRP_MJ_WRITE的分发例程进行OBJECT HOOK,对写入的扇区偏移来进
行判定,如果是第一分区(mbr在第一分区的0柱面 0磁道0扇区)的磁盘设备,并且偏移
扇区为0,也就是从0扇区里的位置开始写入的操作全部拦截,从而保护mbr不被修改。我
的方法过于简单,可以将未被修改的 MBR512 个字节的内容进行 HASH。然后对要写入的 512
个字节也进行 HASH,如果 hash 值不同,则 MBR 证明已被修改过,则拦截该写入操作。主要
代码如下:  

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
    UNICODE_STRING uniobjname={0};
    PDRIVER_OBJECT diskdrvobj; 
    NTSTATUS status;
if ( g_bHooked&& g_Origal_disk_Write_Dispatch)
  {

 RtlInitUnicodeString(&uniobjname,L"\\Driver\\Disk");  
     status = ObReferenceObjectByName(&uniobjname,
              OBJ_CASE_INSENSITIVE,
              0,
              0,
              *IoDriverObjectType,
              KernelMode,
              0,
           &diskdrvobj);
  if (NT_SUCCESS(status))
  {
   
InterlockedExchangePointer(&diskdrvobj->MajorFunction[IRP_MJ_WRITE],(PDRIVER
_DISPATCH)g_Origal_disk_Write_Dispatch); 
    g_bHooked =FALSE;
       ObDereferenceObject(diskdrvobj);
  }
    
  }
  return;
}
PDEVICE_OBJECT GetFirstPartitionDevice()
{
  UNICODE_STRING uniobjname={0};
  PDRIVER_OBJECT diskdrvobj;
  NTSTATUS status; 
  PDEVICE_OBJECT result=NULL;
  PDEVICE_OBJECT findev;
  RtlInitUnicodeString(&uniobjname,L"\\Driver\\Disk");  
  status = ObReferenceObjectByName(&uniobjname,
            OBJ_CASE_INSENSITIVE,
         0,
         0,
         *IoDriverObjectType,
         KernelMode,
0,

 

  •  

  &diskdrvobj);
  if (!NT_SUCCESS(status))
    return result; 
  findev = diskdrvobj->DeviceObject;
  while (findev)
  {
     if (findev->DeviceType == FILE_DEVICE_DISK)  
  result = findev;
findev = findev->NextDevice;
  }
ObDereferenceObject(diskdrvobj);
return result;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING
RegistryPath)
{
   NTSTATUS status=STATUS_SUCCESS;
   PDRIVER_OBJECT diskdrvobj;
   UNICODE_STRING uniobjname={0};
   PDRIVER_DISPATCH originalDispatch=NULL;
    RtlInitUnicodeString(&uniobjname,L"\\Driver\\Disk"); 
    DriverObject->DriverUnload=DriverUnload;
    status = ObReferenceObjectByName(&uniobjname,
             OBJ_CASE_INSENSITIVE,
          0,
          0,
          *IoDriverObjectType,
          KernelMode,
          0,
          &diskdrvobj);
   if (NT_SUCCESS(status))
   {
     originalDispatch =
(PDRIVER_DISPATCH)InterlockedExchangePointer(&diskdrvobj->MajorFunction[IRP
_MJ_WRITE],
                                                                 
fake_disk_Write_dispatch);
     if (originalDispatch)
     {
g_Origal_disk_Write_Dispatch = originalDispatch;
      g_bHooked = TRUE;
     }
ObDereferenceObject(diskdrvobj);
   }
  return status;
}
//这里过滤掉对MBR的读写
NTSTATUS fake_disk_Write_dispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP
Irp)
{
  NTSTATUS status = STATUS_SUCCESS;
IO_STACK_LOCATION  *irpsp= IoGetCurrentIrpStackLocation(Irp);
  LARGE_INTEGER WriteOffsetInBytes= irpsp->Parameters.Write.ByteOffset;
  ULONG writeLength = irpsp->Parameters.Write.Length;
  LARGE_INTEGER Sectionpos={0};
  ULONG SectorRange;  
使用自己编写的程序进行测试或者使用 Winhex 以及内核读写扇区的工具 SectorEditor
来修改 MBR,发现对 MBR扇区的写操作全部无效。效果示意图如下:
 
图1
  这样不管你是在内核用NTWriteFilr 来写磁盘 MBR 还是通过构造 Scst写操作包发送至
DR0来改写MBR,全部无效,当然你可以发向更底层的端口驱动atapi.sys的StartIo或者重
定位类驱动的写例程,那样还是可以绕过这种保护,本来安全就没有绝对的,谢谢大家!
(编辑提醒,本文涉及的代码直接在PDF 附件下载即可)                           
  BOOLEAN IsDeniedAccess = FALSE; 
  PDEVICE_OBJECT firstPartition; 
  do 
  {
    firstPartition=GetFirstPartitionDevice();  
    Sectionpos.HighPart = 0;
    Sectionpos.LowPart = BytesBySECTION;
    SectorRange= WriteOffsetInBytes.QuadPart/Sectionpos.QuadPart;
    //保护 MBR
 if ( SectorRange==0 && firstPartition == DeviceObject)
    {
      IsDeniedAccess =TRUE;
   break;
 }
  } while(0);
  //不让其写入,直接往上返回,其实这方法不好,不如读取MBR 的内容进行hash,
和保存好的Hash比较判定
  if (IsDeniedAccess)
  {
      Irp->IoStatus.Information = writeLength;
   Irp->IoStatus.Status =   STATUS_SUCCESS;
   IoCompleteRequest(Irp,IO_NO_INCREMENT); 

return status; 
  }
  else
  {
    status = g_Origal_disk_Write_Dispatch(DeviceObject,Irp);
  }
return status;
}

 

使用自己编写的程序进行测试或者使用 Winhex 以及内核读写扇区的工具 SectorEditor
来修改 MBR,发现对 MBR扇区的写操作全部无效。

用磁盘类驱动ObjectHook来保护MBR_第1张图片

  这样不管你是在内核用NTWriteFilr 来写磁盘 MBR 还是通过构造 Scst写操作包发送至
DR0来改写MBR,全部无效,当然你可以发向更底层的端口驱动atapi.sys的StartIo或者重
定位类驱动的写例程,那样还是可以绕过这种保护,本来安全就没有绝对的,谢谢大家!

原文地址 http://www.jybase.net/windows/20111207700.html

你可能感兴趣的:(linux,windows,MBR,磁盘驱动,ObjectHook)