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. 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备

    在尝试内核开发之前,需要对内核有个整体的了解. 主要内容: 获取内核源码 内核源码的结构 编译内核的方法 内核开发的特点 1. 获取内核源码 内核是开源的,所有获取源码特别方便,参照以下的网址,可以通 ...

  2. [WIP]laravel 入门

    创建: 2019/06/20 安装    composer brew install composer  laravel composer global require "laravel/i ...

  3. Codeforces Round#522 Div2E(思维,背包,组合数学)

    #include<bits/stdc++.h>using namespace std;int a[107];int b[10007][107];int c[107][107];int ma ...

  4. 用js实现倒计时功能

    源码如下: 原理很简单,看注释吧 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  5. Docker存储卷

    六.Docker 存储卷(volume) COW:写时复制 Bind mount volume:手动mount绑定的卷 # docker run --name centos-3 -it -v /dat ...

  6. dorado开发模式下实现动态查询

    使用dorado开发模式,我们可以实现以下开发技巧 开发技巧1.实现动态查询功能: 1. 查询按钮的onClick事件中写入: datasetEmployee.parameters().setValu ...

  7. AT2160 へんなコンパス / Manhattan Compass

    传送门 乍一看像是一个计算几何,然后想到了BFS,但是苦于无奈\(O(n^2)\)不会优化 然后以下参考zjq_shadow大佬的思路 显然发现曼哈顿距离很麻烦,除了暴力枚举貌似没什么很好的办法 考虑 ...

  8. day16正则表达式作业详解

    1.正则表达式练习题 点击查看详细内容 作业的讲解 1.匹配整数或者小数(包括正数和负数) -?\d+.\d+|-?\d+ -?\d+(\.\d+)? 2.匹配年月日日期 格式2018-12-6 #找 ...

  9. OnclickListener

    https://developer.android.com/reference/android/view/View.OnClickListener.html# https://blog.csdn.ne ...

  10. HTTP(一)概述

    总是觉得HTTP的学习不过就是几页的学习内容罢了,于是就总是没有好好的去学. 我发现我们更愿意通过实例来了解一个东西,不过这里还是添加一下概括的过程吧~ 一个不想看就跳过的概括:输入一个 URL,发生 ...