windows核心编程之使用线程APC回调安全退出多个等待线程

Windows核心编程之创建可等待定时器及其APC回调 创建可等待定时器是Windows内部线程同步的方式之一,本文简单讲述如何使用这一内核对象进行线程同步。 创建对象: //创建事件内核对象,默认未触发状态 HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL); 设置对象属性: CreateWaitableTimer创建完成后内核对象处于未触发状态,需要使用API BOOL WIN 阅读详情

前言

程序开发中经常遇到需要这些情况:辅助线程正在等待内核对象的触发,主线程需要强制终止辅助线程。我们常常做的就是使用:TerminateThread来强制终止线程。这样做当然是不太好的,强制终止线程后系统不会销毁此线程的堆栈,长久下去内存泄露问题就会很严重了。线程最安全的退出方式当然还是让它自己返回了。本文主要介绍windows核心编程中介绍的一种安全退出线程方式:使用可等待API等待内核对象触发,添加线程APC回调。

API介绍

首先得简单介绍下一个重要的windows API

DWORD WINAPI QueueUserAPC(
  __in          PAPCFUNC pfnAPC,
  __in          HANDLE hThread,
  __in          ULONG_PTR dwData
);

函数允许我们手动将一个APC回调添加到指定线程队列中,回调函数:VOID WINAPI ApcCallback1(ULONG_PTR dwParam)
这个线程可以是系统中任何线程,如果标识的线程在另一个进程中,那么回调函数的地址也必须在另一个线程的地址空间中。
QueueUserAPC也可以用来强制让线程退出等待状态,当线程正在等待内核对象触发,可以使用它强制唤醒正在等待的线程,并让它将自己杀死。

另外就是Windows提供了6个API,可将线程的状态设置为可提醒状态。

SleepEx(
__in DWORD dwMilliseconds,
__in BOOL bAlertable
);
WaitForSingleObjectEx(
__in HANDLE hHandle,
__in DWORD dwMilliseconds,
__in BOOL bAlertable
);
WaitForMultipleObjectsEx(
__in DWORD nCount,
__in_ecount(nCount) CONST HANDLE *lpHandles,
__in BOOL bWaitAll,
__in DWORD dwMilliseconds,
__in BOOL bAlertable
);
SignalObjectAndWait(
__in HANDLE hObjectToSignal,
__in HANDLE hObjectToWaitOn,
__in DWORD dwMilliseconds,
__in BOOL bAlertable
);
GetQueuedCompletionStatusEx
MsgWaitForMultipleObjectsEx 使用MWMO_ALERTABLE标识线程进入可等待状态
这五个函数的老版本API,即不带Ex的在内部实现都是调用对应的Ex函数,传入bAlertable=FALSE。

在可提醒I/O中将对这些函数的调用以及完成回调、APC回调进行详细的介绍,这里暂时省略了。

实例代码

//给每一个线程标记上一个索引值
volatile LONG	g_nIndex = 0;

UINT __stdcall Thread1(void* lpParam)
{
	//使用原子锁来操作实现用户模式下的线程同步,更加快捷
	LONG lPrevIndex = InterlockedExchangeAdd(&g_nIndex, 1);//我们需要记录原始值
	LONG lCurIndex	= lPrevIndex + 1;
	cout<<"线程"<<lCurIndex<<"开始执行"<<endl;
	while( true )
	{
		//cout<<"Thread1:"<<nIndex<<endl;
		//休眠一秒钟,线程进入可提醒状态
		if ( WAIT_IO_COMPLETION == SleepEx(1000, TRUE) )
		{//此时,我们添加一项到APC队列中了,线程可以退出了
			break;
		}
		//nIndex++;
	}
	cout<<"线程"<<lCurIndex<<"正常退出"<<endl;
	return 0;
}

//APC回调函数
VOID WINAPI ApcCallback(ULONG_PTR dwParam)
{
	//由于只是为了让线程立即正常退出,而不必杀死线程,我们在这里可以不做任何处理
	cout<<"ApcCallback:线程的APC回调函数执行"<<endl;
}


bool ApcTest()
{
	const int nThreadCount = 10;
	HANDLE hThread[nThreadCount];
	int i = 0; 
	for ( int i=0; i<nThreadCount; ++i )
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, Thread1, NULL, 0, NULL);
	DWORD dwError, dwRet;
	while( true )
	{
		dwRet = WaitForMultipleObjects(nThreadCount, hThread, TRUE, 10*1000);
		if ( dwRet == WAIT_TIMEOUT )
		{//等待超时,想办法强制终止线程

			//由于辅助线程休眠时进入可等待状态,手动添加回调到APC队列将导致毁掉执行完后线程清空队列,线程退出可提醒状态
			//此时,友好地退出线程。
			for ( i=0; i<nThreadCount; ++i )
			{
				dwRet = QueueUserAPC(ApcCallback, hThread[i], 2015);
				if ( dwRet == 0 )
				{//添加APC回调到线程APC队列失败
					dwError = GetLastError();
					break;
				}
			}
			continue;
		}
		if ( WAIT_OBJECT_0 == dwRet )
		{
			cout<<"辅助线程均已退出,循环退出…………"<<endl;
			break;
		}
	}
	for ( i=0; i<nThreadCount; ++i )
		CloseHandle(hThread[i]);
	
	return true;
}

程序运行


总结

主要就是在线程等待时,使用那些扩展的API(带Ex),使线程进入可等待状态。这时,系统会先检查线程的APC队列。由于我们向线程的APC队列中人为添加了一个回调函数,队列不为空则调用APC函数,清空队列。然后函数执行完毕返回WAIT_IO_COMPLETION,这时我们就知道是自己添加了一个APC回调,引导线程自己退出。从而实现多个等待线程安全地退出等待状态。

DLL注入的隐秘世界:揭秘APC注入技术及其防御方法 本文深入解析了Windows系统中的APC注入技术,从原理到实战防御进行全面探讨。APC注入利用线程调度机制实现代码执行,相比传统DLL注入更具隐蔽性。文章详细介绍了技术实现流程、进阶变体及企业级防御策略,帮助安全人员有效应对这一高级威胁。 阅读详情

相关推荐

替代性Shellcode执行:利用回调函数机制实现隐蔽代码注入

在计算机安全领域,Shellcode作为一段用于利用软件漏洞或执行特定任务的机器码,其加载与执行是攻防对抗的核心环节。传统直接分配可执行内存并跳转执行的方式,因特征明显而容易被安全软件检测。其原理在于操作系统和应用程序广泛使用的回调函数机制——这是一种由用户定义、系统在特定事件发生时自动调用的编程模式。从技术价值看,深入理解回调机制不仅能揭示系统底层运行逻辑,也为构建更健壮的防御体系提供基础。在应用场景上,无论是Windows的异步过程调用(APC)、定时器队列,还是Linux的信号处理程序,都为实现隐蔽的

weixin_30326515的博客 431

多线程锁详解之【WaitForSingleObject】

WaitForSingleObject

qq492927689的博客 4772

VC++实现DLL注入:原理、实战与安全攻防详解

在Windows系统编程中,进程间通信与内存管理是核心技术基础。DLL(动态链接库)作为代码复用的重要机制,其加载原理涉及系统加载器、内存映射和导入表解析。通过突破进程内存隔离,将自定义DLL加载到目标进程地址空间,可实现功能扩展、行为监控等高级技术价值。这种技术广泛应用于软件调试、安全分析、游戏模组开发等场景。本文聚焦于使用VC++实现远程线程注入,深入解析CreateRemoteThread、VirtualAllocEx等关键API的底层机制,并探讨如何应对现代安全软件的检测。通过结合进程内存操作和线程

weixin_33754065的博客 420

windows核心编程-线程退出

参考视频链接:点击打开链接

qq_22423659的博客 323

新手必看|HDevelop核心算子快速上手,为C#移植打基础

在上一篇文章中,我们完成了C#+HALCON的开发环境搭建。但在实际工业开发中,绝不会直接在C#中编写视觉算法HDevelop可视化调试算法 → 验证效果 → 导出C#代码 → 集成到上位机。HDevelop是HALCON专属的算法调试工具,支持实时预览图像、参数动态调节、零编译运行,是新手入门和工业算法调试的核心工具。本文聚焦工业场景高频使用的核心算子,从基础操作到实战案例,手把手教你使用HDevelop;同时重点讲解算法导出C#的规范,让你调试完成的算法,能无缝移植到WinForm上位机中。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 781

宽带波束形成

介绍了宽带波束形成器的时域滤波结构,以及波束响应的计算公式,宽带波束形成器的波束响应可表示为权重向量和方向向量的积

... 2490

code:插APC杀进程

apc

Richard的专栏 2511

AU混响终极指南:从‘干声’到‘空间感’,用总音轨和发送技巧打造专业人声

本文详细介绍了如何在Adobe Audition(AU)中使用混响效果器,通过总音轨和发送技巧将‘干声’转化为具有专业‘空间感’的人声。从混响基础原理到总线架构设置,再到精细控制和自动化调整,全面解析了提升音频质量的实用技巧,适用于音乐制作、播客和内容创作。

weixin_30512089的博客 333

APC

APC(异步过程调用) 使用TerminiateThread函数是往对应线程发送APC消息,线程处理APC消息后自己结束线程 ETHREAD结构中有两个APC队列,一个3环APC,一个0环APC APC是个函数,被插入线程执行 APC对列中都存放KAPC结构体 QueueAPC这个API可以插入APC函数 ...

chengtoreal的博客 388

SAP公司间采购后台配置及前台操作详解

公司间采购后台配置及前台操作详解 SAP 实施中公司间交易几乎每个项目都会有此业务需求,比如内地很多公司都会在香港设置贸易型子公司。通过香港公司接单,然后转内地公司生产,或内地公司通过香港公司采购进口原材料,这些业务必然会涉及到公司间交易,下面我将详细说明下SAP是如何实现这种业务场景的,供大家参考。 配置前必须前台先创建公司间供应商主数据和客户主数据 1. 创建相应的客户主数据 功能说明 公司间...

weixin_40672823的博客 1万+

Apollo Planning2.0决策规划算法代码详细解析 (1):环境搭建

1、官方提供连接:git clone https://github.com/ApolloAuto/application-pnc.git。此外,也更新了dreamview对pnc的支持,使得调试更加方便。apollo开源团队近期更新了planning版本,对代码进行了一定程度上的重构。(2)进入docker,并编译整个工程:./apollo.sh build_dbg。下载项目环境后使用aem进行环境配置;2、有一定基础建议直接拉取最新代码,自己手动进行编译。(1)环境安装: ./dev_start.sh。

自动驾驶Player的博客 1841

深入解析 Windows 异步过程调用(APC):原理、代码实战、避坑与跨平台视野

<think>我们需要根据用户提供的文章内容,生成一篇≤150字的摘要。用户提供了完整的文章,包括标题、前言、章节等。摘要需要简洁概括文章核心内容。注意字数限制,可能需高度浓缩。文章主要讲Windows APC机制,包括原理、用户模式APC、可警报状态、代码示例、陷阱以及跨平台对比。摘要需涵盖这些要点,但要在150字内,可能需用简短句子。考虑以“本文”开头,总结APC定义、关键条件、注意事项和跨平台差异。计算字数。中文摘要约150字。开始构思:先提出APC是Windows线程软件中断,核心是线程可警报状态,

qq_43091070的博客 298

如何在 DevOps 管道中实现 AI?

AI与DevOps的融合(AIOps)正在重塑软件开发生命周期。本文系统阐述了AI在DevOps中的五大应用场景:智能监控、自动化测试、安全防护、CI/CD优化和事件管理,并提出了六步实施框架:痛点识别、工具选型、流程集成、智能监控、MLOps和治理合规。通过Netflix、Google等企业的实践案例,验证了AI在提升部署效率(降低40%故障率)、缩短问题解决时间(MTTR减少60%)方面的显著价值,同时指出数据质量、模型偏差等实施挑战。研究表明,战略性地

介绍AWS Azure GCP devops Terraform 等技术 497

APC的结构

APC(Asynchronous Procedure Call)是一种机制,用于让内核或用户代码在指定线程的上下文中,延迟执行一段函数。可以把 APC 理解为:“有人往线程的待办事项里塞了一件事,但线程什么时候做,取决于线程什么时候看待办事项。就像是对线程说:“等你有空了,帮我顺便执行一下这段代码”,而不是“立刻中断你现在的工作”

取个名字太难了a的博客 1067

YOLOv8_obb训练流程-原理解析[旋转目标检测理论篇]

本文主要介绍了YOLOv8旋转目标检测的流程,介绍了标签的解码、预测结果的解码,以及如何理解旋转角度等内容,还介绍旋转目标检测框的正样本选取及Loss计算。

ice 4732

Python 爬虫实战:全面解析雪球网用户投资组合数据采集

本文介绍了如何使用 Python 爬虫技术,抓取雪球网用户的投资组合信息。通过模拟登录、解析页面内容等步骤,获取了用户的持仓数据。未来,可以进一步探索以下方向:

2201_76125261的博客 1304

Windows内核级APC注入驱动injdrv深度解析:跨架构进程注入技术内幕

injdrv是一款基于Windows内核APC(异步过程调用)机制的DLL注入驱动,通过内核级实现解决了传统用户态注入工具的三大技术瓶颈:进程初始化阶段注入时机难以精确控制、跨架构兼容性不足、注入过程易触发安全机制检测。该项目支持从Windows 7到Windows 10的全系列操作系统,覆盖x86、x64、ARM32和ARM64四种硬件架构,特别针对Wow64进程提供了优化的注入能力,为系统调试

gitblog_00200的博客 476

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

终极Windows内核APC注入指南:如何实现零死锁的进程注入技术

injdrv是一款革命性的Windows内核驱动,它通过异步过程调用(APC)机制实现用户态进程的DLL注入。这个开源项目重新定义了进程注入的技术边界,为安全研究人员、逆向工程师和系统开发者提供了前所未有的底层控制能力。 在Windows系统安全研究领域,APC注入技术一直被认为是高级注入技术的代表。然而,传统实现方案存在死锁风险、跨架构兼容性差、注入时机难以控制等痛点。injdrv通过巧妙的内

gitblog_00901的博客 837

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

windwos内核研究(APC队列和挂入过程)

Windows APC机制是内核异步过程调用的核心组件,允许在特定线程上下文中异步执行代码。通过_KTHREAD和_KAPC_STATE结构体管理APC队列,分为用户APC和内核APC两种类型。APC挂入过程涉及QueueUserAPC等API调用,最终通过KiInsertQueueApc插入目标线程队列。线程挂靠时使用SavedApcState保存原APC状态,确保内存访问正确性。Alertable标志决定APC执行时机,影响线程调度状态。该机制实现了Windows系统高效的异步操作和线程同步能力。

weixin_43754657的博客 697

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

让可等待的计时器添加APC调用

1 // TimerAPCRoutine.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <windows.h> 6 #include <iostream> 7 #include <time.h> 8 9 10 using ...

weixin_30699443的博客 101

Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析

Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析前言要点回顾WaitForSingleObjectNtWaitForSingleObjectKeWaitForSingleObject:上半部分关键循环总结关于强制唤醒实验:证明等待块与等待块表的关系第一步:编译并运行以下代码第二步:再WinDbg中找到该进程第三步:查看线程信息 前言 一、学习自滴水编程达人...

lzyddf的博客 3540

Windows远程线程注入的系统级稳定性与安全边界解析

远程线程注入是Windows进程间控制权移交的基础机制,其本质涉及用户态与内核态同步边界、APC队列竞争及线程状态机迁移等底层原理。理解该机制不仅关乎红蓝对抗中的EDR绕过,更直接影响企业热更新、自动化运维与工业控制软件的运行稳定性。本文聚焦真实崩溃案例(如KiInsertQueueApc栈溢出、IRQL_NOT_LESS_OR_EQUAL蓝屏),深入剖析CreateRemoteThread四阶段调度模型、Wow64上下文切换异常、SEH链破坏等关键风险点,并提供三层隔离注入框架与12项生产级实操规范,助力

chuji3953的博客 401

Windows API中线程异步API简介

【代码】Windows API中线程异步API简介。

weixin_45144862的博客 383

Windows驱动开发:系统线程创建、同步与安全退出实战

在Windows驱动开发中,异步I/O、后台轮询和长时间任务常常需要独立的执行流,而用户态线程无法直接满足内核态的资源访问与高IRQL场景。内核线程作为操作系统提供的底层并发机制,运行在System进程上下文,能够直接操作内核对象,但生命周期管理和同步设计远比用户态线程复杂。通过事件对象、超时等待与退出标志位,可以构建可靠的线程控制协议,避免驱动卸载时出现异常或蓝屏。本文以PsCreateSystemThread为主线,系统梳理内核线程的创建、同步、退出及常见故障排查方法,为驱动开发者提供一套可落地的工程实

weixin_32715349的博客 171

Linux线程池实现目录拷贝,多线程文件复制——线程池使用实例(一)

多线程程序设计是Windows程序设计的难点之一。为帮助进行多线程程序设计,Windows提供了线程池机制。《Windows核心编程》的第十一章详细介绍了线程池的使用方法。最近再次阅读这一章,比先前囫囵吞枣的阅读理解深多了,正是所谓的“读书三遍,其义自现”。“纸上得来终觉浅,绝知此事要躬行”,为此,写了个简单的文件复制程序,实验各种线程池机制的使用方法。程序使用了《Windows核心编程》第十一章...

weixin_39600400的博客 1083

关于线程切换与异步调用相关的几句话----摘自《Windows内核情景分析》

关于线程,异步IO,APC, DPC,中断服务等相关的几句解渴的话。

smstong的成长轨迹 1948
上一篇: LocalAlloc,VirtualAlloc,malloc,new的异同
下一篇: windows下编译openssl
疯狂-的-蜗牛
博客等级 码龄16年 427粉丝 104原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值