APC,即Asynchronous procedure call,异步程序调用
APC注入的原理是:
在一个进程中,当一个执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断,当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数,利用QueueUserAPC()这个API,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,

注入流程:
1.根据进程名称得进程ID
2.枚举该进程中的线程
3.将自己的函数插入到每个线程的APC队列中

#include "stdafx.h"
#include <windows.h>
#include <Tlhelp32.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h> using namespace std; typedef struct _THREADLIST
{
DWORD dwThreadId;
_THREADLIST *pNext;
}THREADLIST; int q = ; DWORD GetProcessID(const char *szProcessName);
int EnumThreadID(DWORD dwPID, THREADLIST * pdwTidList);
THREADLIST* InsertThreadId(THREADLIST *pdwTidListHead, DWORD dwTid);
DWORD Inject(HANDLE hProcess, THREADLIST *pThreadIdList); int main()
{
THREADLIST *pThreadIdHead = NULL;
pThreadIdHead = (THREADLIST *)malloc(sizeof(THREADLIST));
if (pThreadIdHead == NULL)
{
printf("申请失败");
return ;
} //ZeroMemory是美国微软公司的软件开发包SDK中的一个宏。 其作用是用0来填充一块内存区域
ZeroMemory(pThreadIdHead, sizeof(THREADLIST)); DWORD dwProcessID = ; if ((dwProcessID = GetProcessID("explorer.exe")) == )
{
printf("进程ID获取失败!\n");
return ;
} EnumThreadID(dwProcessID, pThreadIdHead); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID); if (hProcess == NULL)
{
printf("打开进程失败");
return ;
} Inject(hProcess, pThreadIdHead);
cout<<q;
getchar();
getchar();
return ;
} DWORD GetProcessID(const char *szProcessName)
{
//PROCESSENTRY32这个宏在<Tlhelp32.h>中
PROCESSENTRY32 pe32 = { };
pe32.dwSize = sizeof(PROCESSENTRY32);
//创建线程快照
HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, ); if (SnapshotHandle == INVALID_HANDLE_VALUE)
{
return ;
} if (!Process32First(SnapshotHandle, &pe32))
{
return ;
} do
{
if (!_strnicmp(szProcessName, pe32.szExeFile, strlen(szProcessName)))
{
printf("%s的PID是:%d\n", pe32.szExeFile, pe32.th32ProcessID);
return pe32.th32ProcessID;
}
//Process32Next是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后, 我们可以利用Process32Next函数来获得下一个进程的句柄
} while (Process32Next(SnapshotHandle, &pe32)); return ;
} int EnumThreadID(DWORD dwPID, THREADLIST * pdwTidList)
{
int i = ; THREADENTRY32 te32 = { };
te32.dwSize = sizeof(THREADENTRY32); HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPID); if (SnapshotHandle != INVALID_HANDLE_VALUE)
{
if (Thread32First(SnapshotHandle, &te32))
{
do
{
if (te32.th32OwnerProcessID == dwPID)
{
if (pdwTidList->dwThreadId == )
{
pdwTidList->dwThreadId = te32.th32ThreadID;
}
else
{
if (NULL == InsertThreadId(pdwTidList, te32.th32ThreadID))
{
printf("插入失败!\n");
return ;
}
} }
} while (Thread32Next(SnapshotHandle, &te32));
}
} return ;
} THREADLIST* InsertThreadId(THREADLIST *pdwTidListHead, DWORD dwTid)
{
THREADLIST *pCurrent = NULL;
THREADLIST *pNewMember = NULL; if (pdwTidListHead == NULL)
{
return NULL;
}
pCurrent = pdwTidListHead; while (pCurrent != NULL)
{ if (pCurrent->pNext == NULL)
{
// 定位到链表最后一个元素
pNewMember = (THREADLIST *)malloc(sizeof(THREADLIST)); if (pNewMember != NULL)
{
pNewMember->dwThreadId = dwTid;
pNewMember->pNext = NULL;
pCurrent->pNext = pNewMember;
return pNewMember;
}
else
{
return NULL;
}
}
pCurrent = pCurrent->pNext;
} return NULL;
} DWORD Inject(HANDLE hProcess, THREADLIST *pThreadIdList)
{
THREADLIST *pCurrentThreadId = pThreadIdList; const char szInjectModName[] = "需要加载的自己的动态库路径";
DWORD dwLen = strlen(szInjectModName) + ; PVOID param = VirtualAllocEx(hProcess,
NULL, dwLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); UINT_PTR LoadLibraryAAddress = (UINT_PTR)GetProcAddress(GetModuleHandle("Kernel32.dll"), "LoadLibraryA"); if (param != NULL)
{
SIZE_T dwRet;
if (WriteProcessMemory(hProcess, param, (LPVOID)szInjectModName, dwLen, &dwRet))
{
while (pCurrentThreadId)
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pCurrentThreadId->dwThreadId); if (hThread != NULL)
{
//注入DLL到指定进程
QueueUserAPC((PAPCFUNC)LoadLibraryAAddress, hThread, (ULONG_PTR)param);
printf("OK\r\n"); q++; } printf("ThreadID:%d\n", pCurrentThreadId->dwThreadId);
pCurrentThreadId = pCurrentThreadId->pNext;
}
}
}
return ;
}

如果OpenProce或者OpenThread失败,可以尝试提权,或者给UAC,以管理员身份启动。

不过我个人觉得,这个方法不是每次都能成功,只有线程多的进程,才比较容易成功。win7 测试成功,Win10不是每次成功。

另外没有提供删除APC队列中函数的方法,所以不能反复注入。

Dll注入:Ring3 层 APC注入的更多相关文章

  1. Dll注入技术之APC注入

    APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:     1)当EXE里某个线程执行到SleepEx( ...

  2. 注入理解之APC注入

    近期学习做了一个各种注入的MFC程序,把一些心得和体会每天分享一些 APC(Asynchronous procedure call)异步程序调用,在NT中,有两种类型的APCs:用户模式和内核模式.用 ...

  3. Windows x86/ x64 Ring3层注入Dll总结

    欢迎转载,转载请注明出处:http://www.cnblogs.com/uAreKongqi/p/6012353.html 0x00.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线 ...

  4. 分析恶意驱动(进程启动apc注入dll)

    一.前言  用IDA也有好些时间了,以前就只会用F5功能玩无壳无保护的裸驱动,感觉太坑了,这两天就开始看网上大牛的逆向. 今天记录一下sudami曾经逆向过的fuck.sys.第一遍自己走的时候漏掉了 ...

  5. DLL注入-APC注入

    APC注入 APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:     1)当EXE里某个线程执行到Sl ...

  6. APC注入

    0X01 注入原理 当线程被唤醒时APC中的注册函数会被执行的机制,并依此去调用我们的DLL加载代码,进而完成注入的目的 具体的流程: 1 当EXE里的某个线程执行到sleepEX(),或者waitF ...

  7. 常见注入手法第二讲,APC注入

    常见注入手法第二讲,APC注入 转载注明出处 首先,我们要了解下什么是APC APC 是一个简称,具体名字叫做异步过程调用,我们看下MSDN中的解释,异步过程调用,属于是同步对象中的函数,所以去同步对 ...

  8. DEDECMS数据库执行原理、CMS代码层SQL注入防御思路

    我们在上一篇文章中学习了DEDECMS的模板标签.模板解析原理,以及通过对模板核心类的Hook Patch来对模板的解析流量的攻击模式检测,达到修复模板类代码执行漏洞的目的 http://www.cn ...

  9. Dll注入:注册表注入

    在系统中每一个进程加载User32.dll时,会受到DLL_PROCESS_ATTACH通知,当User32.dll对其进行处理时,会取得注册表键值HKEY_LOCAL_MACHINE\Softwar ...

随机推荐

  1. nessus安装及使用

    1.安装注册 (1)从https://www.tenable.com/products/nessus/select-your-operating-system上下载对应操作系统版本的nessus,结果 ...

  2. 51nod1419 【数学】

    思路: n<=3,就是n. 考虑n>3: 我们可以轻松证明n,n-1这两个数互质: 设gcd(n,n-1)=g,n=g*k1,n-1=g*k2; n-(n-1)=g(k1-k2)=1; 所 ...

  3. 2017-10-26 NOIP模拟赛

    三分咲 #include<iostream> #include<cstdio> #include<ctime> using namespace std; int n ...

  4. Cogs 465. 挤牛奶

    465. 挤牛奶 ★   输入文件:milk2.in   输出文件:milk2.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 三个农民每天清晨5点起床,然后去牛棚给3 ...

  5. vue-cli3.0 使用图形化界面创建和管理项目

    1.打开终端输入vue ui vue ui 2.创建项目 3.选择一套预设,点击创建项目按钮 4.等待安装 5.安装完成后 6.可以添加插件 7.项目依赖管理 8.项目配置管理 9.项目任务管理 10 ...

  6. 3、kubernetes应用快速入门190625

    一.kubernetes应用入门 1.kubectl命令 Basic Commands create Create a resource from a file or from stdin. expo ...

  7. AT2044 Teleporter

    传送门 这个是真的简单题,随便手玩一下就可以发现最优策略一定是给\(1\)加上自环 然后就可以dfs一下看哪些点子树里深度最深的点到当前点的距离会等于\(k-1\),然后将当前点连向\(1\)(当然特 ...

  8. git教程3-分支

    https://git-scm.com/book/zh/v1/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E7%AE%A1%E7%90%86 ...

  9. MD5Utils

    import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import com.yundae ...

  10. LeetCode 236 Lowest Common Ancestor of a Binary Tree 二叉树两个子节点的最低公共父节点

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...