【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析…

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

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

第一课Windows内核/驱动编程概述及应用、 商业驱动保护软件原理简单分析

【湿润前言】

       随着驱动保护技术的逐步成熟,诸如网络游戏公司等越来越多的商业软件公司开始使用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 Windowsdevice 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的湿润之旅吧~

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

【商业驱动保护软件的原理简述】

       盛大公司的GPK驱动保护产品目前在其内部及外部的多家公司游戏产品中使用,例如由网易运营的网络游戏《梦幻西游》、由深圳市迅雷网络技术有限公司运营的网络游戏《仙剑神曲》等众多游戏都采用了GPK驱动保护产品。下面梅哥将以由深圳市迅雷网络技术有限公司运营的网络游戏《仙剑神曲》为例分析商业驱动保护软件的原理。

       盛大公司的GPK将驱动伪装成1394总线集线器设备驱动在内核中注册,利用相关工具可在内核驱动模块中找到1394hub.sys,如下图所示:

【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析...

      Hook该函数即在某种程度上阻止几种常见三方非法软件,例如:

      1)需要使用ExAllocateVirtualMemory在目标进程内部开辟空间的远程线程注入方法等;

      2)Cheat Engineer等通过向目标进程空间读取/写入数据的软件;

再如Shadow SSDT中的NtUserPrintWindow函数被Hook,可以实现阻止应用层进程在游戏窗体内进行绘图操作等;除此以外还有防止输入法注入的NtUserSetAppImeLevel等:

【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析...

       用户空间不能访问高端2G的内核空间,同时,当涉及进程调度等时,内核只切换低端2G的虚拟内存,正因为如此才有了网络协议栈中所谓的零拷贝技术。例如,以UDP常用API函数SendTo为例,其发送缓冲区往往使用malloc等运行时函数在用户层2G内的堆空间分配(运行时函数、堆栈区别不知道的请百度),当SendTo最终陷入系统内核时,由于用户态2G空间与内核态2G空间相互独立,所以就需要将用户层的发送缓冲区拷贝至内核空间,这种拷贝在一定程度上导致了性能的降低,因而有人也就提出了所谓的零拷贝技术。

【Win32子系统与内核】

       前戏:在深入内核之前,我们首先需要了解NT内核的基本结构。

       首先纠正Linux环境、实时操作系统或Anti-Windows背景同学的常见误区(作为一名曾经坚定的Anti-Windows者,梅哥真心只能表示谁人年少不2B啊,哎),即可以在相当程度上认为Ntoskrnl.exe为Windows NT架构操作系统的内核。当然,由于Windows为非典型的微内核结构,故Ntoskrnl.exe实际上包括了操作系统内核及执行体组件两部分组成。在Ntoskrnl.exe以外,用户层功能由诸如Win32、OS/2和POSIX等的子系统DLL的形式提供,这些子系统中的APIs最终通过调用Ntoskrnl.exe提供的系统服务实现。

       目前,可以认为Win32子系统为最主要的子系统,其包含的API即应用开发人员常提到的Win32 API,更加具体地讲Win32 API又分为:

       1)GDI函数,对应GDI32.DLL,在物理设备上执行绘图操作;

       2)USER函数,对应USER32.DLL,管理窗口、菜单、对话框及各类控件等;

       3)KERNEL函数,对应KERNEL32.DLL,管理进程、线程、文件、同步等非GUI资源;

在当前的NT内核架构中,上述三个DLL文件均只包含函数导出定义,其实现全部在内核文件Ntdll.dll中,而Ntdll.dll文件中实现的函数即为所谓Native API。Native API一般以Nt开头,例如Win32 API函数OpenProcess在Ntdll.dll中的实现为NtOpenProcess,如图所示(途中是以WriteFile为例的):

 

【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析...

       我们也可以通过内核函数的反汇编代码看出,如微软为文档化的内核函数ZwQuerySystemInformation函数反汇编如下:

 

【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析...

Ntoskrnl.exe中导出了一个KeServiceDescriptorTable变量,其实际是一个指向结构体struct ServiceDescriptorTable的指针,是访问SSDT的关键。在WinDbg中可以直接使用dd KeServiceDescriptorTable命令查看:

kd> dd KeServiceDescriptorTable

8055b220  804e36b8 00000000 0000011c 805110c8

8055b230  00000000 00000000 00000000 00000000

8055b240  00000000 00000000 00000000 00000000

8055b250  00000000 00000000 00000000 00000000

8055b260  00002710 bf80c361 00000000 00000000

8055b270  f8a49a80 82378cc0 822090f0 80700f40

8055b280  00000000 00000000 32d80ecc 0005f5b0

8055b290  587f2d8c 01cca04b 00000000 00000000

而KeServiceDescriptorTable定义为(对于该结构网上有大量错误代码):

typedef struct ServiceDescriptorTable_s

{

       PULONG ServiceTableBase;                   // System Service Dispatch Table的基地址

       PULONG ServiceCounterTable(0);

       unsigned int NumberOfServices;          //由ServiceTableBase描述的服务的数目

       PULONG ParamTableBase;                    //SSPT

}ServiceDescriptorTable,*pServiceDescriptorTable;

extern pServiceDescriptorTable KeServiceDescriptorTable;

其中,ServiceTableBase指向SSDT(System Service Dispatch Table)系统服务分发表的基址,其中每个地址4字节长;ServiceCounterTable用于checked builds,包含着SSDT中每个服务被调用次数的计数器,这个计数器由INT 0x2E或SYSENTER处理程序KiSystemService更新,一般为零;NumberOfServices描述了SSDT中包换的系统服务的个数;ParamTableBase指向 SSPT(System Service Parameter Table)。

       通过梅哥以上的介绍,我们已经知道SSDT对应Ntoskrnel.exe为Kernel.dll中包含的API服务;除此以外,还有所谓的Shadow SSDT,对应KeServiceDescriptorTableShadow指针,它与GDI相关API有关,具体对应Win32k.sys。本系列教程以后会对Shadow SSDT做详细说明。

       我们可以直接在WinDbg中查看KeServiceDescriptorTable(符号表中已包含):

kd> dd KeServiceDescriptorTable

8055b220  804e36b8 00000000 0000011c 805110c8

8055b230  00000000 00000000 00000000 00000000

8055b240  00000000 00000000 00000000 00000000

8055b250  00000000 00000000 00000000 00000000

8055b260  00002710 bf80c361 00000000 00000000

8055b270  f8a49a80 823e42f8 8219b0f0 80700f40

8055b280  00000000 00000000 314d818d 00000000

8055b290  3d76644d 01cca1f4 00000000 00000000

显然,第一个0x804e36b8即为SSDT的基址。在老版本的WinDbg中,可以利用poi执行显示某一地址处的内容,例如显示地址0x804e36b8处的内容可使用dd poi[0x804e36b8],而新版的WinDbg已经可以直接支持dd [0x804e36b8]:

kd> dd [804e36b8]

804e36b8  8058a1f1 8057a2d1 8058d5e8 8058b52c

804e36c8  80591aa6 806393f2 8063b583 8063b5cc

804e36d8  8057b8c4 8064a391 80638bad 805910c4

804e36e8  80630cf4 8057bdad 80592876 80627c4d

804e36f8  805de479 80569fca 805da817 805a353d

804e3708  804e3cc4 8062d4ae 805cabb6 804edfbc

804e3718  8056a676 805688cd 80591532 8064fc88

804e3728  8058ca4e 8058af39 8064fef5 8058d63a

上述的内容依次就是用工具观察SSDT时得到的当前地址,也就是说SSDT中存放是相应索引对应函数的所在地址,例如第一个0x8058a1f1中存放的就是索引0对应函数NtAcceptConnectPort的地址,如图所示:

【梅哥的Ring0湿润插入教程】第一课Windows内核/驱动编程概述及应用、商业驱动保护软件原理分析...

另外,由于每个函数地址为4字节,故索引为Index的函数对应的地址为[[KeServiceDescriptorTable]+Index*4]。

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

 在下节课中,将深入讲解SSDT的相关知识,具体涉及SSDT的读取、写不可写页面(SSDT的写入)等。请大家继续期待梅哥的Ring0湿润插入教程吧~

转载于:https://www.cnblogs.com/daiguowen/articles/4552111.html

相关资源:PPT中FLASH插入软件.rar-Flash文档类资源-CSDN文库

来源:aejtu5698

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2015年5月2日
下一篇 2015年5月2日

相关推荐