通过异步过程调用(APC)注入DLL
2015-12-05 23:36
435 查看
关于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路径字符串作为过程函数的参数。
示例代码:
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/apc-injection.html
// ApcInjection.cpp
// Author: 代码疯子
// Blog: http://www.programlife.net/
#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;
}
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/apc-injection.html
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路径字符串作为过程函数的参数。
示例代码:
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/apc-injection.html
// ApcInjection.cpp
// Author: 代码疯子
// Blog: http://www.programlife.net/
#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;
}
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/apc-injection.html
相关文章推荐
- service介绍之IntentService与Notification前台通知
- Switch
- linux常用命令
- PHP
- codeforces 547B. Mike and Feet 单调栈
- 22
- 昂贵的珍珠垂饰
- 计算机网络_2_TCP/IP
- 去掉电脑快捷方式小箭头
- 第二百四十七天 how can I 坚持
- 查看Ubuntu/Redhat等Linux系统版本号等系统信息
- Number Steps
- 有趣的一天。。。。恰巧下雪
- CSS学习要点
- 106-背包问题
- 跨域解决方案总结
- 使用VMDepot镜像快速部署CKAN开放数据门户
- XDOC编辑器支持新版本Chrome浏览器
- 使用XDOC云服务做套打
- PDF生成进入基于Web服务的模板时代