驱动管家:安全、高效、精准的专业驱动下载站!

如何实现内核钩子?内核函数系列简单介绍

2018-02-11 22:14:54责编:llp   来源:驱动管家     人气:

我们知道,应用程序总是离不开系统内核所提供的服务,比如它要使用内存的时候,只要跟操作系统申请就行了,而不用自己操心哪里有空闲的内存空间等问题,实际上,这些问题是由操作系统的内核来代劳的。站在黑客的角度讲,如果能够控制内核,实际上就是控制了内核之上的各种应用程序。本文将向您介绍如何建立内核级钩子来控制操作系统向上提供的各种低级功能。有了内核级钩子,我们不但能够控制、监视其他程序并过滤有关数据,还能用其实现Rootkit本身及其它程序的隐形。

本文首先回顾系统调用表和内存保护方面的知识,然后讲解如何实现内核钩子,最后对一些重要的内核函数进行了简要的说明。

一、系统调用表

系统调用表又称系统服务表或者服务描述符表,是Windows 内核在进行各种系统操作时所需的一个函数指针表。也就是说,这个表中存放的是提供系统服务的各种函数的地址。当然,该表所指向的都是系统自身的一些函数,但是,如果我们对它做了手脚后,就可以让它指向我们自己的函数。这正是本文要讲解的重点。

读者一定要注意,修改系统调用表及替换内核函数时,会对系统全局产生影响,稍有不慎就会导致系统崩溃。所以,下手之前,最好对表中的各个函数要有足够的认识,然后才好用我们自己的函数替换这些内核函数的方法。你对它们了解得越多越深,在实现内核钩子的时候就越顺手。但话又说回来,这个系统调用表中的表项实在是太多了,有的指向字符串操作,有的指向客户机/服务器操作,等等。所以要在短时间内了解所有表项是不可能的,所以下文中对它们只做有选择的、概括的介绍。

二、内存保护

现代的Windows操作系统通常将系统调用表所在内存页设为只读来提供保护。如果不能克服这个问题,实施内核钩子技术就是痴人说梦。因为试图向只读内存写入数据也即修改只读内存区时,立刻就会蓝屏。为此,先让我们来了解一下内存保护方面的有关知识。

内存描述符表是内存保护的一大关键,具体定义详见微软DDK中的ntddk.h头文件,我们这里仅做简要介绍:

typedef struct _MDL {

struct _MDL *Next;

CSHORT Size;

CSHORT MdlFlags;

struct _EPROCESS *Process;

PVOID MappedSystemVa;

PVOID StartVa;

ULONG ByteCount;

ULONG ByteOffset;

} MDL, *PMDL;

#define MDL_MAPPED_TO_SYSTEM_VA 0x0001

#define MDL_PAGES_LOCKED 0x0002

#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004

#define MDL_ALLOCATED_FIXED_SIZE 0x0008

#define MDL_PARTIAL 0x0010

#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020

#define MDL_IO_PAGE_READ 0x0040

#define MDL_WRITE_OPERATION 0x0080

#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100

#define MDL_FREE_EXTRA_PTES 0x0200

#define MDL_IO_SPACE 0x0800

#define MDL_NETWORK_HEADER 0x1000

#define MDL_MAPPING_CAN_FAIL 0x2000

#define MDL_ALLOCATED_MUST_SUCCEED 0x4000

#define MDL_MAPPING_FLAGS (MDL_MAPPED_TO_SYSTEM_VA | \

MDL_PAGES_LOCKED | \

MDL_SOURCE_IS_NONPAGED_POOL | \

MDL_PARTIAL_HAS_BEEN_MAPPED | \

MDL_PARENT_MAPPED_SYSTEM_VA | \

MDL_SYSTEM_VA | \

MDL_IO_SPACE )

内存描述符表(MDL)的作用是将虚拟内存映射成物理页。如果将系统调用表所在内存页的MDL的MDLFlags成员设为MDL_MAPPED_TO_SYSTEM_VA 并且该页面被锁定的话,那么就可以使用内核钩子技术了。以下代码将可以达此目的:

#pragma pack(1)

typedef struct ServiceDescriptorEntry

{

unsigned int *ServiceTableBase;

unsigned int *ServiceCounterTableBase;

unsigned int NumberOfServices;

unsigned char *ParamTableBase;

} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;

#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

PVOID* NewSystemCallTable;

PMDL pMyMDL = MmCreateMdl( NULL,

KeServiceDescriptorTable.ServiceTableBase,

KeServiceDescriptorTable.NumberOfServices * 4 );

MmBuildMdlForNonPagedPool( pMyMDL );

pMyMDL->MdlFlags = pMyMDL->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

NewSystemCallTable = MmMapLockedPages( pMyMDL, KernelMode );

好了,我们现在可以通过NewSystemCallTable来新建系统调用表了。系统调用表如下图所示。

图1系统调用表示意图

进行挂钩时,可以使用以下宏:

#define HOOK_INDEX(function2hook) *(PULONG)((PUCHAR)function2hook 1)

#define HOOK(functionName, newPointer2Function, oldPointer2Function )\

oldPointer2Function = (PVOID) InterlockedExchange( (PLONG)

&NewSystemCallTable[HOOK_INDEX(functionName)], (LONG) newPointer2Function)

#define UNHOOK(functionName, oldPointer2Function)\

InterlockedExchange( (PLONG) &NewSystemCallTable[HOOK_INDEX(functionName)]

, (LONG)

oldPointer2Function)

使这些宏后,钩子技术会变得更简单,也更安全。因为InterlockedExchange 是原子函数,不会要求中止中断,所以交换指针的方式是安全的;另外,它也不需要用一个宏挂钩之后用另一个宏卸载钩子,所以也更方便。下图向我们展示了拦截系统调用表的过程。

如何实现内核钩子?内核函数系列简单介绍

图2系统调用表拦截技术示意图

系统调用表数据结构KeServiceDescriptorTable不仅含有ntdll.dll 的全部函数指针,还存有系统调用表的基地址和表的大小,当建立我们自己的内存描述符表的时候,这些信息是不可或缺的。利用MDL_MAPPED_TO_SYSTEM_VA 标志,我们可以建立一个不可页出(即不会被换到内存之外)的MDL ,这样我们就可以将其锁定,并把返回的地址用于我们自己的系统调用表,重要的是,这个系统调用表是可写的。

三、定义钩子函数

内核钩子主要有三部分组成:要钩取的函数(在下文中称为目标函数)、替代要钩取的函数的函数(在下文中成为钩子函数)和系统调用表。前面部分介绍了系统调用表的问题,下面开始介绍钩子函数。一般说来,当定义自己的钩子函数时,可以先到DDK 的头文件中找到所想要的函数的原型,然后,稍加修改就能把目标函数变成钩子函数了。

例如,ZwMapViewOfSection 是一个内核函数,允许应用程序把从动态链接库导出的函数映射至内存。如果我们想要钩住这个内核函数,那么可以到ntddk.h头文件中查看其函数原型,如下所示:

NTSYSAPI

NTSTATUS

NTAPI

ZwMapViewOfSection(

IN HANDLE SectionHandle,

IN HANDLE ProcessHandle,

IN OUT PVOID *BaseAddress,

IN ULONG ZeroBits,

IN ULONG CommitSize,

IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,

IN OUT PSIZE_T ViewSize,

IN SECTION_INHERIT InheritDisposition,

IN ULONG AllocationType,

IN ULONG Protect );

有了函数原型,我们就可以确定指向目标函数的指针了,如下所示:

typedef NTSTATUS (*ZWMAPVIEWOFSECTION)(

IN HANDLE SectionHandle,

IN HANDLE ProcessHandle,

IN OUT PVOID *BaseAddress,

IN ULONG ZeroBits,

IN ULONG CommitSize,

IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,

IN OUT PSIZE_T ViewSize,

IN SECTION_INHERIT InheritDisposition,

IN ULONG AllocationType,

IN ULONG Protect );

ZWMAPVIEWOFSECTION OldZwMapViewOfSection;

钩子函数如下所示:

NTSTATUS NewZwMapViewOfSection(

IN HANDLE SectionHandle,

IN HANDLE ProcessHandle,

IN OUT PVOID *BaseAddress,

IN ULONG ZeroBits,

IN ULONG CommitSize,

IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,

IN OUT PSIZE_T ViewSize,

IN SECTION_INHERIT InheritDisposition,

IN ULONG AllocationType,

IN ULONG Protect )

{

NTSTATUS status;

DbgPrint("comint32: NewZwMapViewOfSection called.");

//我们可以对输入为所欲为,既可以马上返回,也可以继续执行原函数

status = OldZwMapViewOfSection(SectionHandle,

ProcessHandle,

BaseAddress,

ZeroBits,

CommitSize,

SectionOffset OPTIONAL,

ViewSize,

InheritDisposition,

AllocationType,

Protect );

// 我们可以在此对输出为所欲为,想返回什么,就返回什么

return status;

}

好了,钩子技术的三大件已经准备好了。现在,我们就可以像下面这样使用它们:

HOOK( ZwMapViewOfSection, NewZwMapViewOfSection, OldZwMapViewOfSection );

如果你打算使用DriverUnload ()的话,可千万不要忘了卸载钩子。

四、内核函数系列

经过上面的介绍,我们已经了解了系统调用表有关知识,也已知道如何拦截系统调用表中的函数,下面,我们再来了解一下我们要钩取的函数:目标函数。这方面,如果我们不仅了解系统调用表中有哪些函数,还知道这些函数的工作机制就最好了。但实际上,ntdll.dll 中的导出函数有好几百个,别说一个一个的探究,就是把它们都列出来,看着看着头都大了。幸运的是,我们不必了解每个函数,只要了解其所在的系列就行了。为什么这么说?因为微软已经按照函数的功能对Ntdll.dll的导出函数进行了分组,并冠以意义明确的前缀,所以根据函数系列的前缀就能明白它们的大体功能了。下面对这些函数系列进行简单的介绍:

1.KiEtw系列:本系列内核函数用于系统内核,这些函数只能从内核的内部进行调用,常用的有:KiUserCallbackDispatcher、KiRaiseUserExceptionDispatcher、KiUserApcDispatcher、KiUserExceptionDispatcher等。

2.Csr系列:此系列函数用于客户机和服务器运行时,如果您想拦截客户机/服务器方面的操作,那么就需要对Csr系列内核函数做进一步的了解。常见的有:CsrClientCallServer、CsrCaptureMessageBuffer、CsrConnectClientToServer和CrsNewThread等。

3.Ldr系列:本系列内核函数用于加载程序管理器,如果你打算拦截加载程序的话,那么请进一步考察这组以Ldr为前缀的函数,常用的有:LdrInitializeThunk、LdrLockLoaderLock、LdrUnlockLoaderLock、LdrGetDllHandle、LdrGetProcedureAddress等。

4.Dbg系列:本系列内核函数用于调试管理,如果打算拦截调试操作的话,那么请进一步考察这组以Dbg为前缀的函数,常用的函数包括:、DbgBreakPoint、DbgUserBreakPoint、DbgPrint和DbgUiConnectToDbg等。

5.Etw系列:本系列内核函数用于追踪窗口事件,如果你打算拦截追踪之类的操作的话,那么请进一步考察这组以Etw为前缀的函数。常用的函数包括:EtwTraceEvent、EtwEnableTrace、EtwGetTraceEnableLevel和EtwGetTraceEnableFlags等。

6.Rtl系列:本系列内核函数用于运行时库,以Rtl为前缀的函数可以完成多种操作,例如字符串、线程、资源、临界区、安全对象的初始化和使用,内存、进程异常和数据类型的处理,还用于完成定时器、堆、IPv4和IPv6方面的操作,以及压缩和解压缩等。

7.Pfx系列:本系列内核函数用于ANSI字符串操作,如果你打算拦截ASNI串表方面的操作的话,就需要进一步了解这些函数。常用的包括:PfxInitialize、PfxRemovePrefix、PfxInsertPrefix、PfxFindPrefix等。

8.Zw系列:本系列内核函数用于文件和注册表方面的操作,比如文件操作、注册表操作、访问进程、事件操作、令牌操作、进程操作和端口操作等。

这里介绍的只是内核函数中的一部分,限于篇幅其他部分在此不作介绍。

六、结束语

本文深入介绍了系统调用表和内存保护方面的知识,并介绍了实现钩子函数的方法,最后对一些重要的内核函数进行了简要的说明。有了内核级钩子,我们不但能够控制、监视其他程序并过滤有关数据,还能达到隐藏Rootkit本身及其它程序的目的。需要说明的是,尽管可以通过内核钩子技术来实现rootkit所需的一些功能,但是,现实中的rootkit通常组合使用多种其它技术,如进程注射、分层驱动过滤等。更多的技术,将在后文中分别加以介绍。

  • 路由器怎么设置才可以防止arp攻击?这里有防止arp攻击教程

    路由器怎么设置才可以防止arp攻击?这里有防止arp攻击教程

    第一步:打开网吧路由器的管理界面,在左侧的菜单中可以看到:“IP与MAC绑定”,在该项来设置IP和MAC绑定。第二步:打开“静态ARP绑定设置”窗口如下:注意:默认情况下ARP绑定功能是关闭,请选中启用后,点击保

    详情2018-01-23 14:45:41责编:llp   来源:驱动管家     
  • 公共wifi密码共享不要随便连接 教你安全使用公共wifi网络

    公共wifi密码共享不要随便连接 教你安全使用公共wifi网络

    虽然用户使用公共Wi-Fi存在不少风险,但用户还是可以养成一些习惯来更安全地使用公共Wi-Fi网络。1、关掉共享。用户在工作场所或自己家里使用笔记本电脑时可能会与其他电脑共享文件及文件夹,但在使用公共Wi-Fi时

    详情2018-01-17 16:25:05责编:llp   来源:驱动管家     
  • 人们需要知道有关后门程序的三大技术知识

    人们需要知道有关后门程序的三大技术知识

    曾经饱受木马、后门(以下统称后门)侵害的人们都不会忘记机器被破坏后的惨象,于是人们展开了积极的防御工作,从补丁到防火墙,恨不得连网线都加个验证器,在多种多样的防御手法夹攻下,一大批后门倒下了,菜鸟们

    详情2018-01-06 18:19:03责编:llp   来源:驱动管家     
  • 密钥管理 怎么管理加密密钥?

    密钥管理 怎么管理加密密钥?

    “传输中的数据”密钥管理系统在加密数据“休息”的时候不起作用有两个原因。第一个原因是传输中的数据加密没有密钥存储的概念。一旦你从一个密钥转移到另一个密钥,旧的密钥就不再需要了。然而,在加密存储的数据时,密钥是正常变化的。旧的密钥必须要保留,否则使

    详情2018-01-17 14:09:50责编:llp   来源:驱动管家     
  • 路由器设置 路由器连接路由器的设置方法

    路由器设置 路由器连接路由器的设置方法

    本文将为大家详细讲述路由接路由的设置方法,下面以图示先标明局域网各路由间的接法:(上联路由LAN口接下联路由LAN口不在讨论范围)上联路由设置:跟平时设置时一样,无任何难度,不过要记好上联路由网关(此例为192

    详情2018-02-02 20:08:17责编:llp   来源:驱动管家     
  • 卡巴斯基2010防止程序被误杀或阻止的方法

    卡巴斯基2010防止程序被误杀或阻止的方法

    有的时候为了测试某个黑客软件或者有些正常的游戏被卡巴误杀,我们可以使用以下方法来防止我们的程序被误杀或阻止。1 请您点击桌面右下角卡巴斯基的图标打开主界面,点击右上角的“设置”,如下图:2 在设置界

    详情2018-01-28 17:18:07责编:llp   来源:驱动管家     
  • 什么是黑客社会工程学?黑客社会工程学的网站入侵手法

    什么是黑客社会工程学?黑客社会工程学的网站入侵手法

    大家一定知道超级黑客凯文·米特尼克吧,深为他的社会工程学所折服,美国国防部、五角大楼、中央情报局、北美防空系统……都是他闲庭信步的地方,没有人怀疑他的真实身份,对于他所想获得的信息如鱼得水,这便是

    详情2018-02-03 11:56:31责编:llp   来源:驱动管家     
  • 不让外来人员共享文件要怎么做?禁止外人共享文件的方法

    不让外来人员共享文件要怎么做?禁止外人共享文件的方法

    为了日常工作方便,设置共享文件服务器通常是大多数企业的管理方式,共享文件服务器上的共享文件仅用于局域网内的用户使用。但工作中免不了有客户来访,也需要连接网络,这样公司内部共享的文件也会向这些外来人

    详情2018-01-06 18:07:13责编:llp   来源:驱动管家     
  • mac系统的密码怎么破解重置?破解mac系统密码的方法有哪些?

    mac系统的密码怎么破解重置?破解mac系统密码的方法有哪些?

    不开源就意味着更干净更安全,现在连苹果都要准备部分开源给第三方软件了,是不是意味着苹果的安全也不如想象中的那么强大了?这个猜测并没有证据,有证据的是,iMac和MacBook的固件密码已经可以破解重置了。安全

    详情2018-01-16 10:29:42责编:llp   来源:驱动管家     
  • 密码忘了不用怕 按照下面的步骤可以轻松破解win2000的密码

    密码忘了不用怕 按照下面的步骤可以轻松破解win2000的密码

    第一步,网站下载NTFSDOS Professional软件,下载后进行安装,安装后执行NTFSDOS Professional Boot Disk Wizard程序,根据向导,会提示依次插入两张软盘,其实能用到的就是第一张。第二步,用Win98软盘或光

    详情2018-01-30 11:05:05责编:llp   来源:驱动管家