紫水晶编程技术论坛 - 努力打造成全国最好的编程论坛

 找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 6124|回复: 5

TP的学习笔记:用驱动实现在32位操作系统上通用的MBR保护器

[复制链接]

76

主题

267

帖子

9

精华

贵宾会员

Rank: 2Rank: 2

积分
15599
发表于 2015-8-13 14:34:57 | 显示全部楼层 |阅读模式
MBR即Master Boot Record。它是硬盘的主引导记录,它独立于操作系统之外,不管你装Windows亦或是Linux,它都存在。MBR包括了引导程序、分区表以及结束标志(0xAA55)。他被BIOS将引导程序加载在0x7c00的起始位置,检查最后两个标志位是否正确。如果正确,取出活动分区的起始扇区(引导扇区),然后跳转到活动分区的引导扇区,通过引导扇区的引导程序找到NTLDR区域。如果NTLDR文件丢失或者损坏,就会出现一段熟悉的信息:“NTLDR is missing,press Ctrl+Alt+Del to restart.”。如果你不修复或者重装,就陷入这个死循环。NTLDR是一个16位程序,它运行在实模式下,其中的一个很重要的职责就是负责实模式切换到保护模式并开启分页功能(注:实模式不支持分页,采取段首址*0x10+偏移,其所有指令均是特权指令)。然后重定位osload程序,也就是核心的启动程序,它加载核心设备驱动,比如:ftdisk.sys,atapi.sys,disk.sys等,然后再加载内核文件(即ntkrnlpa.exe,不同的机器加载的文件可能不同),此时把控制权转交给ntkrnlpa.exe,之后再加载一些其他设备驱动,服务等,最后进入系统。
著名的Bootkit的鬼影2就是先替换fips.sys驱动,并且替换了BIOS的扩展INT13,以达到接管MBR的读写。因此MBR相当重要,在NT6的操作系统下根本就无法在Ring3下使用CreateFileA+WriteFileA写MBR(尼玛这句话是谁说的,我特么在Windows 7 x64下就能实现Ring3读写MBR!)
首先我们先看看一段操作MBR的代码(VB写的在Ring3下使用CreateFileA+WriteFileA实现读写MBR的代码,包含了读取MBR,破坏MBR,检测BK,备份MBR以及重置MBR的代码):
  1. Public Sub DetectBootkit(ByVal ListBoxItem As ListBox)
  2. If ListBoxItem.List(510) <> "55" Or ListBoxItem.List(511) <> "AA" Then
  3.     MsgBox "Bootkit exists!", vbCritical, ""
  4. Else
  5.     MsgBox "No Bootkit is detected", vbInformation, ""
  6. End If
  7. End Sub
  8. Public Sub DamageMBR()
  9. Dim hFile As Long
  10. Dim buffer(511) As Byte
  11. Dim dwReadWrite As Long
  12. If MsgBox("It's a highly dangerous operation for you to damage MBR!", vbCritical + vbYesNo, "") = vbNo Then Exit Sub
  13. hFile = CreateFile("\\.\PhysicalDrive0", GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
  14. If (hFile <> INVALID_HANDLE_VALUE) Then
  15.     Call SetFilePointer(hFile, 0, 0, FILE_BEGIN)
  16.     Call ReadFile(hFile, VarPtr(buffer(0)), 512, dwReadWrite, 0)
  17.     Call SetFilePointer(hFile, 0, 0, FILE_BEGIN)
  18.     Call RtlZeroMemory(VarPtr(buffer(0)), 512)
  19.     Call WriteFile(hFile, VarPtr(buffer(0)), 512, dwReadWrite, 0)
  20.     Call CloseHandle(hFile)
  21. Else
  22.     MsgBox "Failed to call CreateFileA!", vbCritical, ""
  23. End If
  24. End Sub
  25. Public Sub BackupMBR(ByVal ListBoxItem As ListBox)
  26. Dim szTxt As String, szFileName As String: szFileName = Replace(App.Path & "\mbr.txt", "\", "")
  27. Dim i As Long
  28. For i = 0 To 511
  29.     szTxt = szTxt & ListBoxItem.List(i) & vbCrLf
  30. Next
  31. szTxt = Left$(szTxt, Len(szTxt) - 2) '去掉最后的回车
  32. Open szFileName For Output As #1
  33.     Print #1, szTxt
  34. Close #1
  35. MsgBox "The backup file has been saved as mbr.txt in current directory", vbInformation, ""
  36. End Sub
  37. Public Sub ResetMBR()
  38. 'Read Txt
  39. Dim i As Long
  40. Dim szMbr As String
  41. Dim bsMbr() As String
  42. Dim btMbr(511) As Byte
  43. szMbr = GetCodes(Replace(App.Path & "\mbr.txt", "\", ""))
  44. bsMbr = Split(szMbr, vbCrLf)
  45. For i = 0 To 511
  46.     btMbr(i) = CByte(Val("&H" & bsMbr(i)))
  47. Next
  48. 'Write Mbr
  49. Dim hFile As Long
  50. Dim dwReadWrite As Long
  51. hFile = CreateFile("\\.\PhysicalDrive0", GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
  52. If (hFile <> INVALID_HANDLE_VALUE) Then
  53.     Call SetFilePointer(hFile, 0, 0, FILE_BEGIN)
  54.     Call WriteFile(hFile, VarPtr(btMbr(0)), 512, dwReadWrite, 0)
  55.     Call CloseHandle(hFile)
  56. Else
  57.     MsgBox "Failed to call CreateFileA!", vbCritical, ""
  58.     Exit Sub
  59. End If
  60. End Sub
  61. Public Sub ReadMBR(ByVal ListBoxItem As ListBox)
  62. Dim i As Long
  63. Dim hFile As Long
  64. Dim buffer(511) As Byte
  65. Dim dwReadWrite As Long
  66. hFile = CreateFile("\\.\PhysicalDrive0", GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
  67. If (hFile <> INVALID_HANDLE_VALUE) Then
  68.     Call SetFilePointer(hFile, 0, 0, FILE_BEGIN)
  69.     Call ReadFile(hFile, VarPtr(buffer(0)), 512, dwReadWrite, 0)
  70.     Call CloseHandle(hFile)
  71. Else
  72.     MsgBox "CreateFile ERROR!", vbCritical, ""
  73.     Exit Sub
  74. End If
  75. ListBoxItem.Clear
  76. For i = 0 To 511
  77.     ListBoxItem.AddItem AddZero(Hex$(buffer(i)))
  78. Next
  79. End Sub
复制代码

作为良心作者,贴上相关声明:
  1. Option Explicit
  2. Public Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
  3. Public Declare Function SetFilePointer Lib "kernel32.dll" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
  4. Public Declare Sub RtlZeroMemory Lib "kernel32.dll" (ByVal pDestination As Long, ByVal Length As Long)
  5. Public Declare Function ReadFile Lib "kernel32.dll" (ByVal hFile As Long, ByVal lpBuffer As Long, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Long) As Long
  6. Public Declare Function WriteFile Lib "kernel32.dll" (ByVal hFile As Long, ByVal lpBuffer As Long, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long
  7. Public Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
  8. Public Const GENERIC_READ As Long = &H80000000
  9. Public Const GENERIC_WRITE As Long = &H40000000
  10. Public Const FILE_SHARE_READ As Long = &H1
  11. Public Const FILE_SHARE_WRITE As Long = &H2
  12. Public Const OPEN_EXISTING As Long = 3
  13. Public Const INVALID_HANDLE_VALUE As Long = (-1)
  14. Public Const FILE_BEGIN As Long = 0
  15. Public Function AddZero(ByVal sz As String) As String
  16.     AddZero = String(2 - Len(sz), "0") & sz
  17. End Function
  18. Public Function GetCodes(ByVal szFileName As String) As String
  19.     Dim szTextCodes As String
  20.     Open szFileName For Binary As #1
  21.         szTextCodes = StrConv(InputB(LOF(1), 1), vbUnicode)
  22.     Close #1
  23.     GetCodes = szTextCodes
  24. End Function
复制代码

看到操作MBR代码怎么写了吧,我们Hook相关函数就可以实现MBR的保护器。
初级保护MBR
由于CreateFileA的函数会走到SSDT的NtCreateFile函数下面,而Hook这个函数相当简单,由于它同时是导出函数,因此不需要用服务Index去找地址。挂钩这个函数的代码就显得很简单了。这里采用Inline Hook的方式。
  1. void HookNtCreateFile()
  2. {
  3.         PMDL pMdl;
  4.         ULONG PatchSize;
  5.         BYTE g_HookCode[5]={0xE9,0,0,0,0};//相对跳转
  6.         BYTE Jmp_Orig_Code[7]={0xEA,0,0,0,0,0x08,0x00 }; //绝对地址跳转
  7.         UNICODE_STRING uniFuncName;
  8.         RtlInitUnicodeString(&uniFuncName,L"NtCreateFile");
  9.         NtCreateFile=MmGetSystemRoutineAddress(&uniFuncName);
  10.         PatchSize=GetPatchSize(NtCreateFile,5);//获得要Patch的字节数
  11.         //构造Proxy_Func
  12.         Old_NtCreateFile=ExAllocatePool(NonPagedPool,20);
  13.         memset(Old_NtCreateFile,0x90,20);
  14.         RtlCopyMemory((PBYTE)Old_NtCreateFile,(PBYTE)NtCreateFile,PatchSize);//实现原函数头
  15.         *((PULONG)(Jmp_Orig_Code+1))=(ULONG)((PBYTE)NtCreateFile+PatchSize );//原函数+N 地址
  16.         RtlCopyMemory((PBYTE)Old_NtCreateFile+PatchSize,Jmp_Orig_Code,7);//绝对地址跳转
  17.         *((ULONG*)(g_HookCode+1))=(ULONG)fake_NtCreateFile-(ULONG)NtCreateFile-5;//计算JMP 地址
  18.         pMdl=IoAllocateMdl(NtCreateFile,5,FALSE,FALSE,NULL);
  19.         if(pMdl)
  20.         {
  21.                 __try
  22.                 {
  23.                         MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  24.                 }
  25.                 __except(EXCEPTION_EXECUTE_HANDLER)
  26.                 {
  27.                         IoFreeMdl(pMdl);
  28.                 }
  29.                 f_oldirql=KeRaiseIrqlToDpcLevel();
  30.                 KeInitializeSpinLock(&f_spinlock);
  31.                 KeAcquireSpinLockAtDpcLevel(&f_spinlock);
  32.                 _asm
  33.                 {
  34.                         cli              
  35.                         mov eax, cr0   
  36.                         and eax, not 10000h
  37.                         mov cr0, eax     
  38.                 }
  39.                 RtlCopyMemory(NtCreateFile, g_HookCode, 5);
  40.                 _asm
  41.                 {
  42.                         mov eax, cr0   
  43.                         or  eax, 10000h            
  44.                         mov cr0, eax              
  45.                         sti                  
  46.                 }
  47.                 KeReleaseSpinLockFromDpcLevel(&f_spinlock);
  48.                 KeLowerIrql(f_oldirql);
  49.                 MmUnlockPages(pMdl);
  50.                 IoFreeMdl(pMdl);
  51.         }
  52. }
复制代码

挂钩了函数之后,别忘了退出程序需要Unhook,代码如下:
  1. void UnhookNtCreateFile()
  2. {
  3.         PMDL pMdl;
  4.         pMdl=IoAllocateMdl(NtCreateFile,5,FALSE,FALSE,NULL);
  5.         if(pMdl)
  6.         {
  7.                 __try
  8.                 {
  9.                         MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  10.                 }
  11.                 __except(EXCEPTION_EXECUTE_HANDLER)
  12.                 {
  13.                         IoFreeMdl(pMdl);
  14.                 }
  15.                 f_oldirql=KeRaiseIrqlToDpcLevel();
  16.                 KeInitializeSpinLock(&f_spinlock);
  17.                 KeAcquireSpinLockAtDpcLevel(&f_spinlock);
  18.                 _asm
  19.                 {
  20.                         cli              
  21.                         mov eax, cr0   
  22.                         and eax, not 10000h
  23.                         mov cr0, eax     
  24.                 }
  25.                 RtlCopyMemory(NtCreateFile,Old_NtCreateFile,5);
  26.                 _asm
  27.                 {
  28.                         mov eax, cr0   
  29.                         or  eax, 10000h            
  30.                         mov cr0, eax              
  31.                         sti                  
  32.                 }
  33.                 KeReleaseSpinLockFromDpcLevel(&f_spinlock);
  34.                 KeLowerIrql(f_oldirql);
  35.                 MmUnlockPages(pMdl);
  36.                 IoFreeMdl(pMdl);
  37.         }
  38.         ExFreePool(Old_NtCreateFile);
  39. }
复制代码

接下来便是处理参数的过程。根据操作MBR的代码我们可以看出,要过滤的关键字是"PhysicalDrive"。那么只要过滤掉这个关键字就可以了。首先先看看NtCreateFile的函数原型:
  1. typedef NTSTATUS (*NTCREATEFILE)
  2. (
  3. OUT PHANDLE FileHandle,
  4. IN ACCESS_MASK DesiredAccess,
  5. IN POBJECT_ATTRIBUTES ObjectAttributes,
  6. OUT PIO_STATUS_BLOCK IoStatusBlock,
  7. IN PLARGE_INTEGER AllocationSize OPTIONAL,
  8. IN ULONG FileAttributes,
  9. IN ULONG ShareAccess,
  10. IN ULONG CreateDisposition,
  11. IN ULONG CreateOptions,
  12. IN PVOID EaBuffer OPTIONAL,
  13. IN ULONG EaLength
  14. );
复制代码

注意到第三个参数ObjectAttributes了没?对应的结构体OBJECT_ATTRIBUTES的结构如下:
  1. Public Type OBJECT_ATTRIBUTES
  2.         Length As Long
  3.         RootDirectory As Long
  4.         ObjectName As Long 'PUNICODE_STRING 的指针
  5.         Attributes As Long
  6.         SecurityDescriptor As Long
  7.         SecurityQualityOfService As Long
  8. End Type
复制代码

ObjectAttributes->ObjectName就是CreateFileA传递的文件名。知道了这一点,似乎就可以开始写过滤函数了。不过要知道一点:无论是ObjectAttributes还是ObjectAttributes->ObjectName以及该字符串对应Buffer,它们均是指针,而其中也有可能是无效的,所以要用MmIsAddressValid检查一遍地址的有效性。代码如下:
  1. NTSTATUS fake_NtCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG CreateDisposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength)
  2. {
  3.         UNICODE_STRING uniFileName;
  4.         NTSTATUS st;
  5.         if(MmIsAddressValid(ObjectAttributes)==TRUE)
  6.         {
  7.                 if(MmIsAddressValid(ObjectAttributes->ObjectName)==TRUE)
  8.                 {
  9.                         if(MmIsAddressValid(ObjectAttributes->ObjectName->Buffer)==TRUE)
  10.                         {
  11.                                 RtlInitUnicodeString(&uniFileName,L"PhysicalDrive");
  12.                                 if(SpyFindSubString(ObjectAttributes->ObjectName,&uniFileName)==TRUE)
  13.                                 {
  14.                                         st=STATUS_ACCESS_DENIED;
  15.                                 }
  16.                                 else
  17.                                 {
  18.                                         st=Old_NtCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
  19.                                 }
  20.                         }
  21.                         else
  22.                         {
  23.                                 st=STATUS_INVALID_PARAMETER;
  24.                         }
  25.                 }
  26.                 else
  27.                 {
  28.                         st=STATUS_INVALID_PARAMETER;
  29.                 }
  30.         }
  31.         else
  32.         {
  33.                 st=STATUS_INVALID_PARAMETER;
  34.         }
  35.         return st;
  36. }
复制代码

其中有个函数叫SpyFindSubString,它是用来检测字符串是否有重叠部分的,代码如下:
  1. BOOLEAN SpyFindSubString(PUNICODE_STRING String,PUNICODE_STRING SubString)
  2. {
  3.         ULONG Index;
  4.         if(RtlEqualUnicodeString(String,SubString,TRUE))
  5.         {
  6.                 return TRUE;
  7.         }
  8.         for(Index=0;Index+(SubString->Length/sizeof(WCHAR))<=(String->Length/sizeof(WCHAR));Index++)
  9.         {
  10.                 if(_wcsnicmp(&String->Buffer[Index],SubString->Buffer,(SubString->Length/sizeof(WCHAR)))==0)
  11.                 {
  12.                         return TRUE;
  13.                 }
  14.         }
  15.         return FALSE;
  16. }
复制代码

效果不错,已经起到了无法在Ring3下读写MBR的效果了。如图所示:

初级保护

初级保护

然而加载了驱动的RK完全可以用导出的IoCreateFile来读写MBR,所以这种保护方法太弱。
中级保护MBR
我们知道,打开文件最最最底层的函数是IopCreateFile,由于这个函数是未导出函数,所以需要定位。首先看看XP下WinDbg对其反汇编的结果,如图所示:

反汇编结果

反汇编结果

因此我们要搜索的特征码是0xE80875FF,注意不是0xFF7508E8。不明所以的人复习计算机基础去吧。。。
经检验,在windows server 2003,windows 7,windows 8的需要搜的特征码均是一样的,因此这方法可谓通用。
搜索特征码的代码如下:
  1. ULONG FindIopCreateFile()
  2. {
  3.         ULONG SrcFuncAddr=0, i=0, DWordVal=0, OffsetAddr=0;
  4.         UNICODE_STRING uniFuncName;
  5.         RtlInitUnicodeString(&uniFuncName,L"IoCreateFile");
  6.         SrcFuncAddr = (ULONG)MmGetSystemRoutineAddress(&uniFuncName);
  7.         for(i=0;i<1024;i++)
  8.         {
  9.                 if( MmIsAddressValid((PVOID)(SrcFuncAddr+i)) )
  10.                 {
  11.                         ReadKernelMemory((PVOID)(SrcFuncAddr+i),4,&DWordVal);
  12.                         if(DWordVal==0xE80875FF)        //char code of xp/win7
  13.                         {
  14.                                 ReadKernelMemory((PVOID)(SrcFuncAddr+i+4),4,&OffsetAddr);
  15.                                 return (OffsetAddr + 5 + SrcFuncAddr+i+3);
  16.                         }
  17.                 }
  18.         }
  19.         return 0;
  20. }
复制代码

为了保证安全,不直接用RtlCopyMemory读写内核内存,而是自己定义了个ReadKernelMemory函数,代码如下:
  1. NTSTATUS ReadKernelMemory(PVOID Address, ULONG Size, PVOID OutBuffer)
  2. {
  3.         NTSTATUS st = STATUS_UNSUCCESSFUL;
  4.         PMDL  pMdl = 0;
  5.         PVOID pAddress = 0;
  6.         if (!Address) return st;
  7.         pMdl = IoAllocateMdl(Address, Size, FALSE, FALSE, 0);
  8.     if (pMdl)
  9.     {
  10.         MmBuildMdlForNonPagedPool(pMdl);
  11.         pAddress = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
  12.         if (pAddress)
  13.         {
  14.                         __try
  15.                         {
  16.                                 RtlCopyMemory(OutBuffer, pAddress, Size);
  17.                                 st = STATUS_SUCCESS;
  18.                         }
  19.                         __except(EXCEPTION_EXECUTE_HANDLER)
  20.                         {                    
  21.                         }
  22.         }            
  23.         IoFreeMdl(pMdl);
  24.     }
  25.     return st;
  26. }
复制代码

找到函数的地址就好办了,直接Hook就可以了,代码如下:
  1. void HookIopCreateFile()
  2. {
  3.         PMDL pMdl;
  4.         ULONG PatchSize;
  5.         BYTE g_HookCode[5]={0xE9,0,0,0,0};//相对跳转
  6.         BYTE Jmp_Orig_Code[7]={0xEA,0,0,0,0,0x08,0x00 }; //绝对地址跳转
  7.         IopCreateFile=(PVOID)FindIopCreateFile();
  8.         PatchSize=GetPatchSize(IopCreateFile,5);//获得要Patch的字节数
  9.         //构造Proxy_Func
  10.         Old_IopCreateFile=ExAllocatePool(NonPagedPool,20);
  11.         memset(Old_IopCreateFile,0x90,20);
  12.         RtlCopyMemory((PBYTE)Old_IopCreateFile,(PBYTE)IopCreateFile,PatchSize);//实现原函数头
  13.         *((PULONG)(Jmp_Orig_Code+1))=(ULONG)((PBYTE)IopCreateFile+PatchSize );//原函数+N 地址
  14.         RtlCopyMemory((PBYTE)Old_IopCreateFile+PatchSize,Jmp_Orig_Code,7);//绝对地址跳转
  15.         *((ULONG*)(g_HookCode+1))=(ULONG)fake_IopCreateFile-(ULONG)IopCreateFile-5;//计算JMP 地址
  16.         pMdl=IoAllocateMdl(IopCreateFile,5,FALSE,FALSE,NULL);
  17.         if(pMdl)
  18.         {
  19.                 __try
  20.                 {
  21.                         MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  22.                 }
  23.                 __except(EXCEPTION_EXECUTE_HANDLER)
  24.                 {
  25.                         IoFreeMdl(pMdl);
  26.                 }
  27.                 f_oldirql=KeRaiseIrqlToDpcLevel();
  28.                 KeInitializeSpinLock(&f_spinlock);
  29.                 KeAcquireSpinLockAtDpcLevel(&f_spinlock);
  30.                 _asm
  31.                 {
  32.                         cli              
  33.                         mov eax, cr0   
  34.                         and eax, not 10000h
  35.                         mov cr0, eax     
  36.                 }
  37.                 RtlCopyMemory(IopCreateFile, g_HookCode, 5);
  38.                 _asm
  39.                 {
  40.                         mov eax, cr0   
  41.                         or  eax, 10000h            
  42.                         mov cr0, eax              
  43.                         sti                  
  44.                 }
  45.                 KeReleaseSpinLockFromDpcLevel(&f_spinlock);
  46.                 KeLowerIrql(f_oldirql);
  47.                 MmUnlockPages(pMdl);
  48.                 IoFreeMdl(pMdl);
  49.         }
  50. }

  51. void UnhookIopCreateFile()
  52. {
  53.         PMDL pMdl;
  54.         pMdl=IoAllocateMdl(IopCreateFile,5,FALSE,FALSE,NULL);
  55.         if(pMdl)
  56.         {
  57.                 __try
  58.                 {
  59.                         MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  60.                 }
  61.                 __except(EXCEPTION_EXECUTE_HANDLER)
  62.                 {
  63.                         IoFreeMdl(pMdl);
  64.                 }
  65.                 f_oldirql=KeRaiseIrqlToDpcLevel();
  66.                 KeInitializeSpinLock(&f_spinlock);
  67.                 KeAcquireSpinLockAtDpcLevel(&f_spinlock);
  68.                 _asm
  69.                 {
  70.                         cli              
  71.                         mov eax, cr0   
  72.                         and eax, not 10000h
  73.                         mov cr0, eax     
  74.                 }
  75.                 RtlCopyMemory(IopCreateFile,Old_IopCreateFile,5);
  76.                 _asm
  77.                 {
  78.                         mov eax, cr0   
  79.                         or  eax, 10000h            
  80.                         mov cr0, eax              
  81.                         sti                  
  82.                 }
  83.                 KeReleaseSpinLockFromDpcLevel(&f_spinlock);
  84.                 KeLowerIrql(f_oldirql);
  85.                 MmUnlockPages(pMdl);
  86.                 IoFreeMdl(pMdl);
  87.         }
  88.         ExFreePool(Old_IopCreateFile);
  89. }
复制代码

注意IopCreateFile和NtCreateFile的函数原型不太一样。过滤函数的代码如下:
  1. NTSTATUS fake_IopCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG Disposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength,IN CREATE_FILE_TYPE CreateFileType,IN PVOID InternalParameters OPTIONAL,IN ULONG Options,IN ULONG InternalFlags,IN PVOID DeviceObject)
  2. {
  3.         UNICODE_STRING uniFileName;
  4.         NTSTATUS st;
  5.         if(MmIsAddressValid(ObjectAttributes)==TRUE)
  6.         {
  7.                 if(MmIsAddressValid(ObjectAttributes->ObjectName)==TRUE)
  8.                 {
  9.                         if(MmIsAddressValid(ObjectAttributes->ObjectName->Buffer)==TRUE)
  10.                         {
  11.                                 RtlInitUnicodeString(&uniFileName,L"PhysicalDrive");
  12.                                 if(SpyFindSubString(ObjectAttributes->ObjectName,&uniFileName)==TRUE)
  13.                                 {
  14.                                         st=STATUS_ACCESS_DENIED;
  15.                                 }
  16.                                 else
  17.                                 {
  18.                                         st=Old_IopCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,Disposition,CreateOptions,EaBuffer,EaLength,CreateFileType,InternalParameters,Options,InternalFlags,DeviceObject);
  19.                                 }
  20.                         }
  21.                         else
  22.                         {
  23.                                 st=STATUS_INVALID_PARAMETER;
  24.                         }
  25.                 }
  26.                 else
  27.                 {
  28.                         st=STATUS_INVALID_PARAMETER;
  29.                 }
  30.         }
  31.         else
  32.         {
  33.                 st=STATUS_INVALID_PARAMETER;
  34.         }
  35.         return st;
  36. }
复制代码

这样一来,调用IoCreateFile来读写MBR的路就彻底封死了。效果如图所示:

中级保护

中级保护

然而,我们可以通过发送IRP的方式读写MBR,不过鉴于难度较大,尤其是函数党根本就不会这玩意,因此这个办法搞定大多数MBR操作还是没有问题的。
高级保护MBR
这里,我就要解密T.A的《[原创]全平台支持的EAT/IAT/OBJECT/IRP/IDT HOOK范例(WIN32)》帖子中关于Disk Hook的代码(帖子的地址:http://www.m5home.com/bbs/thread-8128-1-1.html)。其实不能说是解密,因为我只是看到附件里面没有源码而已。为了防止读写MBR,我们要Hook IRP_MJ_READ和IRP_MJ_WRITE两个例程。这里就不使用Inline Hook的方式了。因为这两个例程的地址是一样的。
首先,这里修改地址的时候,我们使用InterlockedExchangePointer函数实现,主要是因为它以原子操作的方式修改4个字节的数据,修改的过程也不会被打断,而且,还会返回要修改的位置的值。其次是定位例程的地址,首先用ObReferenceObjectByName来取得Disk.sys的驱动对象,然后找MajorFunction就好了。挂钩这两个例程的代码如下:
  1. void StartHook()
  2. {
  3.         NTSTATUS st;
  4.         UNICODE_STRING uniDiskName;
  5.         RtlInitUnicodeString(&uniDiskName,L"\\Driver\\Disk");
  6.         st=ObReferenceObjectByName(&uniDiskName,OBJ_CASE_INSENSITIVE,0,0,*IoDriverObjectType,KernelMode,0,&DiskDrvObj);
  7.         if(NT_SUCCESS(st))
  8.         {
  9.                 IrpMjRead=(IRP_MJ_SERIES)InterlockedExchangePointer(&DiskDrvObj->MajorFunction[IRP_MJ_READ],fake_IrpMjRead);
  10.                 IrpMjWrite=(IRP_MJ_SERIES)InterlockedExchangePointer(&DiskDrvObj->MajorFunction[IRP_MJ_WRITE],fake_IrpMjWrite);
  11.                 IsHooked=TRUE;
  12.         }
  13. }

  14. void StopHook()
  15. {
  16.         InterlockedExchangePointer(&DiskDrvObj->MajorFunction[IRP_MJ_READ],IrpMjRead);
  17.         InterlockedExchangePointer(&DiskDrvObj->MajorFunction[IRP_MJ_WRITE],IrpMjWrite);
  18.         ObDereferenceObject(DiskDrvObj);
  19.    IsHooked=FALSE;
  20. }
复制代码

有木有发现过程很简短啊。。。。。。用四个字来说就是返璞归真。只不过处理IRP的时候略麻烦。
任何处理IRP的Hook都要先用IoGetCurrentIrpStackLocation取得对应IRP堆栈的位置,否则得不到要处理的数据。
过滤的规则就很简单了,对读写的扇区偏移进行判定,如果是对象是磁盘设备而且是要从0扇区的位置开始的读写操作,那就拦截之。
代码如下:
  1. NTSTATUS fake_IrpMjWrite(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
  2. {
  3.         NTSTATUS status = STATUS_SUCCESS;
  4.         IO_STACK_LOCATION  *irpsp= IoGetCurrentIrpStackLocation(Irp);
  5.         LARGE_INTEGER WriteOffsetInBytes= irpsp->Parameters.Write.ByteOffset;
  6.         ULONG writeLength = irpsp->Parameters.Write.Length;
  7.         LARGE_INTEGER Sectionpos={0};
  8.         ULONG SectorRange;
  9.         BOOLEAN IsDeniedAccess = FALSE;
  10.         do
  11.         {
  12.                 Sectionpos.HighPart = 0;
  13.                 Sectionpos.LowPart = 0x200;
  14.                 SectorRange= WriteOffsetInBytes.QuadPart/Sectionpos.QuadPart;
  15.                 if(SectorRange==0 && DeviceObject->DeviceType==FILE_DEVICE_DISK)
  16.                 {
  17.                         IsDeniedAccess =TRUE;
  18.                         break;
  19.                 }
  20.         }while(0);
  21.         if (IsDeniedAccess)
  22.         {
  23.                 Irp->IoStatus.Information=writeLength;
  24.                 Irp->IoStatus.Status=STATUS_ACCESS_DENIED;
  25.                 IoCompleteRequest(Irp,IO_NO_INCREMENT);
  26.                 status=STATUS_ACCESS_DENIED;
  27.         }
  28.         else
  29.         {
  30.                 status=IrpMjWrite(DeviceObject,Irp);
  31.         }
  32.         return status;
  33. }

  34. NTSTATUS fake_IrpMjRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
  35. {
  36.         NTSTATUS status = STATUS_SUCCESS;
  37.         IO_STACK_LOCATION  *irpsp= IoGetCurrentIrpStackLocation(Irp);
  38.         LARGE_INTEGER ReadOffsetInBytes= irpsp->Parameters.Read.ByteOffset;
  39.         ULONG readLength = irpsp->Parameters.Write.Length;
  40.         LARGE_INTEGER Sectionpos={0};
  41.         ULONG SectorRange;
  42.         BOOLEAN IsDeniedAccess = FALSE;
  43.         do
  44.         {
  45.                 Sectionpos.HighPart = 0;
  46.                 Sectionpos.LowPart = 0x200;
  47.                 SectorRange= ReadOffsetInBytes.QuadPart/Sectionpos.QuadPart;
  48.                 if(SectorRange==0 && DeviceObject->DeviceType==FILE_DEVICE_DISK)
  49.                 {
  50.                         IsDeniedAccess =TRUE;
  51.                         break;
  52.                 }
  53.         }while(0);
  54.         if (IsDeniedAccess)
  55.         {
  56.                 Irp->IoStatus.Information=readLength;
  57.                 Irp->IoStatus.Status=STATUS_ACCESS_DENIED;
  58.                 IoCompleteRequest(Irp,IO_NO_INCREMENT);
  59.                 status=STATUS_ACCESS_DENIED;
  60.         }
  61.         else
  62.         {
  63.                 status=IrpMjWrite(DeviceObject,Irp);
  64.         }
  65.         return status;
  66. }
复制代码

运行保护器后,虽然能用CreateFileA打开物理磁盘,但是不能进行读写操作了。无论是调用NtWriteFile还是构造FSD的IRP甚至是SCSI的IRP都无效。要绕过这种方式保护MBR的话,可以用解析Disk.sys的方式取得原始地址并恢复或者绕过钩子,或者构造更加底层的atapi.sys的IRP包发送到DriverStartIo。那样一来仍然可以绕过这种高级保护方式,本来安全就没有绝对的。
效果如图所示:

高级保护

高级保护

文章似乎可以到此为止了,但还是有几句话要说。
一、初级以及中级的方式保护代码只需要把关键字"PhysicalDriver"改成自己的文件名就能实现文件保护器了。
二、高级的方式保护MBR可以通过禁止读取内核文件的方式防止被恢复或者绕过。
三、本文附带的附件,其附件描述摘自Hovi.Delphic的帖子,并不设置阅读权限以及水晶币。

ProtectMBR.zip

173.08 KB, 下载次数: 3405

下载代码不回帖是一种很欠扁的行为

评分

参与人数 1水晶币 +100 收起 理由
Tesla.Angela + 100 赞一个!

查看全部评分

854

主题

3481

帖子

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

Rank: 125Rank: 125Rank: 125Rank: 125Rank: 125

积分
36100
发表于 2015-8-13 15:08:49 | 显示全部楼层
我咋感觉是拿我几个以前发黑防和论坛的代码改的。。。好了,言归正传评论一下:
1.在NT5上不禁止对磁盘任意偏移的写入,NT6上只能写入前63(或64)个LBA。
2.【\\Driver\\Disk】所属的的驱动是classpnp.sys。【这句有误!】
3.WIN64AST的MBR保护是HOOK了磁盘小端口驱动IRP_MJ_SCSI。
4.以后是EFI+GPT的时代了。

76

主题

267

帖子

9

精华

贵宾会员

Rank: 2Rank: 2

积分
15599
 楼主| 发表于 2015-8-13 15:26:23 | 显示全部楼层
那啥,读写MBR的代码是直接抄你的代码。。。但读写MBR并不是文章的重点
【\Driver\Disk】所属的驱动是Disk.sys但是Disk分发例程中IRP_MJ_READ(IRP_MJ_WRITE)是属于classpnp.sys的。。。
我并没有用过win64ast的MBR保护器
第四条貌似很有道理,我老爸买了新笔记本,其硬盘只有500GB竟然也使用了UEFI+GPT,后来被我强行改成Legacy+MBR了。
(UEFI的FastBoot让我一开始不知道怎么进BIOS,尼玛!)
据说x64下不禁止Disk Hook。。。

76

主题

267

帖子

9

精华

贵宾会员

Rank: 2Rank: 2

积分
15599
 楼主| 发表于 2015-8-14 15:15:16 | 显示全部楼层
打开PCHunter,进入Kernel Module选项卡,刷新一遍,单击列首查找classpnp.sys,于是惊喜的发现它的驱动对象是"-"

854

主题

3481

帖子

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

Rank: 125Rank: 125Rank: 125Rank: 125Rank: 125

积分
36100
发表于 2015-8-15 22:58:21 | 显示全部楼层
tangptr@126.com 发表于 2015-8-14 15:15
打开PCHunter,进入Kernel Module选项卡,刷新一遍,单击列首查找classpnp.sys,于是惊喜的发现它的驱动对 ...


你对了。【\\Driver\\Disk】所属的的驱动是确实是DISK.SYS。
还有,PG只关注几个重要的驱动(NTOS、HAL、CI、KDCOM、NDIS等),其它的不管。

0

主题

31

帖子

0

精华

铜牌会员

Rank: 2Rank: 2

积分
180
发表于 2016-1-26 14:28:37 | 显示全部楼层
顶一下
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

手机版|Archiver|紫水晶工作室 ( 粤ICP备05020336号 )

GMT+8, 2024-4-20 19:36 , Processed in 0.036931 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表