通过异步过程调用(APC)注入DLL
2015-11-20 15:44
411 查看
关于APC的介绍,可以参考MSDN对Asynchronous Procedure Calls的介绍(索引APCs),下面是简单翻译的一段文字。
APC(Asynchronous Procedure Calls,异步过程调用)是指在一个特定的线程环境中异步的执行代码。当一个APC被添加到一个线程的APC队列的时候,系统会产生一个软中断;当线程下一次被调度的时候APC函数将被执行。操作系统产生的APC称为内核模式APC,应用程序产生的APC称为用户模式APC。只有当线程处于可唤醒状态(alertable state),用户模式的APC才会被执行。
每一个线程都有自己的APC队列,应用程序可以通过调用QueueUserAPC来队列中插入APC。当一个用户模式的APC插入APC队列之后,与之关联的线程并不会立即执行APC函数,除非线程进入可唤醒状态。当线程调用SleepEx、SignalObjectAndWait、MsgWaitForMultipleObjectsEx、WaitForMultipleObjectsEx、WaitForSingleObjectEx这些函数的时候会进入可唤醒状态。如果在APC插入队列之前线程已经进入等待状态,那么APC函数将不会被执行,但APC会仍然存在于队列之中,所以APC函数将会在线程下一次进入可唤醒状态的时候被执行。
如果要通过QueueUserAPC来注入DLL模块,可以向指定进程的每一个线程(增加执行机会)都插入一个APC,然后把LoadLibrary作为APC函数的过程函数,把DLL路径字符串作为过程函数的参数。
示例代码:
APC(Asynchronous Procedure Calls,异步过程调用)是指在一个特定的线程环境中异步的执行代码。当一个APC被添加到一个线程的APC队列的时候,系统会产生一个软中断;当线程下一次被调度的时候APC函数将被执行。操作系统产生的APC称为内核模式APC,应用程序产生的APC称为用户模式APC。只有当线程处于可唤醒状态(alertable state),用户模式的APC才会被执行。
每一个线程都有自己的APC队列,应用程序可以通过调用QueueUserAPC来队列中插入APC。当一个用户模式的APC插入APC队列之后,与之关联的线程并不会立即执行APC函数,除非线程进入可唤醒状态。当线程调用SleepEx、SignalObjectAndWait、MsgWaitForMultipleObjectsEx、WaitForMultipleObjectsEx、WaitForSingleObjectEx这些函数的时候会进入可唤醒状态。如果在APC插入队列之前线程已经进入等待状态,那么APC函数将不会被执行,但APC会仍然存在于队列之中,所以APC函数将会在线程下一次进入可唤醒状态的时候被执行。
如果要通过QueueUserAPC来注入DLL模块,可以向指定进程的每一个线程(增加执行机会)都插入一个APC,然后把LoadLibrary作为APC函数的过程函数,把DLL路径字符串作为过程函数的参数。
示例代码:
#include <windows.h> #include <TlHelp32.h> #include <stdio.h> #include <string.h> #define CHECK_NULL_RET(bCondition) if (!bCondition) goto Exit0 BOOL EnableDebugPrivilege(void) { HANDLE hToken; TOKEN_PRIVILEGES tkp; BOOL bRet = FALSE; bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); CHECK_NULL_RET(bRet); bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid); CHECK_NULL_RET(bRet); tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; bRet = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); CHECK_NULL_RET(bRet); bRet = TRUE; Exit0: CloseHandle(hToken); return bRet; } BOOL ApcInject(DWORD dwPid, CHAR *pszDllPath) { HANDLE hProcess = NULL; BOOL bRet = FALSE; HANDLE hSnapshot = NULL; LPVOID lpDllName = NULL; DWORD dwResult = 0; THREADENTRY32 te32; bRet = EnableDebugPrivilege(); CHECK_NULL_RET(bRet); hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); CHECK_NULL_RET(bRet); lpDllName = VirtualAllocEx(hProcess, NULL, strlen(pszDllPath) + 1, MEM_COMMIT, PAGE_READWRITE); CHECK_NULL_RET(lpDllName); bRet = WriteProcessMemory(hProcess, lpDllName, (LPVOID)pszDllPath, strlen(pszDllPath) + 1, &dwResult); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPid); CHECK_NULL_RET((hSnapshot != INVALID_HANDLE_VALUE)); te32.dwSize = sizeof(THREADENTRY32); bRet = Thread32First(hSnapshot, &te32); while (bRet) { if (te32.th32OwnerProcessID == dwPid) { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); if (hThread) { dwResult = QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpDllName); CloseHandle(hThread); } } te32.dwSize = sizeof(THREADENTRY32); bRet = Thread32Next(hSnapshot, &te32); } Exit0: // VirtualFreeEx CloseHandle(hSnapshot); CloseHandle(hProcess); // Do NOT check this value return bRet; } int main(int argc, char **argv) { if (argc != 3) { printf("Usage: %s PID DllPath\n", argv[0]); return 1; } ApcInject(atoi(argv[1]), argv[2]); return 0; }
相关文章推荐
- Win下如何安装PHP的APC拓展
- 深入解析php之apc
- Linux下PHP加速器APC的安装与配置笔记
- PHP利用APC模块实现大文件上传进度条的方法
- PHP的APC模块实现上传进度条
- php使用APC实现实时上传进度条功能
- PHP利用APC模块实现文件上传进度条的方法
- 使用php+apc实现上传进度条且在IE7下不显示的问题解决方法
- PHP APC的安装与使用详解
- PHP APC缓存配置、使用详解
- windows 安装PHP缓存加速器 Alternative PHP Cache (APC) 扩展
- PHP APC 配置详解
- 三款免费的PHP加速器:APC、eAccelerator、XCache比较
- php apc
- 这个是APC注入?
- 在RHEL/CentOS 6.3/5.6和Fedora 17/12上安装APC
- 学习PHP精粹,编写高效PHP代码之性能
- PHP之APC缓存
- Alertable I/O
- php apc缓存以及与redis的对比