0X01 注入原理

当线程被唤醒时APC中的注册函数会被执行的机制,并依此去调用我们的DLL加载代码,进而完成注入的目的

具体的流程:

1 当EXE里的某个线程执行到sleepEX(),或者waitForSingleObjectEX()(其实还有WaitForMultipleObjectsEx

 , SignalObjectAndWait,MsgWaitForMultipleObjectsEx)这几个函数时,会产生一个软中断。

2 当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。

3.利用QueueUserAPC()这个API可以在软中断的时间内插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的

0x02代码实现

在注入的操作准备前需要提升权限,使我们有足够的权限去对相应的函数进行操作。

  三步。

1先OpenProcessToken()打开令牌,

2然后LookupPrivilegeValue()

3AdjustTokenPrivileges()调整令牌权限,提取完毕进行注入

注入:

1先要根据进程ID,开启我们的远程注入线程。

2开启完毕后,需要进行相应的内存的空间申请VirtualAllocEx(ProcessHandle, NULL, (wcslen(wzDllFullPath) + 1) * sizeof(WCHAR), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

拥有自己的空间后就可以根据路径写入待注入的DLL路径。

3 用WriteProcessMemory()函数

4 再根据GetProcAddress(GetModuleHandleA("ntdll.dll"), "LdrLoadDll");   //LadrloadDll得到我们LoadLirbrary()地址

5 最后调用sleepEx()函数,利用QueueUserApc()函数对APC队列进行操作,完成注入。这里是因为sleepEx可以触发这个函数

完整代码如下:

// LoadExe.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <Windows.h>
#include <iostream> using namespace std;
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING; typedef struct _INJECT_STRUCT {
UINT_PTR LdrLoadDllAddress; //
UNICODE_STRING DllFullPath; //4,4
HANDLE OutHandle;
} INJECT_STRUCT, *PINJECT_STRUCT;
UINT32 MakeShellCode(UINT8* ShellCodeData, PVOID Address); BOOL InjectByAPC(int ProcessID, int ThreadID, const char *szDllFullPath);
int GrantDebugPrivileges();
//analyzer.py ---> Start(LoadExeFullPath,Inject,ProcessID,ThreadID,DllPath) LoadExe()
//APC 注入
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ int ProcessID = ;
int ThreadID = ; if (__argc < )
{
return -;
}
if (!strcmp(__argv[], "Inject"))
{ GrantDebugPrivileges();
ProcessID = atoi(__argv[]);
ThreadID = atoi(__argv[]);
return InjectByAPC(ProcessID, ThreadID, __argv[]);
}
return ;
} //Target,exe
BOOL InjectByAPC(int ProcessID, int ThreadID, const char *szDllFullPath)
{
HANDLE ProcessHandle = NULL;
HANDLE ThreadHandle = NULL;
if (ProcessID <= || ThreadID < )
{
return FALSE;
}
printf("Success\r\n");
ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID); //
if (ProcessHandle == NULL)
{ return FALSE;
} if (ThreadID > ) {
ThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadID);
if (ThreadHandle == NULL)
{
CloseHandle(ProcessHandle);
return FALSE;
}
} //malloc virtualalloc globalalloc heapalloc new malloc //注入都要在目标进程空间中申请内存 写入Dll的绝对路径
UINT32 DllPathLength = ;
DllPathLength = (UINT32)strlen(szDllFullPath);
WCHAR* wzDllFullPath = (WCHAR*)calloc(, (DllPathLength + ) * sizeof(WCHAR)); //在LoadEx进程空间中
if (wzDllFullPath == NULL)
{ return FALSE;
}
for (int i=;i<DllPathLength;i++)
{
wzDllFullPath[i] = (UINT16)szDllFullPath[i];
} //单字转换双字 WCHAR* wzDllFullPathData = (WCHAR*)VirtualAllocEx(ProcessHandle, NULL, (wcslen(wzDllFullPath) + ) * sizeof(WCHAR), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (wzDllFullPathData == NULL)
{
free(wzDllFullPath);
wzDllFullPath = NULL; return FALSE;
}
SIZE_T ReturnSize = ;
if (!WriteProcessMemory(ProcessHandle, wzDllFullPathData, wzDllFullPath, (wcslen(wzDllFullPath) + ) * sizeof(WCHAR), &ReturnSize))
{ free(wzDllFullPath);
wzDllFullPath = NULL; return FALSE;
}
LPVOID LdrLoadDll;
LdrLoadDll = GetProcAddress(GetModuleHandleA("ntdll.dll"), "LdrLoadDll"); //LadrloadDll INJECT_STRUCT InjectStruct = {}; InjectStruct.LdrLoadDllAddress = (UINT_PTR)LdrLoadDll;
InjectStruct.DllFullPath.Buffer = wzDllFullPathData;
InjectStruct.DllFullPath.Length = InjectStruct.DllFullPath.MaximumLength = (USHORT)(wcslen(wzDllFullPath) * sizeof(WCHAR)); PINJECT_STRUCT InjectStructData = NULL;
InjectStructData = (PINJECT_STRUCT)VirtualAllocEx(ProcessHandle, NULL, sizeof(INJECT_STRUCT), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (InjectStructData == NULL)
{
free(wzDllFullPath);
wzDllFullPath = NULL; return FALSE;
} if (!WriteProcessMemory(ProcessHandle, InjectStructData, &InjectStruct, sizeof(INJECT_STRUCT), &ReturnSize))
{
free(wzDllFullPath);
wzDllFullPath = NULL; return FALSE;
}
char szShellCode[] = {};
UINT32 ShellCodeSize = MakeShellCode((UINT8*)szShellCode, InjectStructData); CHAR* szShellCodeData = NULL;
szShellCodeData =(CHAR*)VirtualAllocEx(ProcessHandle, NULL, ShellCodeSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (szShellCodeData == NULL)
{
free(wzDllFullPath);
wzDllFullPath = NULL; return FALSE;
} if (!WriteProcessMemory(ProcessHandle, szShellCodeData, szShellCode, ShellCodeSize, &ReturnSize))
{
free(wzDllFullPath);
wzDllFullPath = NULL; return FALSE;
} if (ThreadHandle)
{ if(!QueueUserAPC((PAPCFUNC)szShellCodeData,ThreadHandle, (ULONG_PTR)InjectStructData))
{
free(wzDllFullPath);
wzDllFullPath = NULL;
return FALSE;
} } free(wzDllFullPath);
wzDllFullPath = NULL;
return TRUE;
} int GrantDebugPrivileges()
{
HANDLE TokenHandle = NULL;
TOKEN_PRIVILEGES PrivilegesToken;
LUID v1;
int iRet; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle))
{
return ;
} if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &v1))
{
CloseHandle(TokenHandle);
return ;
}
PrivilegesToken.PrivilegeCount = ;
PrivilegesToken.Privileges[].Luid = v1;
PrivilegesToken.Privileges[].Attributes = SE_PRIVILEGE_ENABLED; iRet = AdjustTokenPrivileges(TokenHandle, FALSE, &PrivilegesToken, sizeof(PrivilegesToken), NULL, NULL);
CloseHandle(TokenHandle); return iRet;
}

APC注入的更多相关文章

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

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

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

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

  3. 注入理解之APC注入

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

  4. Dll注入:Ring3 层 APC注入

    APC,即Asynchronous procedure call,异步程序调用APC注入的原理是:在一个进程中,当一个执行到SleepEx()或者WaitForSingleObjectEx()时,系统 ...

  5. Dll注入技术之APC注入

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

  6. windows:shellcode 代码远程APC注入和加载

    https://www.cnblogs.com/theseventhson/p/13197776.html  上一章介绍了通用的shellcode加载器,这个加载器自己调用virtualAlloc分配 ...

  7. DLL注入-APC注入

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

  8. APC注入(Ring3)

    首先简单介绍一下APC队列和Alertable. 看看MSDN上的一段介绍(https://msdn.microsoft.com/en-us/library/ms810047.aspx): The s ...

  9. 注入 - Ring3 APC注入

    系统产生一个软中断,当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数,利用QueueUserAPC()这个API,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的, 1.根据进 ...

随机推荐

  1. 一种新的隐藏-显示模式诞生——css3的scale(0)到scale(1)

    .dropdown-menu {  background: rgba(255, 255, 255, 0.98) none repeat scroll 0 0;  box-shadow: 0 1px 2 ...

  2. C# new和override的区别

    浅析C# new和override的区别 C#中new和override是继承中经常用到的两个关键字,但是往往有时候容易把这两个关键字的作用搞混淆. new C# new关键字表示隐藏,是指加上new ...

  3. Docker学习计划

    刚开始学习Docker的时候,找资料在网上看到最多的是Docker的好处.比如: 1.Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多 2.Docker 对系统资源的利用率很高, ...

  4. AC日记——统计难题 hdu 1251

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...

  5. 常用的JavaScript字符串处理函数及用法

    最近参加了几次前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等,如果你经常参加笔试或者也是一个过来人,相信你也跟我一样,发现字符串的处理是前端招聘过程中最 ...

  6. 高斯RBF核函数中Sigma取值和SVM分离面的影响

    1:高斯RBF核函数的定义 k(x) = exp(-x^2/(2×sigma)) 在MATLAB中输入一下代码:ezsurf('exp(-x^2/(2*sigma^2))'); 在GOOGLE中输入“ ...

  7. Mybatis增加对象属性不增加mapper.xml的情况

    Mybatis增加对象属性不增加mapper.xml的情况: 只增加Model 对象的属性,在查询语句中返回相同名称的字段,但是在mapper中的 resultMap上面不进行新增字段的增加,查询结果 ...

  8. 在Express中安装XTemplate

    上一节讲了安装Express,并且生成了一个"microblog"的工程,我们的目标是在工程下安装XTemplate: 1.安装xtpl npm install xtpl xtem ...

  9. 二维动态规划——Interleaving String

    97. Interleaving String Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2 ...

  10. 深入React事件系统(React点击空白部分隐藏弹出层;React阻止事件冒泡失效)

    只关注括号内问题的同学,可直接跳转到蓝字部分.(标题起的有点大,其实只讨论一个问题) 两个在React组件上绑定的事件,产生冲突后,使用e.stopPropagation(),阻止冒泡,即可防止事件冲 ...