首先,我们将介绍两种与线程挂起有关的新方法。它们不是最具革命性或有用的,但我会尽力做到最好。
这是Microsoft在19H1中添加的一个可爱的小线程创建标记。有没有想过为什么在线程创建标志中存在漏洞?好吧,这个漏洞已经充满了一个我称之为的标志THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE
(我不知道它的实际名字),其值自然是0x40
。
为了演示它的作用,我将展示PsSuspendProcess的工作原理:
NTSTATUS PsSuspendProcess(_EPROCESS* Process) { const auto currentThread = KeGetCurrentThread(); KeEnterCriticalRegionThread(currentThread); NTSTATUS status = STATUS_SUCCESS; if ( ExAcquireRundownProtection(&Process->RundownProtect) ) { auto targetThread = PsGetNextProcessThread(Process, nullptr); while ( targetThread ) { // Our flag in action if ( !targetThread->Tcb.MiscFlags.BypassProcessFreeze ) PsSuspendThread(targetThread, nullptr); targetThread = PsGetNextProcessThread(Process, targetThread); } ExReleaseRundownProtection(&Process->RundownProtect); } else status = STATUS_PROCESS_IS_TERMINATING; if ( Process->Flags3.EnableThreadSuspendResumeLogging ) EtwTiLogSuspendResumeProcess(status, Process, Process, 0); KeLeaveCriticalRegionThread(currentThread); return status; }
如您所见,NtSuspendProcess
该调用PsSuspendProcess
将仅忽略带有此标志的线程。另一个好处是该线程也不会被挂起NtDebugActiveProcess
!据我所知,一旦使用该线程创建了线程,就无法查询或禁用该标志,因此您不能对此做太多事情。
就其有用性而言,我想说这只是防止转储的一个好方法,当您在Processhacker中单击“暂停”时,会引起混乱,并且该过程继续进行,就像什么也没发生一样。
例如,这是一个有点有趣的代码,它将继续打印I am running
。我敢肯定,在倒车时看到这一点会引起很多困惑,为什么地狱会中止他自己的过程。
#define THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE 0x40 NTSTATUS printer(void*) { while(true) { std::puts("I am running\n"); Sleep(1000); } return STATUS_SUCCESS; } HANDLE handle; NtCreateThreadEx(&handle, MAXIMUM_ALLOWED, nullptr, NtCurrentProcess(), &printer, nullptr, THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE, 0, 0, 0, nullptr); NtSuspendProcess(NtCurrentProcess());
继续保持行为不检点的趋势NtSuspendProcess
,我们将再次滥用它如何检测我们的流程是否被暂停。
诀窍在于,暂停计数是一个带符号的8位值。就像上一个一样,这里有一些代码可以让您了解内部工作原理:
ULONG KeSuspendThread(_ETHREAD *Thread) { auto irql = KeRaiseIrql(DISPATCH_LEVEL); KiAcquireKobjectLockSafe(&Thread->Tcb.SuspendEvent); auto oldSuspendCount = Thread->Tcb.SuspendCount; if ( oldSuspendCount == MAXIMUM_SUSPEND_COUNT ) // 127 { _InterlockedAnd(&Thread->Tcb.SuspendEvent.Header.Lock, 0xFFFFFF7F); KeLowerIrql(irql); ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED); } auto prcb = KeGetCurrentPrcb(); if ( KiSuspendThread(Thread, prcb) ) ++Thread->Tcb.SuspendCount; _InterlockedAnd(&Thread->Tcb.SuspendEvent.Header.Lock, 0xFFFFFF7F); KiExitDispatcher(prcb, 0, 1, 0, irql); return oldSuspendCount; }
如果您看一下第一个代码示例,PsSuspendProcess
它没有错误检查,也不会在乎是否不再挂起线程。那么打电话时会发生什么NtResumeProcess
呢?它减少了挂起计数!我们需要做的就是最大限度地利用它,当有人决定暂停并恢复我们时,他们实际上会将计数保持在以前未处于的状态。
下面的简单代码相当有效:
NtSuspendProcess
并导致将其检测到,但是在我报告后已修复。for(size_t i = 0; i < 128; ++i) NtSuspendThread(thread, nullptr); while(true) { if(NtSuspendThread(thread, nullptr) != STATUS_SUSPEND_COUNT_EXCEEDED) std::puts("I was suspended\n"); Sleep(1000); }
如果有的话,我希望这表明最好不要依赖于NtSuspendProcess
您期望的工具来处理潜在的恶意代码或受保护的代码。希望您喜欢这篇文章,并希望在接下来的几周内能有更多的内容。
全球的数据生成速度不会很快放缓。根据预测,到2021年,全球每人每秒将平均产生...
.ltd的 域名 怎么样?这个后缀是新通用顶级域名,一般被人们认为是代表“有限公...
爆炸性增长的数据带来了价值增长地带,合理利用数据诚然可以提升企业运行效率。...
近日米市中出现不少 域名交易 、结拍的消息,其中一枚组合 域名 cbaleague.com以...
很多企业用户想一览阿里云服务器租用价格表,便于详细了解前期项目开支预算,因...
2020年的云计算市场整体上可谓扶云直上,但是如果盘点过去一年云市场格局变化以...
网络安全技能的差距如今仍然是一个现实问题,但最终可能会解决。根据(ISC)公司发...
Kafka宕机引发的高可用问题 问题要从一次Kafka的宕机开始说起。 笔者所在的是一...
我们都知道开发过程中应该编写单元测试,实际上我们中的许多人都这样做。对于生...
目前,据不完全统计,我国的程序员俨然已经超过500万了,并且这个数字目前还在不...