当前位置: 首页 > web >正文

2507C++,APC可以干的活

原文

窗口中的异步过程调用(APC)是可附加进线程的对象.每个线程都有自己的存储要调用的函数和参数APC队列.

想法是,希望由特定线程而不是某个任意线程执行a函数.这是因为线程所属的进程有时很重要,因此APC(执行时)可完全访问该进程资源.

技术上,有用户模式,内核模式特殊内核模式APC,这里,讨论用户模式APC,即窗口接口直接支持的用户模式APC.
还有特殊用户模式APC,但它一般不可用.下面是线程及其APC队列的概念表示:

线程==用户模式APC队列 APC APC APC APC
线程==内核模式APC队列 APC APC 线程及其`APC`队列

当在线程中排队用户模式APC时,APC只是坐在队列中闲着.要实际运行当前附加进线程的APC,该线程必须进入可警告等待(也叫可警告状态).

在该状态时,线程队列中的任何和所有APC将按顺序执行.但是线程如何进入可警告等待?

有一些函数可完成.最简单的是扩展的休息函数SleepEx,这里:

DWORD SleepEx(DWORD msec, BOOL alertable);

如果可警告,则该函数休息相同.否则,线程将休息指定的时间(可为零),如果在其队列中任何APC退出(或在休息时出现),则现在将执行并结束休息,此时,SleepEx返回值WAIT_IO_COMPLETION而不是零.

典型的调用可能是SleepEx(0,TRUE),以强制运行所有排队的APC(如果有).可按APC"垃集"对待此调用.如果线程从未进入可警告等待,则不会执行任何附加的APC.

进入可警告等待的其他方法,涉及使用各种等待函数的扩展版本,如WaitForSingleObjectEx,WaitForMultipleObjectsEx,它们都接受与SleepEx一样的额外的布尔参数.
这里
这里
MsgWaitForMultipleObjectsEx也可这样,只是使用(MWMO_ALERTABLE)标志,而不是指定可警告状态的极.
这里

异步I/O完成

用户模式APC"经典"用法是,取异步I/O操作的通知.对此,窗口有多种机制,其中一个涉及APC.即,ReadFileExWriteFileEx,API接收一个(与其非Ex变量相比)异步I/O操作完成时要调用的回调额外的参数.
这里
这里

问题是,回调包装在请求线程中排队的APC中,即只能在该线程进入可警告等待时执行它.下面是一些概念代码:

HANDLE hFile = ::CreateFile(..., FILE_FLAG_OVERLAPPED, nullptr);
OVERLAPPED ov{};
ov.Offset = ...;
::ReadFileEx(hFile, buffer, size, &ov, OnIoCompleted);//其他工作......//不时执行 APC:
::SleepEx(0, TRUE);

完成例程有以下原型:

void OnIoCompletion(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped);

实际上,这种通知异步/O完成的机制不是很流行,因为使用同一线程来完成一般不方便.事实上,线程可能会在I/O完成之前退出.尽管如此,它仍是一个利用APC的选项.

进程中注入DLL

有时"强制"另一个进程加载你提供的DLL很有用.完成的经典方法是,使用按LoadLibrary,API的地址设置"线程函数"的CreateRemoteThread,API,因为从二进制角度来看,线程的函数LoadLibrary有相同原型,因为两者都接受指针.
这里
这里

LoadLibrary传递要加载的DLL路径.视频
完整源码在此.

该方法的问题是它非常明显,在创建线程时会通知反恶意软件内核驱动,如果由不同进程中的线程创建,在驱动看来,是可疑的.

顺便,CreateRemoteThread"合法"用法是调试器通过强制进程中的新线程调用DbgBreakPoint,来强制中断到初始附加中的目标进程.

使用APC,也许可"说服"现有线程加载我们的DLL.这要隐蔽得多,因为它是现有线程加载DLL,这非常常见.为此,可用通用的QueueUserAPC,API,这里:

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

幸好,APC函数有与线程函数相同的二进制布局,再次,接收某种指针.主要问题目标线程可能不会进入可警告的等待.

为了增加成功概率,可在目标进程中排队所有线程的APC,只需要一个线程即可进入可警告的等待.这对像资管此类有很多线程的进程效果很好,几乎总是可工作,视频.

自然队列

最后,因为在队列中保存APC,因此只需使用APC就可非常自然地创建一个"工作队列".如果需要顺序调用函数队列,可借助C++中的std::queue<>自行管理它们.

但是该队列不是线安的,因此你必须正确保护它.如果使用的是.NET,则可用ConcurrentQueue<>来帮助同步,但仍要构建某种循环弹出项目,调用它们等.
有了APC,一切都自然而简单:

void WorkQueue(HANDLE hQuitEvent) {while(::WaitForSingleObjectEx(hQuitEvent, INFINITE, TRUE) != WAIT_OBJECT_0);
}

简单自身.可用事件对象来退出此无限循环(从某处调用的SetEvent).线程等待APC出现在其队列中,并在出现时运行它们,返回等待.
这里
此队列的客户调用QueueUserAPC在该线程中入队工作项(回调).就是这样,简单而优雅.

http://www.xdnf.cn/news/16516.html

相关文章:

  • 第二阶段-第二章—8天Python从入门到精通【itheima】-138节(MySQL的综合案例)
  • 记录一次薛定谔bug
  • SpringAI入门及浅实践,实战 Spring‎ AI 调用大模型、提示词工程、对话记忆、Adv‎isor 的使用
  • goland编写go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案
  • red靶机
  • zabbix-agent静默安装
  • AI编程自动化与算法优化实践指南
  • Oracle 19C RU 19.28 升级和安装
  • Spring Cloud 详解与搭建全攻略
  • MySQL的底层原理--InnoDB数据页结构
  • Java实现大根堆与小根堆详解
  • 53. 最大子数组和
  • 在 Windows 系统中实现 WinToGo 的 VHDX 文件切换使用的常见方法
  • 9.3 快速傅里叶变换
  • Cortex-M内核SysTick定时器介绍
  • [2025CVPR-图象合成、生成方向]ODA-GAN:由弱监督学习辅助的正交解耦比对GAN 虚拟免疫组织化学染色
  • 【Keepalived】高可用集群
  • 香港本地和国际金融科技应用
  • Javaweb————HTTP的九种请求方法介绍
  • RoPE:相对位置编码的旋转革命——原理、演进与大模型应用全景
  • 【micro:bit】从入门到放弃(六):示例蜂鸣器音乐、摇色子、光照强度、串口调试、麦克风
  • mac版SVN客户端
  • “Datawhale AI夏令营”「结构化数据的用户意图理解和知识问答挑战赛」1
  • 最优估计准则与方法(5)加权最小二乘估计(WLS)_学习笔记
  • 【图像分割】记录1:unet, yolov8_seg
  • 基于springboot的在线数码商城/在线电子产品商品销售系统的设计与实现
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘ipython’问题
  • 【iOS】网易云仿写
  • 【守护】同为科技SPD:AP-20D/4P产品解析
  • 【leetGPU】1. Vector Addition