QueueUserAPC简介

QueueUserAPC是一个简洁的工具,通常可以用作某些通过同步对象处理的任务的快捷方式。它允许您告诉特定线程在该线程方便的时候(即何时完成其当前工作并开始等待某件事)执行某项操作。

假设您有一个主线程和一个工作线程。辅助线程打开文件服务器的套接字,并通过循环调用recv()开始下载10GB文件。主线程希望在等待网络数据包时让工作线程在停机期间执行其他操作。它可以将要在工作程序上运行的功能排队,否则它将等待并且什么也不做。

您必须小心APC,因为在我提到的情况下,您不想进行另一个阻塞的WinSock调用(这将导致未定义的行为)。您确实必须注意才能找到此功能的任何好用法,因为您可以通过其他方式来做同样的事情。例如,通过让另一个线程在每次即将进入睡眠状态时检查一个事件,而不是赋予它在等待时运行的功能。显然,在这种情况下,APC会更简单。

就像您有一个电话服务台员工坐着等待电话,而您却给该人员在停机期间几乎没有什么工作要做。 “在这里,等你的时候解决这个魔方。”尽管当有电话打进来时,此人不会放下魔方来接听电话(APC必须返回,线程才能返回等待状态)。

如果只有一个线程(线程A)负责某些数据结构,并且您想要对另一个线程(线程B)的数据结构执行某些操作,则QueueUserAPC也很有用。尝试在两个线程之间共享数据的同步开销/复杂性。通过让线程B将要在线程A上运行的操作排队(该线程仅维护该结构),您可以在该数据上执行所需的任意函数,而不必担心同步。

它只是另一个工具,例如线程池。但是,对于线程池,您无法将任务发送到特定线程。您无法控制在哪里完成工作。当您将一个任务排队时,可能最终会创建一个新线程。您可以将两个任务排队,并且它们同时在两个不同的线程上完成。使用QueueUserAPC,可以保证任务将按顺序完成并在指定的线程上完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
APC (Asynchronous Procedure Call) 是一种常见的 Windows 操作系统技术,通过在指定线程上异步执行指定函数的方式实现进程间通信或线程间通信,常见的应用场景包括 Hook、注入 DLL 等等。 以下是一个简单的 C 语言 APC 注入实现过程: ```c #include <stdio.h> #include <windows.h> void apcFunc(ULONG_PTR dwParam) { printf("APC injected successfully!\n"); } int main() { HANDLE hProcess; HANDLE hThread; PTHREAD_START_ROUTINE pfnThreadRtn; LPVOID lpRemoteBuffer; SIZE_T dwBufferSize = strlen("kernel32.dll") + 1; SIZE_T dwBytesWritten; HMODULE hKernel32; FARPROC pfnQueueUserAPC; // 获取目标进程句柄 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, <PID>); if (!hProcess) { printf("OpenProcess error: %d\n", GetLastError()); return 1; } // 在目标进程中申请一块内存空间 lpRemoteBuffer = VirtualAllocEx(hProcess, NULL, dwBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!lpRemoteBuffer) { printf("VirtualAllocEx error: %d\n", GetLastError()); return 1; } // 将 DLL 名称写入申请的内存空间 if (!WriteProcessMemory(hProcess, lpRemoteBuffer, "kernel32.dll", dwBufferSize, &dwBytesWritten)) { printf("WriteProcessMemory error: %d\n", GetLastError()); return 1; } // 获取 LoadLibraryA 函数地址 hKernel32 = GetModuleHandle("kernel32.dll"); pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"); if (!pfnThreadRtn) { printf("GetProcAddress error: %d\n", GetLastError()); return 1; } // 在目标进程中启动一个线程,执行 LoadLibraryA("kernel32.dll") 函数 hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, lpRemoteBuffer, 0, NULL); if (!hThread) { printf("CreateRemoteThread error: %d\n", GetLastError()); return 1; } // 等待线程执行完毕 WaitForSingleObject(hThread, INFINITE); // 获取 QueueUserAPC 函数地址 pfnQueueUserAPC = GetProcAddress(hKernel32, "QueueUserAPC"); if (!pfnQueueUserAPC) { printf("GetProcAddress error: %d\n", GetLastError()); return 1; } // 在目标线程上执行 APC if (!QueueUserAPC((PAPCFUNC)apcFunc, hThread, 0)) { printf("QueueUserAPC error: %d\n", GetLastError()); return 1; } printf("APC injection complete!\n"); // 关闭句柄 CloseHandle(hThread); CloseHandle(hProcess); return 0; } ``` 需要注意的是,在实际使用中,需要将 `<PID>` 替换成目标进程的进程 ID,以及将 `apcFunc` 函数替换成需要注入的函数。同时,为了防止注入失败,还需要注意一些细节问题,如权限、内存大小、错误处理等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值