【梅哥的Ring0湿润插入教程】重磅第三课:Ring0下的PE Loader及重加载内核秒杀一切内核级钩子(上篇)

【梅哥的Ring0湿润插入教程】

Email:mlkui@163.com 转载请注明出处,谢绝喷子记者等,如引起各类不适请自觉滚J8蛋!

第三课:Ring0下PE Loader及重加载内核绕过一切内核级钩子(上篇)

       随着驱动保护技术的逐步成熟,诸如网络游戏公司等越来越多的商业软件公司开始使用Ring0级保护技术保护自己的产品,以起到反用户级调试、反RootKit、反各类钩子、反各类远程注入等作用。目前,使用驱动保护技术的代表产品主要有上海盛大网络发展有限公司开发的GPK(Game Protect Kit)、深圳市腾讯计算机系统有限公司开发的TenSafe及韩国neople棒子公司开发的nProtect等。显然,进入到Ring0级进行某些操作是应对这些驱动保护技术的较好办法之一,而运行于核心态即Ring0级的Windows设备驱动程序则可以说是进入到Ring0的唯一方法。

       微软在其WDK,即所谓Windows Driver Kit的官方文档《Getting Started with the Windows Driver Development Environment》一文中开篇指出:“Even for experienced developers, getting started with Windows® device drivers can be difficult. You have a new programming model to learn and a new set of tools for building and debugging”。

       正如上文所述,Windows内核编程与Win32编程区别较大,其调试方法也与Win32下的调试方法有极大不同;同时,Ring0级的反汇编与Ring3反汇编环境也有不小的差异;而大量计算机专业从业人员在没有点拨的情况下也难以意识到内核编程化御姐为萝莉、化少年为怪蜀黍的威力(以下省略一万字)。正是出于以上及其他的各种原因,梅哥将在学习Windows内核编程的同时写下本系列的Ring0湿润插入大法,旨在分享Windows内核编程经验、并说明Windows内核编程在绕过/破解商业驱动保护软件中的重要地位和神奇作用!

       好了,下面就抛开用户级的桎梏,跟梅哥一起开始深入Ring0的湿润之旅吧~

============================我是湿润的昏割线=============================

【说明】

       重加载内核最早应该在www.rootkit.com中提出,根据经验应该已经在大量ARK(Anti-RootKit)、HIPS(Host-based Intrusion Protect System)等安全软件中使用,用于实现查找及恢复各层次的内核级钩子、内核对象等多种功能。在国内,网名为长风傲天的网友于2011年9月15日在看雪论坛上首次以“重加载内核”的概念将其引出,目前几乎所有中文搜索引擎中“重加载内核”的关键字均指向此篇文章及使用了重加载内核的两个反游戏保护框架。目前,多数使用了该技术的国人大多将其命名为KernelReload、ReloadKernel或RebuildKernel等,但在外文搜索引擎中上述三个关键字均不能搜到有意义的相关资料。在仔细阅读并学习了目前可以得到的三个重加载内核的资料后,我初步模仿、改进并实现了重加载内核的基本功能,并在本文中总结。在这个过程中,我参考了以下大量资料,特别鸣谢:

       1、看雪论坛文章及评论若干;

       2、向旻同学购买的正版《Windows PE权威指南》及省得自己下的COFF手册;

       2、卡卡西.R的 Home Blog(http://yukei.blog.163.com/blog/static/112587703201022262224461/)

【前戏】

       所谓重加载内核即将内核在Ring0重新加载一份(记为K2),并根据原始内核(记为K1)的基址进行重定位。在重定位结束后,内存中就有了两个内核,即原始内核K1和新加载的内核K2。值得特别注意的是,新加载的内核K2中所有的函数代码都是全新的、干净的、安全的、处女般的、未曾被任何HOOK及其他代码污染过的;此外,由于重定位以原始内核K1为基址进行了重定向,新内核K2中的所有导出函数都可以直接进行调用,相当于我们拥有了一份完全干净的内核函数集,此时由于可以参照/使用完全干净的内核,那么在恢复无论是SSDT Hook还是Inline Hook上都比较容易了。

【Loader的逆袭】

       对几乎所有通用操作系统而言,在应用程上总是有相应的可执行镜像加载器(Image Loader)负责将特定格式的可执行镜像按Section的结构和要求加载到内存中的合适位置并重定位相关数据、函数引用,例如Linux由Shell负责加载ELF格式的可执行镜像,Windows由相当于shell的执行体SuckMyEss.exe负责加载PE格式的可执行镜像。

       在这一点上,此处所谓的Loader与嵌入式系统中常见的BootLoader概念有重大区别,BootLoader所在的层次比Image Loader更低。例如,对嵌入式系统而言,其BootLoader实际主要完成Boot功能和Loader功能,Boot负责初始化MCU等,而Loader主要负责将二进制镜像从ROM中加载到RAM的合适位置;对Windows操作系统而言,ntldr为实际的BootLoader,在BIOS引导后,主引导扇区MBR将控制权交给ntldr,ntldr负责完成各GDT、IDT等关键表的构建、启用页式内存管理并从实模式跳转到保护模式下,以OS Loader的身份加载Windows内核ntoskrnl.exe。

【PE文件结构】

       想将内核加载到内存中,必须理解其所用的PE文件结构。

       众所周知,为方便操作系统管理,任何文件都有其固定格式,例如苍井空.avi、陈冠希.rmvb、东京热.wma等也是由文件头信息及压缩后的视频流、音频流组成。可以在一定程度上认为,在Windows系统下所有可执行镜像均为PE格式,如常见的.exe、.dll、.sys等。 对可执行镜像而言,除二进制机器码外显然还需要其他信息(如大小、加载基址、Section数量、Section大小、重定位信息等)辅助,以便于操作系统将可执行镜像加载到内存中运行,这些辅助信息在程序中即表现为结构体。典型的PE文件结构如下图所示:

而在微软官方文档《Microsoft Portable Executable and Common Object File Format Specification》中,则是简明地以下图表示:

褪去这些浮云的衣衫后具体而褴褛地看,在Windows源码中WDK源码中,可执行镜像格式在ntimage.h中定义。之后具体细节会有另外的说明。

【重加载内核步骤概述】

       1、使用为文档化函数NtQuerySystemInformation获取系统已加载内核信息(内核FullPathName、基址等);

       2、读取新内核;

       3、按PE结构将新内核在非分页内存池中展开;

       4、按重定位表信息将新内核以旧内核为加载基址重定位;

       5、修复SDT等关键结构;

       6、Enjoy a dreaming night with your girl;

【未完待续】

        To be enjoyed...

posted @ 2015-06-04 16:09  大重九  阅读(988)  评论(0编辑  收藏  举报