
发表日期: 2021-04-28 09:57:57 浏览次数:154
汝州400电话办理【汝州网站公司】汝州百度优化、汝州域名注册、汝州网店美工、汝州微信公众号托管
汝州市位于河南省中西部,因北汝河贯穿全境而得名,总面积1573平方公里,总人口120万,辖21个乡镇街道,459个行政村,是平顶山市下辖的县级市,也是河南省十个省直管县试点之一。
汝州是历代郡州治所。从公元606年的隋朝设立汝州以来,距今已有1400多年的历史。
汝州距离省会郑州90公里、洛阳70公里、平顶山60公里,焦枝(柳)铁路、宁洛高速、二广高速、林桐高速穿境而过,在1小时交通圈内通达郑州国际机场、洛阳机场,已建成和规划建设的郑万高铁、郑洛城际铁路、洛平漯周高铁、三洋铁路紧临汝州或在汝州设站。
汝州境内旅游景点达到852个,省级以上重点文物保护单位20个,其中国家重点文物保护单位10处,拥有风穴寺、九峰山等2个4A级景区,怪坡、中国汝瓷小镇、丹阳湖景区、汝水湾景区、汝河沙滩公园等5个3A级景区。共有37个具有开发价值的古寨古堡,夏店镇山顶村、蟒川镇半扎村、大峪镇青山后村、焦村镇张村等4个是国家级传统村落。九峰山、紫云山、蒋姑山、大红寨等风景名胜,罗圈地质公园冰川遗址是世界四大冰川地质遗址之一。
汝州市为国家园林城市、国家卫生城市、全国绿化模范市、全国文明城市城市,被评为全国第二批节水型社会建设达标市、全省水生态文明城市、全省首批全域旅游示范市、首批省级森林城市,荣获中国十佳绿色城市、全国文旅融合特色创新示范市、中国汝瓷之都等称号,海绵城市项目荣获中国人居环境范例奖,PPP项目实施和土地节约集约利用两项工作受到国务院通报表彰。 [1]
Hook 是一种可以改变程序执行流程的技术,巧妙利用 Hook 技术可以实现很多实用的操作,如:监控、过滤、拦截、修改等。但在现代操作系统中,出现了诸多限制,导致无法轻松的进行底层Hook。其中典型例子就是 Win10 的 PatchGuard。现在,我们将深度剖析一个神奇的技术:InfinityHook。
InfinityHook 是一个可以Hook各种系统调用、上下文切换、页面错误、DPC 等内核事件的技术。它目前可以与 PatchGuard 同时运行,且比常规 Hook 技术具有更好隐蔽性。InfinityHook 并不是其名意所谓的“无限 Hook”,实际意义是可以安全的对内核底层进行 Hook。因为安全界中攻与防的对抗,产生了一种,谁先 Hook,谁 Hook 的最底层,谁最有优势的概念。而攻与防之间互相抢夺 Hook 优势的现象,像极了一个无尽深渊,没有终点。微软为了保护底层系统的安全,防止被第三方程序滥用,在一系列新版本操作系统中推出和升级了 PatchGuard。而 InfinityHook 的出现打破了微软的这一保护,拥有更安全更底层的 Hook 优势。随着时间的推移这项技术会广为人知,这意味着一场更激烈的攻防无限 Hook 战争即将开战。故名“InfinityHook”。想要更深入剖析 InfinityHook 的原理,就得先了解 Windows 的 Event Tracing 机制。
Windows事件跟踪(ETW)是一种高效的内核级跟踪工具,可让您将内核或应用程序定义的事件记录到日志文件中。您可以实时或从日志文件中使用事件,并使用它们来调试应用程序或确定应用程序中发生性能问题的位置。ETW 允许您动态启用或禁用事件跟踪,允许您在生产环境中执行详细跟踪,而无需重新启动计算机或应用程序。事件跟踪 API 分为三个不同的组件:
控制器(Controllers): 用于启动和停止事件跟踪会话并启用提供程序。
提供者(Providers):用于提供事件。
消费者(Consumers):用于消费事件。
0x02.1 控制器(Controllers)
控制器是定义日志文件的大小和位置、启动和停止事件跟踪会话、启用提供程序以便将事件记录到会话、管理缓冲池的大小以及获取会话的执行统计信息的应用程序。0x02.2 提供者(Providers)
提供程序是包含事件跟踪工具的应用程序。提供程序注册后,控制器可以在提供程序中启用或禁用事件跟踪。提供者定义其启用或禁用的实现。通常,启用的提供程序会生成事件,而禁用的提供程序则不会。这使您可以向应用程序添加事件跟踪,而无需始终生成事件。虽然 ETW 模型将控制器和提供程序分离为单独的应用程序,但应用程序可以包含这两个组件。0x02.3 消费者(Consumers)
消费者是选择一个或多个事件跟踪会话作为事件源的应用程序。消费者可以同时从多个事件跟踪会话中请求事件;系统按时间顺序提供事件。消费者可以接收存储在日志文件中的事件,也可以接收实时传递事件的会话。处理事件时,消费者可以指定开始和结束时间,并且仅传递在指定时间范围内发生的事件。
(Event Tracing 事件跟踪模型图)
我们可以在 “此电脑->管理->性能->数据收集器集->事件跟踪会话” 中找到系统中所有正在运行的事件跟踪会话。
(系统中所有正在运行的事件跟踪会话)
即将讲解的 InfinityHook 就将使用第一个事件跟踪会话“Circular Kernel Context Logger”(之后简称 CKCL)进行操作。
首先我们要知道一点,InfinityHook 因为一些特殊的操作必须要在 Ring0 层才能实现。而 ETW 模型的3个组件是可以在 Ring3 完成。所以我们可以参考微软开放的文档例子帮助分析。找到微软开放的“配置和启动 NT 内核记录器会话”的代码:https://docs.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-the-nt-kernel-logger-session我从网页截取了关键代码贴了上来:
可以不难发现,配置会话的关键结构体是 EVENT_TRACE_PROPERTIES,启动会话的关键 API 是 StartTrace。
EVENT_TRACE_PROPERTIES 结构体的定义:
StartTrace 函数的声明:
在这段代码中有一个需要关注的点:
分配的内存长度不仅仅只是结构体的大小,还包含了两段其他的长度。看一下 msdn 对这个 API 的描述:https://docs.microsoft.com/en-us/windows/win32/etw/starttrace其中同样有一点值得关注:This function copies the session name that you provide to the offset that the LoggerNameOffset member of Properties points to.
此函数将您提供的会话名称复制到属性的LoggerNameOffset成员指向的偏移量。
这段话说明我们拷贝到结构体之后的字符串还会在 StartTrace 内部被处理。对在 Ring3 启动跟踪会话的信息了解的差不多了。但是问题来了,如何在 Ring0 层实现这些东西呢?所以我们得上 IDA 分析一下这个函数的内部实现。
从 msdn 的描述里我们可以看到:DLL
Sechost.dll on Windows 8.1 and Windows Server 2012 R2;
Advapi32.dll on Windows 8, Windows Server 2012, Windows 7, Windows Server 2008 R2, Windows Server 2008, Windows Vista and Windows XP
所以我们将 Advapi32.dll 文件用IDA打开,下载 dll 的符号文件让 IDA 自动分析。分析完成后,转到 StartTraceA 函数,从函数头部开始看。首先是对参数的合法性检查。接着是对参数2的 InstanceName 字符串内容进行比较。如果为“NT Kernel Logger”,则将 SystemTraceControlGuid 的 Guid 赋值给 Properties->Wnode.Guid。如果为“Circular Kernel Context Logger”, 则将 CKCLGuid 的 Guid 赋值给 Properties->Wnode.Guid。我们看下这个 CKCLGuid 的内容,之后会用到。首先判断“Properties->LogFileNameOffset”如果小于等于0,则跳到 LABEL_67 标签。在图片底部可以看到 LABEL_67 标签置零了2个变量,但并没有返回退出。说明这个函数允许 LogFileNameOffset 的值为0。同样,我们在 msdn 查阅一下这个结构体:https://docs.microsoft.com/en-us/windows/win32/etw/event-trace-properties找到对这个成员的描述,截取关键内容下来:LogFileNameOffset
Offset from the start of the structure's allocated memory to beginning of the null-terminated string that contains the log file name.
从结构的已分配内存开始到包含日志文件名的以空值终止的字符串的开头的偏移量。
If you do not want to log events to a log file (for example, you specify EVENT_TRACE_REAL_TIME_MODE only), set LogFileNameOffset to 0. If you specify only real-time logging and also provide an offset with a valid log file name, ETW will use the log file name to create a sequential log file and log events to the log file. ETW also creates the sequential log file if LogFileMode is 0 and you provide an offset with a valid log file name.
如果您不想将事件记录到日志文件中(例如,仅指定EVENT_TRACE_REAL_TIME_MODE),请将LogFileNameOffset设置为0.如果仅指定实时日志记录并提供具有有效日志文件名的偏移量,则ETW将使用日志文件名,用于创建顺序日志文件并将事件记录到日志文件中。如果LogFileMode为0,ETW还会创建顺序日志文件,并提供带有效日志文件名的偏移量。
文章头部对 ETW 的介绍中写到:您可以实时或从日志文件中使用事件,并使用它们来调试应用程序或确定应用程序中发生性能问题的位置。
我们可以得知, 日志文件是用于调试应用程序或定位性能问题位置的。而 InfinityHook 并不需要这些东西。所以 LogFileNameOffset 成员可以直接置0,跳过这段继续往下分析。接着是一些参数标志合法性检查,这些合法性检查由 Etwp 开头的 API 完成。假定我们传递的所有参数都是正确的,所以无需跟进这些 API 进行分析。从堆中分配一块内存空间,后面要用到。将我们传递进来的 Properties 参数填进v27变量内。接着我们可以看到几个字符串操作 API 。还记得刚刚在 msdn 提到的关注点吗?应该就是这里了。第一个字符串的处理是将我们传递进来的 InstanceName 参数初始化为一个 ANSI_STRING 字符串。再将其转换为一个 UNICODE_STRING 字符串。转换完的 UNICODE_STRING 字符串存放在 (PUNICODE_STRING)v27 + 9 的位置。UNICODE_STRING 结构体的大小为16,故步长为16。实际存放地址是在 v27 + 144 。再看下 EVENT_TRACE_PROPERTIES 结构体的大小为120。说明这个 UNICODE_STRING 字符串存放在 v27 + sizeof(EVENT_TRACE_PROPERTIES) + 24 的位置。处理完第一个字符串后有一个判断,如果 v46 等于0,则跳到 LABEL_69 标签。而这个 v46 就是刚刚判断 LogFileNameOffset 如果等于0所置零的变量。所以这里可以跳过第二个字符串的处理,直接往下看。看到了两个 Etwp 开头的API,我们先跟进第一个 API 看看。不难看出,这个 API 对 Property 的内容影响并不大,只有两处,74和72偏移。对比结构体定义发现,是在对 EnableFlags 成员填值。这个成员放到后面再讲,所以这里先暂时跳过此 API。接着来看 EtwpStartLogger 这个API。可以很直观的看到,检查了一些成员后调用了 NtTraceControl 这个 API。这个就是我们在 Ring0 层启动事件跟踪会话的API了。在这 API 之下是一些与结构体内容无关的操作。所以直接跳过,返回上层继续看。将堆内存的 Property 内容,置回到参数 Property 中。然后跳到 LABEL_58 标签。释放堆内存,返回成功与否。至此,StartTraceA 这个 API 逆向完成。我们知道了部分参数的填写规则和关键 API。下一步我们开始写 InfinityHook 的实现代码。0x03.2 InfinityHook 的实现
首先,从刚刚分析出来的信息:UNICODE_STRING 类型的 InstanceName 存放在 Property + sizeof(EVENT_TRACE_PROPERTIES) + 24 的位置。所以我们定义一个名为 CKCL_TRACE_PROPERTIES 的结构体,这个结构体继承于 EVENT_TRACE_PROPERTIES。
然后定义一个变量为其申请一块内存空间,并对其置零。为了保险起见,以防底层 API 还会对结构体更后面的内存进行操作,所以申请的大小填 PAGE_SIZE。
然后初始化一个变量名为 InstanceName 的 UNICODE_STRING 字符串。
接着我们开始填写 pProperty 内容。pProperty->Wnode.BufferSize:填写我们为其申请内存的大小 PAGE_SIZE。pProperty->Wnode.ClientContext:
根据 msdn 的描述,此成员为时间戳的分辨率。可以为3个值:
1:Query performance counter (QPC). QPC 计数器提供高分辨率时间戳,不受系统时钟调整的影响。存储在事件中的时间戳等同于QueryPerformanceCounter API 返回的值。
2:System time(系统时间).
3:CPU cycle counter(CPU 循环计数器). CPU 计数器提供最高分辨率的时间戳,并且是检索资源最少的。但是,CPU 计数器不可靠,不应在生产中使用。例如,在某些计算机上,除了在某些状态下停止之外,定时器还会因热量和功率变化而改变频率。
我们这里填写为3值(CPU 循环计数器),因为它的实现很简单,仅使用了一条汇编指令,后面会讲。
pProperty->Wnode.Flags:根据 msdn 的描述,必须包含 WNODE_FLAG_TRACED_GUID 以指示该结构包含事件跟踪信息。
pProperty->Wnode.Guid:
从上面的 IDA 中取出来改为代码则是:
pProperty->BufferSize:每个事件的缓冲区,直接填4字节即可,因为我们不需要实际接收事件内容。pProperty->LogFileMode:上面说过,我们不需要 ETW 写入日志文件,所以设置为 EVENT_TRACE_BUFFERING_MODE。pProperty->MinimumBuffers:为事件跟踪会话的缓冲池分配的最小缓冲区数,最小为2,直接填2,。pProperty->MaximumBuffers:
这个成员 msdn 描述的有点矛盾。既说必须大于等于 MinimumBuffers,又说 LogFileMode 设置了 EVENT_TRACE_BUFFERING_MODE 可以不用设置此值。虽然应该可以忽略这个成员,但这里为了保险起见,我们设置和 MinimumBuffers 一样的值。
pProperty->InstanceName:这个为我们刚刚扩充的成员,填写初始化的 UNICODE_STRING 字符串 InstanceName 即可。所以Property的成员填写代码是这样的。
然后就是控制 CKCL 事件跟踪会话。NtTraceControl,msdn 并没有给出他的声明。结合谷歌搜索、GitHub 项目和 IDA 分析,可以得到的声明为:
其中参数一可以是5个常量中的任意一个:
这5个常量在此 API 内部对应5个 Etwp 开头的 API,分别代表:启动跟踪、停止跟踪、查询跟踪、更新跟踪、刷新跟踪。
0x03.2 InfinityHook 的执行流程图InfinityHook 只需要:启动、停止和更新。
值得注意的是,我们需要在更新跟踪的时候,设置 pProperty->EnableFlags 标志,以此来过滤我们想要的事件。本文将以 Hook Syscall 中的 NtOpenProcess 作为例子进行讲解。所以这里设置 EVENT_TRACE_FLAG_SYSTEMCALL 标志,以拦截到所有的 Syscall 事件。我们将以上内容封装为一个函数,所以整个函数的代码是这样的:
接着调用这个函数,启动并更新 CKCL 事件跟踪对象:
至此,CKCL 已成功启动和更新。下面,我们需要找到一些内核全局地址,来方便我们进行之后的操作。EtwpDebuggerData,是一张存放所有 ETW 信息的表。通过IDA搜索可以发现有这个变量符号,但是查看交叉引用却发现IDA并没有分析出哪里使用了这个变量。所以只能通过暴搜的方法去找到这个变量的地址。通过多个系统版本的内核文件进行 IDA 分析,可以发现两条信息。
根据相同的数值,得出 EtwpDebuggerData 的特征码是“?? ?? 2c 08 04 38 0c”。
不同系统上的 EtwpDebuggerData 可能存在于不同的区段。
那我们首先取到内核基地址,解析PE头找到“.data”和".rdata"区段的起始地址和区段大小,然后根据特征码进行暴搜。
接着在 EtwpDebuggerData + 0x10 处取到 EtwpDebuggerDataSilo 指针。再从 EtwpDebuggerDataSilo + 0x10 的位置取到 CkclWmiLoggerContext 指针。这两个数据的硬编码偏移在所有系统上都一样,并没有发生改变。(EtwpDebuggerDataSilo 和 CkclWmiLoggerContext,是直接参考的 GitHub 上的项目,因为在IDA中找了很久都没有找到关于 EtwpDebuggerDataSilo 的信息,仅仅找到了一个可能是 CkclWmiLoggerContext 的指针,是动态分配的,鄙人逆向能力有限,实在没能跟到 EtwpDebuggerDataSilo 在哪,如果有大佬研究出来了,欢迎在评论区分享,谢谢!)
接着我们需要取到 SyscallEntry 的页面基址。直接从 msr 中可以取出 SyscallEntry。
但是有一个问题,还记得2018年的内核页表隔离补丁吗。不记得没关系,大表哥之前分析过的帖子:https://bbs.pediy.com/thread-223805.htm简单来说,在打了内核页表隔离补丁的系统上,取到的只是一个影子入口,通过影子入口内的过渡代码,最后走到真正的入口。而 CKCL 事件是在真实入口中触发的,只拿到影子入口并不能完成之后的操作。影子入口和过渡代码都存在于内核模块的 KVASCODE 区段内,该区段是否存在取决于有没有打内核页表隔离补丁。如果区段存在,我们则取到这个区段的入口地址和区段大小。再对比我们从 msr 中得到的 SyscallEntry 是否在此区段内,则可以判定内核页表隔离有没有被开启。
这是没打补丁通过 msr 取到的 SyscallEntry,函数名是 KiSystemCall64。这是打了 KB4056892 补丁后通过 msr 取到的 SyscallEntry,可以看到函数名是 KiSystemCall64Shadow。在函数尾部有一个 jmp,跳到了真正的入口 KiSystemServiceUser,而这个真正的入口一定是在 KVASCODE 区段外。所以我们利用 HDE 反汇编引擎,对影子入口的每条指令进行解析,找到一条跳出 KVASCODE 区段的 jmp 指令。
至此,定位到真实 SyscallEntry 函数地址。再回过头来看看我们刚刚找的 CkclWmiLoggerContext。这个变量的结构体定义是 WMI_LOGGER_CONTEXT。通过 Windbg 输出这个结构体在 Win10 1709 上的定义:
在 WMI_LOGGER_CONTEXT + 0x28 的位置 GetCpuClock 是一个函数指针。这个函数将在每次触发 CKCL 事件跟踪时会被调用。
换言之就是每次发生 Syscall 时会触发 CKCL 事件,从而调用到 GetCpuClock。
GetCpuClock 的函数指针指向就是根据我们开启事件跟踪填写的 pProperty->Wnode.ClientContext 来赋值的。ClientContext 的:1、2、3,分别对应给GetCpuClock赋值:PpmQueryTime、EtwpGetSystemTime、EtwpGetCycleCount。我们之前填的3,所以这个指针应该指向 EtwpGetCycleCount。通过IDA看一下 EtwpGetCycleCount 的实现:
我们在这里将这个指针替换为我们自己的函数。
在 FakeGetCpuClock 函数内,先判断当前 PreviousMode 是否为 KernelMode。当为 KernelMode 时,我们直接返回 rdtsc() ,防止意外重入。
接着我们需要取到栈顶和栈帧,往上遍历堆栈。
在gs段寄存器中同样存放着栈顶,在其偏移量 0x1a8 的位置。
通过内联函数获取 __readgsqword 进行取值。
虽然这里可以通过 KeQueryCurrentStackInformation,进行获取。
但还记得我们文章开头说的话吗,如果被别人 Hook 了这个 API 岂不是只能甘拜下风了?
所以我们需要尽可能的少用及不用 API。
判断两个只有 Syscall 调用才会产生的标志,和之间的指针是否有在 SyscallEntry 函数范围内,以此来确定这是否是一个 Syscall 调用事件。
此次事件的 Syscall 目标指针则相对存放在当前栈的 rsp + 72h 处,我们调用另一个函数对此 Syscall 目标指针进行派发修改。
我们先在驱动入口函数中中取到 NtOpenProcess 的地址保存起来。
再与这里的 SyscallTarget 做对比,如果地址相同则修改到我们自己的 FakeNtOpenProcess。
然后在 FakeNtOpenProcess 中做相应的处理。
接着在驱动卸载例程中调用我们封装的 EventTraceControl 函数关闭或重启 CKCL。因为基本在所有系统上,CKCL 事件跟踪会话是默认开启的,所以我们尽量重启它,而不是关闭。重启之后其所有信息都会恢复默认,就不需要还原对 GetCpuClock 指针的修改了。
至此,驱动层的代码已写完。编译驱动,在虚拟机中测试看下效果。再看下 Windbg 的调试输出信息
(InfinityHook 驱动层执行流程图)(InfinityHook 钩子执行流程图)
相关参考资料链接:https://github.com/everdox/InfinityHook
https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing
https://docs.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-the-nt-kernel-logger-session
https://bbs.pediy.com/thread-223805.htm
InfinityHook 说到底也算是 PatchGuard 的一个疏忽,不出意外的话在不久的将来应该会被微软修复。但至少这短暂的时间也够看一场戏了。毕竟攻防无绝对,技术无黑白。没有攻与防之间的战斗,哪里来绝对的安全呢?

服务热线
顶部
备案号: 苏ICP备11067224号
CopyRight © 2011 书生商友信息科技 All Right Reserved
24小时服务热线:400-111-6878 E-MAIL:1120768800@qq.com QQ:1120768800
网址: http://www.768800.com 网站建设:上往建站
关键词: 网站建设| 域名邮箱| 服务器空间| 网站推广| 上往建站| 网站制作| 网站设计| 域名注册| 网络营销| 网站维护|
企业邮箱| 虚拟主机| 网络建站| 网站服务| 网页设计| 网店美工设计| 网站定制| 企业建站| 网站设计制作| 网页制作公司|
400电话办理| 书生商友软件| 葬花网| 调温纤维| 海洋馆运营维护| 北京保安公司| 殡仪馆服务| 殡葬服务| 苏州殡葬一条龙| 朝阳殡葬| 苏州殡葬服务|
欢迎您免费咨询,请填写以下信息,我们收到后会尽快与您联系
服务热线:400-111-6878