已阅读5页,还剩15页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
高级Bootkit :Tophet.a摘要: 本文揭示了一种新型的Bootkit技术:Tophet,以及其第一代范本Tophet.a使用的一些新颖的技术。Tophet.a并非病毒或木马,只用来演示高级的启动、穿透与隐身技术。 Bootkit是更高级的Rootkit,该概念最早于2005年被eEye Digital公司在他们的“BootRoot项目中提及,该项目通过感染MBR(磁盘主引记录)的方式,实现绕过内核检查和启动隐身。可以认为,所有在开机时比Windows内核更早加载,实现内核劫持的技术,都可以称之为Bootkit,例如后来的BIOS Rootkit , VBootkit,SMM Rootkit等。 在现在MBRBoot SectorNt OS Loader这些众所周之的位置都被HIPS监视软件、检查软件严防死守,而BIOS, SMM, ROM firmware 之类的启动位置又存在被锁定或通用性不够好的时候,如何简单、通用,又有效地进行Windows内核启动劫持呢?Tophet.a使用了一种新的方式:NtBootdd.sys。 同时,Tophet.a揭示了一些磁盘级的穿透、隐藏技术,可以穿透目前所有防御软件,进行安装,同时在目前任何Rootkit文件检测技术下隐身。关键字:Bootkit 内核劫持 磁盘穿透与隐藏第一章:启动 最早的Bootkit使用MBR(主引导记录)感染或Boot Sector(启动引导扇区)感染手段来实现早于Windows内核启动,一般考虑MBR或BootSector中的代码负荷有限,会在感染代码中,挂钩Windows内核,再进一步实现具体功能,常用手段是挂钩INT 0x13中断,干涉nt os loader对内核文件的读取, 实现 Windows内核挂钩。 现在看来,这种手段不免过于原始,对MBR / BootSector这些关键位置,只要严格防御或者定时检查,即使Bootkit在系统启动获得控制权后对MBR或BootSector扇区的感染进行隐藏,也难逃使用低级磁盘读写的检查恢复方式。 感染ntldr和os loader的方式,存在和上面的感染方式同样的问题。 至于BIOS Rootkit , SMM Rootkit , VBootkit,由于其过于依赖硬件,除了有通用性的难题,再则硬件厂商也开始逐步注意安全问题,BIOS和SMM的写入锁定,启动时抢占VM root等方式,也限制了这类Rootkit的应用。 如何不感染系统关键文件、位置和硬件,来实现内核劫持呢? boot.ini是一个很好的突破点。 boot.ini中的很多选项都可以用来实现内核劫持,例如启动条目的/KERNEL,/HAL参数可以用来进行内核文件的替换和劫持,这已经是众所周之的了。另外,DEBUG选项和VGA选项都可以用来做劫持或辅助劫持 Vista操作系统已不再使用boot.ini这个文件作为启动配置,其启动配置保存于SystemPartitionbootbcd这个HIVE文件中,而这个HIVE的注册表项中的GUID即是相关的启动选项,与以往的boot.ini并没有本质上的区别,本文将不为Vista操作系统做特别讨论,下面的相关细节都以Windows XP 操作系统为准。 比起简单的/KERNEL参数替换内核,这里tophet.a用的是更为隐蔽的方式。 我们知道,Windows NT的启动过程简单来说是这样的: BIOS进行上电引导自检等操作后,将控制权交给主引导记录(MBR)的引导代码,引导代码读取硬盘分区表(DPT)后,找到引导分区,并将控制权移交启动扇区(Boot Sector)的启动代码,启动代码使用其自带的只读FAT32或NTFS的代码,读出其根目录下的NTLDR文件,并将控制权交给NTLDR中的代码,NTLDR首先将系统切换到保护模式,并开启分页机制,然后控制权被交给NTLDR体内的OSLoader.exe,OSLoader读入boot.ini文件,根据配置的启动条目显示启动菜单,等待用户选择(如果只有一个启动项 , 则直接启动那个启动项, 不显示启动菜单),用户选择指定的启动项目后,便会引导相应的项目。 下面是一个普通的boot.ini中的一条启动项:multi(0)disk(0)rdisk(0)partition(1)WINDOWS=Microsoft Windows XP Professional /noexecute=optin /fastdetect boot.ini中启动项是符合ARC(Advanced RISC Computing)命名规范的。 请注意前面的multi(0),Windows有三种语法:multi , scsi 和signature。当引导卷所在的磁盘控制器支持BIOS的 INT 0x13中断读写磁盘时,就会使用multi语法,这也是绝大部分系统上使用的语法。而scsi语法则是当磁盘控制器不支持INT 0x13指令时使用的,此时,NTLDR在确定了引导项后,会从根目录加载一个名为NtBootdd.sys的文件,将其绑定到OSLoader上,OSLoader中包含的只读NTFS/FAT32代码会使用该驱动来读写磁盘,实现Windows内核文件(ntoskrnl.exe)、硬件抽象层文件(hal.dll)和BOOT驱动文件的加载。 那么,我们只需要将boot.ini中当前系统的启动条目中的multi语法改为scsi语法,系统就会在进行内核加载前,加载我们放置在根目录下的NtBootdd.sys文件了。 这里介绍一个小技巧:如何知道当前系统是由boot.ini中的哪个启动条目引导的呢?在WindowsXP及以后的操作系统中很简单,注册表的HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControl键下的SystemBootDevice键值就保存着当前系统引导的启动项目的内容,用该键值的内容同boot.ini的条目对比,不难发现引导当前的系统的启动条目。 在Windows 2000操作系统上则稍微复杂点,该系统上并没有这么一个键值,但HKEY_LOCAL_MACHINESystemSetup键下有个名为SystemPartition的键值,该值指明了当前启动卷的设备名,例如:DeviceHarddiskVolumeX“(X为磁盘分区号),而在系统对象目录的ArcName目录下保存了这些磁盘设备名对应的ARC名,形如multi(0)disk(X)rdisk(Y),这些Arc名实际是一些符号链接(Symbolic Link),在对象目录中匹配取得启动卷的设备名对应的ARC名,再在Boot.ini中匹配ARC名,即可确定当前的启动条目。 言规正传,OSLoader在读入boot.ini到其数据段的一块缓存并确定了启动条目后,首先会检查该条目的前5个字符是不是:scsi(,如果是,就会调用名为AEInitializeIo()的函数,该函数会调用BlLoadImage函数加载根目录下的NtBootdd.sys 到内存中,然后使用BlAllocateDataTableEntry函数为该模块分配一个名为NTBOOTDD.SYS的DataTableEntry(该表类似于Windows内核使用的PsLoadedModuleList,是OSLoader用来管理加载模块使用的,在引导Windows内核过程中,会被复制到PsLoadedModuleList 中)。 接着它会扫描OSLoader的引入表,将NtBootdd.sys所引出的ScsiPort读写函数绑定到OSLoader的引入表中,然后会调用 NtBootdd.sys的入口点,以便NtBootdd.sys完成自己的初始化工作,如果初始化返回成功,则继续进行名为HardDiskInitialize的函数,让以后的磁盘读写操作都通过NtBootdd.sys来实现,若返回失败,则结束AEInitializeIo函数,继续正常的引导过程。 那么我们用来劫持的NtBootdd.sys要完成的工作就是:1. 不导出任何函数,这样就不会影响OSLoader的引入表2. 在初始化函数中完成相关的钩子例程及处理例程,然后返回失败,让系统仍然使用INT 0x13来读写磁盘3. 需要注意的是,我们需要在初始化例程中将ntldr中已读入的boot.ini进行修改,将scsi语法重新改回multi语法,否则在后面的引导过程中ntldr会认为我们使用了错误的引导语法,导致系统无法启动。读入的boot.ini是保存在OSLoader的数据段的一个全局变量中的,我们扫描整个OSLoader镜像,即可找到需要修改的数据。4. 为了劫持内核,Tophet.a进行了这样的工作:因为调用 NtBootdd.sys的初始化例程的函数是AEInitializeIo,那么我们在初始化例程中通过堆栈就可以轻松找到该函数 call DriverEntry的下一条指令位置,然后我们从这条指令向上搜索,就可以准确稳定地找到BlLoadImage函数的地址,OSLoader正是通过这个函数来加载包括Windows内核文件、HAL和boot驱动的模块的,我们挂钩该函数,就可以准确地知道Windows内核文件加载的瞬间,并对其内存镜像进行修改和劫持。下面是Tophet.a的NtBootdd.sys的DriverEntry函数NTSTATUS_declspec(naked) DriverEntry(ULONGxx , ULONGxx1)_asm/将esp保存,接下来的domywork函数会根据该值找到堆栈中call DriverEntry的下一条指令,并搜索、挂钩BlLoadImagemovSavedEsp , esppush eaxpushebx/NTLDR 会将osloader.exe重定位到它的PE头的ImageBase域指示的地址/因此我们从0x400000开始搜索/这个地址可以根据osloader的ImageBase不同改变(安装时自修改)mov eax , 0x400000 /搜索范围0x80000字节movebx , 0x7FFFALoopFind:/寻找 字符串scsicmp dword ptreax + ebx , 0x69736373jnzNotCatch/寻找 字符串(cmpword ptreax + ebx + 4 , 0x2828/osloader.exe会读入boot.ini并将其放到自己的全局变量中jnzNotCatch/将其改为multi,否则系统将无法正常启动movdword ptreax + ebx , 0x746c756dmovbyte ptreax + ebx + 4 , 0x69jmpFindmultiNotCatch:dec ebxtestebx , ebxjnzLoopFind/无法找到,重启系统 moval , 0xfeout0x64 , alFindmulti:calldomywork/实现钩子例程popebxpopeaxmoveax , 1/返回错误值,这样OSLoader将不会再做scsi初始化等操作,而是正常启动retn 8 在挂钩了BlLoadImage后,我们判断如果加载的模块是ntoskrnl(LoaderSystemCode标记或是分析镜像),就可以实现对ntoskrnl镜像的修改了,例如可以搜索MmLoadSystemImage函数并进行挂钩,或者是替换内核PE头中的EntryPoint入口点位置,这样就完成了Windows内核的劫持。第2章 :隐身 Tophet.a 是一个纯RING0的 Rootkit, 通过OSLoader来引导,因此它的隐身不涉及注册表的隐藏和进程的隐藏,那么剩下的就是内核模块和文件的隐藏。 内核模块的隐藏很简单, Ntbootdd.sys在引导完成后,不会被复制到PsLoadedModuleList列表中,也不是一个驱动对象,那么它剩下的就只有一个内存镜像了,我们在系统启动完成后抹去DOS头和PE头,它就只剩下一块内存了。 这里有个问题,在内核劫持中,如果利用/KERNEL,/HAL参数,或者NtBootdd.sys进行内核劫持时,会遇到一个小麻烦:Windows内核在进行内核初始化时,会调用一个名为MmInitSystem的函数来初始化Windows内存管理组件,其中会调用一个名为MiReloadBootLoadedDrivers的函数,该函数会将ntldr加载的模块,除了ntoskrnl.exe和hal.dll外,全部重新分配内存来存放,包括boot驱动、kdcom.dll和Bootvid.dll(WindowsXP以后系统的调试模块和启动过程的显示驱动),同时释放之前存放它们的内存,这样,如果你在该函数执行之前实行了挂钩动作,或者导出了某些函数(例如进行/HAL劫持时),那么系统便会由于你所在的内存被释放而崩溃。要解决此问题,除了在初始化内核完毕后再挂钩外,有个简单的小方法,那就是欺骗这个函数,告诉它你的模块并没有重定位信息,这样该函数就不会为你的模块做reload操作了。 在Windows XP及以后的操作系统,只要将PeHeader-FileHeader-Characteristics 中加入IMAGE_FILE_RELOCS_STRIPPED 标志即可在Windows 2000上,则需要重定位的数据目录清空:PeHeaderOptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC-VirtualAddress = 0 ; 下面则是重头戏了,文件隐藏。 最早的Rootkit使用挂钩内核API NtQueryDirectoryFile来隐藏自身的文件,稍高级的Rootkit会挂钩文件系统驱动:FSD(File System Driver)上的IRP_MJ_DIRECTORY_CONTROL处理例程并过滤IRP_MN_QUERY_DIREC-TORY请求 来隐藏文件。Anti-Rootkit工具使用恢复钩子,或者自行读取磁盘数据,并分析文件系统结构,再同原始结果对比的方式检测。 后期的Rootkit开始在磁盘级做隐藏,例如AK922,Hook了IofCompleteRequest过滤磁盘的读请求,并在Anti-Rootkit工具的磁盘解析下隐藏自身,成功绕过了Rootkit Unhooker , FileReg等检测工具,但缺点是有明显的钩子痕迹。 这里Tophet.a使用了一种新型的磁盘过滤技术,不使用inline hook方式,也不使用任何Object hook方式,就可以实现磁盘请求的过滤。目前也没有任何检测软件和工具可以检测出这种过滤方式,我称之为对象劫持。 我们知道,Windows管理驱动设备栈,是使用的DeviceObject 中的AttachedDevice域,例如在我的虚拟机上,一个磁盘请求IRP发送到Disk.sys的磁盘设备后,会被接着转发到总线上的Atapi.sys的端口设备,实际是存在这样的关系:Atapi.sys的设备(例如DeivceIdeIdeDevicePOTOLO-3)的AttachedDevice域 = Disk.sys的设备(例如DeviceHarddisk0DR0) 。如图,DeviceTree 显示的结果:著名的DeviceTree工具就是使用驱动设备间的AttachedDevice域的关系来分析出驱动设备间的树形关系的。那么,系统是依靠这个域来决定IRP该向下面的哪个设备发送的吗? 并非如此。 事实上,大多数情况都是驱动在自己创建的设备对象的设备扩展(这是驱动为设备分配并确定一个自定义结构)中,保存了一个其附加到的下层驱动设备的对象。例如DeviceHarddisk0DR0的处理例程的驱动程序是classpnp.sys,它在该设备的设备扩展(DeviceObject-DeviceExtension) 结构中保存了下层的设备DeivceIdeIdeDevicePOTOLO-3的DeviceObject,然后当需要向下转发IRP时,就使用该DeviceObject,由于这个DeviceObject是保存在其自定义结构中的,不了解这个结构的检测工具根本不知道这个IRP究竟会发到哪一个下层设备。我们只需要替换这个结构中的DeviceObject指针,就可以轻松地将IRP劫持到我们的驱动中来,在其中做一些过滤工作,下层和上层驱动根本不知道发生了这样的变动。Tophet.a自己创建了一个虚假的DriverObject和DeviceObject(并不使用系统的标准函数IoCreateDevice,而是使用ExAllocatePool自己分配内存),然后通过AttachedDevice域确定磁盘设备的上层和下层设备关系,对我们的虚假DeviceObject,只填充其中一些重要的域,并保持和原始的下层DeviceObject一致,例如StackSize , 并将其中的DriverObject域填充为我们的虚假DriverObject,同时将该DriverObject的MajorFunction填充为我们自己的处理函数,最后搜索上层设备的设备扩展,找到保存了下层设备对象的域位置,填充为我们的虚假DeviceObject, 于是劫持完成。 接下来,所有由磁盘设备发送到总线驱动的IRP都会首先经过我们的处理函数,只要我们在我们的MajorFunction中过滤我们关心的内容,例如劫持完成例程,或者是修改访问的扇区号等,接下来再调用原始的下层设备的处理函数,就可以轻松地进行磁盘隐藏工作了。 这种方式的好处是没有任何HOOK(例如inline hook IofCompleteRequest 或IofCallDriver),也没有任何标准的对象内容被劫持(例如Driver Dispatch hook ,Attached Device等),现有的检测方法极难检测到此种劫持,目前没有任何工具可以检测到Tophet.a的劫持。同时这种劫持方式不止可以用于磁盘过滤,文件过滤,网络过滤等也可以使用类似的对象劫持技术实现。第3章 :穿透 接下来是最后的内容,如何穿透各类保护/还原程序,将我们的Bootkit安装到目标系统上呢?由于Tophet.a Bootkit只需要改写两个文件即可完成安装,那么我们的问题就是如何穿透主动防御软件、磁盘还原软件,将我们的数据写入目标系统的硬盘上。我们知道,主动防御软件通常使用SSDT HOOK监视Ring3程序对PhysicalDriveX(X为物理磁盘号)等符号链接的打开或写入来监视物理磁盘操作,并通过SSDT HOOK拦截非受信的驱动加载,同时通过文件过滤驱动监视文件操作,而磁盘还原软件通过会在磁盘卷及物理磁盘设备上做HOOK或过滤,拦截或旁路对于物理磁盘或磁盘卷的读写。如何在这些软件的防御下写入真实磁盘呢?既然无法加载驱动,我们就只有在Ring3下进行穿透了,既然读写已经被拦截或旁路,那么我们可以发送SCSI_PASS_THROUGH指令给磁盘设备。简单介绍一下背景:何为SCSI_PASS_THROUGH? 这是系统提供的一组发送给磁盘设备的PassThrough控制码:IOCTL_SCSI_PASS_THROUGH、IOCTL_ATA_PASS_THROUGH和IOCTL_IDE_PASS_THROUGH等通常,Ring3程序可以通过DeviceIoControl函数向磁盘设备发送这些I/O Control Code, 它的输入缓存保存的是一个类似SCSI_REQUEST_BLOCK的结构,可以向磁盘控制器发送一些SCSI标准指令,可以实现磁盘的读写,擦除等操作。但是对于类似HIPS软件拦截了RING3对物理磁盘设备磁盘卷设备的访问,RING3如何能够打开需要对其发送请求的物理磁盘设备呢?实际上,磁盘设备是这样处理PASS_THROUGH指令的:直接将该请求转发到了下层的总线设备上,下层的总线设备驱动(例如atapi.sys)会分析该请求,并重新封装成IRP,发送给总线端口设备,总线端口设备将其转化为Io Packet,最后调用HAL导出的端口读写函数读写磁盘控制器端口来完成SCSI指令的操作。因此我们将请求直接发送到总线设备上,一样可以成功执行SCSI命令。幸运的是,系统暴露给了RING3使用的总线驱动设备的符号连接,只要打开总线设备对应的符号连接,并通过DeviceIoControl向其发送PassThrough指令,就可以进行穿透了,如图:Tophet.a 通过NtQueryDirectoryObject , NtQuerySymbolicLinkObject等函数遍历对象目录的根目录,找到当前物理磁盘对应总线设备的符号连接,打开后填充SCSI_PASS_THROUGH结构,并发送DeviceIoControl,穿透磁盘保护。下面是Tophet.a穿透磁盘部分代码,bypassdisk_write_disk函数,BusDevicename是找到的总线设备连接,DataBuf是要写入的数据缓冲,LBA为要写入的磁盘扇区号:ULONGbypassdisk_write_disk(LPCSTR BusDevicename , PVOID DataBuf , ULONG LBA) HANDLE hdev = CreateFile(BusDevicename ,FILE_READ_DATA | FILE_WRITE_DATA ,0 , 0,OPEN_EXISTING , 0,0);if (hdev = INVALID_HANDLE_VALUE) return 0 ;/打开总线设备的符号连接SCSI_PASS_THROUGH passthru ; ULONGBlockCount = 1 ; /一次写入一块BlockZeroMemory(&passthru , sizeof(passthru);passthru.CdbLength = 10 ; passthru.Length = 0x2c;passthru.Lun = 0 ; passthru.PathId = 0 ;passthru.ScsiStatus = 0 ; passthru.SenseInfoLength = sizeof(passthru.SenceInfo);passthru.TargetId = 0; passthru.DataIn = SCSI_IOCTL_DATA_OUT ; passthru.DataTransferLength = sizeof(passthru.bDataBuf) ; passthru.TimeOutValue = 5000 ; passthru.DataBufferOffset = (ULONG)&passthru.bDataBuf - (ULONG)&passthru;passthru.SenseInfoOffset = (ULONG)&passthru.SenceInfo - (ULONG)&passthru; passthru.Cdb0 = SCSIOP_WRITE;passthru.Cdb1 = 0x00 ; passthru.Cdb2 = (LBA24)&0xff ; passthru.Cdb2 = (LBA 24) & 0xFF; passthru.Cdb3 = (LBA 16) & 0xFF; passthru.Cdb4 = (LBA 8) & 0xFF; passthru.Cdb5 = (LBA 0) & 0xFF; passthru.Cdb6 = 0x00; passthru.Cdb7 = (BlockCount 8) & 0xFF; passthru.Cdb8 = (BlockCount 0) & 0xFF; passthru.Cdb9 = 0x00; CopyMemory(passthru.bDataBuf , DataBuf , 512); DWORD br ; if (!DeviceIoControl(hdev , IOCTL_SCSI_PASS_THROUGH,&passthru , sizeof(passthru) , &passthru,sizeof(passthru),&br , 0)CloseHandle(hdev);return 0 ; CloseHandle(hdev);return 1; 目前的在磁盘卷及磁盘卷上做监视的还原软件都无法拦截该种穿透写入方式,Tophet.a利用这种方式将其文件数据写入boot.ini和NtBootdd.sys就可以成功安装到目标系统上,绕过了所有的防御体系。需要注意的是
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 房屋诚意金合同范本
- 房屋转让建设协议书
- 房屋销售合同协议书
- 房车出行协议书范本
- 手工活代加工协议书
- 手机厂家供货协议书
- 手机网点维修协议书
- 打工员工安全协议书
- 托养合同协议书范本
- 托管委托接送协议书
- Unit 2 how to keep healthy作文课件 英语八年级上册
- 土木工程施工课程设计完整版
- 农产品物流配送中心建设项目可行性研究报告
- 专转本英语800个词组复习
- 胶质瘤治疗课件
- 万人计划蓝色简约万人计划青年拔尖人才答辩PPT模板
- 《梅岭三章》 完整版课件
- 2022年四川省绵阳市涪城区东辰国际学校小升初数学试卷
- 气管镜科室讲课ppt课件(PPT 69页)
- 钢-混凝土叠合梁施工
- 中央电大(国开)专科《电工电子技术》机考题库及答案
评论
0/150
提交评论