.NET内网实战:通过线程池等待对象实现线程注入

原文链接: https://mp.weixin.qq.com/s?__biz=MzUyOTc3NTQ5MA==&mid=2247500073&idx=1&sn=70def9028da43f156cc586ca9b2f6fc3

.NET内网实战:通过线程池等待对象实现线程注入

专攻.NET安全的 dotNet安全矩阵 2025-07-13 03:10

01

阅读须知

此文所节选自小报童《.NET 内网实战攻防》专栏,主要
内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧,对内网和后渗透感兴趣的朋友们可以订阅该电子报刊,解锁更多的报刊内容。

02

基本介绍

本文内容部分节选自小
报童《.NET 通过线程池等待对象实现线程注入
》,
完整的
文章内容请加入小报童后订阅查看。
现在限时
只需69元,永久
买断!
目前已有300+位朋友抢先预定,我们会长期更新,对.NET内网安全的朋友们请尽快订阅该报刊!

.NET内网实战:通过线程池等待对象实现线程注入

03

原理分析

在 Windows 操作系统中,线程池是一种高效的系统资源管理机制,被广泛用于执行异步任务、IO 完成回调、定时器事件等。微软 Windows 提供了一系列与线程池相关的原生 API,如 CreateThreadpoolWait、WaitForSingleObject 等,用于创建和管理基于事件触发的线程回调。

3.1 技术原理

线程池等待对象注入的核心思想是构造一个等待对象事件(Event),注册一个线程池等待回调,然后将 Shellcode 地址作为回调函数指针,再触发事件,系统线程池将执行 shellcode。

整个流程可分为以下几步:

1. 创建一个事件对象(Event Object)
2. 分配一块可执行内存并写入 Shellcode
3. 调用 CreateThreadpoolWait 设置 shellcode 为回调函数
4. 使用 SetThreadpoolWait 将线程池等待对象与事件绑定
5. 使用 WaitForSingleObject 或其他方法触发事件

线程池机制内部会调用 RtlpExecuteWaitCallback 来执行与该事件相关的回调函数,从而完成 shellcode 的执行。

3.2 CreateThreadpoolWait

CreateThreadpoolWait函数是Windows线程池API的组件之一,常用于创建一个等待对象,当特定的事件对象被设置为signaled状态或发生超时事件时,该等待对象将触发预设的回调函数。该函数在.NET平台下的签名如下所示。

[DllImport("kernel32.dll")]
publicstaticexternIntPtrCreateThreadpoolWait(IntPtr pfnwa,IntPtr pv,IntPtr pcb);

参数 pfnwa:指向回调函数的地址,这里我们传递 shellcode 的地址。参数 pv / pcb:通常设置为 0,可忽略。该函数返回一个 TP_WAIT 结构的指针,代表线程池等待对象。

3.3 CreateEvent

CreateEvent函数用于创建一个事件对象,一般情况下通过设置第三个参数的值为True,让事件在单个等待操作之后不会自动重置为未发信号(unsignaled)状态。该函数在.NET平台下的签名如下所示。

[DllImport("kernel32.dll")]
publicstaticexternIntPtrCreateEvent(IntPtr lpEventAttributes,bool bManualReset,bool bInitialState,string lpName);

参数 bManualReset:设置为 false,表示系统在一个等待线程被释放后自动重置信号,另外,参数 bInitialState:设置为 true,表示事件初始为 signaled 状态,确保回调能被立即触发。

3.4 实战代码解析

在红队实战中,这几个函数可能会被一起使用,作为加载和执行Shellcode等恶意代码的一种手段。下面是一个使用这些API函数加载Shellcode的示例,具体代码如下所示

string Event_lpname =null;
IntPtr Event_handle =CreateEvent(IntPtr.Zero,false,true, Event_lpname);
IntPtr Buf1_address =VirtualAlloc(IntPtr.Zero,(UInt32)buf1.Length,0x1000,0x40);
IntPtr TP_WAIT_pointer =CreateThreadpoolWait(Buf1_address, IntPtr.Zero, IntPtr.Zero);
SetThreadpoolWait(TP_WAIT_pointer, Event_handle, IntPtr.Zero);

在上述代码中,首先,通过CreateEvent函数创建一个已发信号(signaled)的事件对象,这要求将CreateEvent的第三个参数设置为TRUE,以便事件对象在单个等待操作之后保持已发信号的状态。如果未将事件对象设置true,那么任何依赖于该事件对象的线程池等待回调将不会触发,导致进程可能陷入无限等待状态。

.NET内网实战:通过线程池等待对象实现线程注入


上 ,
线程池等待对象注入技术是一种利用 Windows 系统线程池的低检测率内存注入方式。它不依赖显式线程创建,而是将 shellcode 注入到系统线程池所管理的线程中,通过事件对象触发其执行,达到隐藏行为、绕过检测的目的。
想要了解
完整或者更多的内网安全方向的文章,可以移步订阅小报童《.NET 内网实战攻防》电子报刊。

04

欢迎加入.NET 电子报刊

我们的小报童电子报刊【.NET内网安全攻防】也开始运营,引入小报童也是为了弥补知识星球对于轻量级阅读支持的不足,为用户读者提供更佳的阅读体验。
如果您对阅读体验的需求比较高,那么可以订阅这个专栏


次电子报刊《.NET 内网安全攻防》专栏,内容主要有.NET在各个内网渗透阶段与Windows系
统交互的方式和技巧,可细分为以下8个方向。

1) .NET 安全防御绕过
2) .NET 本地权限提升
3) .NET 内网信息收集
4) .NET 内网代理通道
5) .NET 内网横向移动
6) .NET 目标权限维持
7) .NET 数据传输外发
8) .NET 目标痕迹清理

原价899,现在限时
只需69元,永久买断

目前已有300+位朋友抢先预定,我们会长期更新,初步计划保持每周更新1-2篇新内容,对.NET内网安全的朋友们请尽快订阅该报刊!
图片

每增加五十人涨价10元,抓紧订阅,超值!
订阅后请关注公众号:
dotNet安全矩阵,发送订单截图和您的微信号,邀请您加入专属交流群。
感兴趣的朋友,可以点击链接:https://xiaobot.net/p/dotNetAttack,或者
扫描下方海报微信二维码加入即可

订阅后小报童定时会将最新内容通过微信推送给您。

图片