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. LPC2478的SPI使用

    LPC2478的spi使用 LPC2748具有一个SPI控制器,可以当做SPI主机或者从机使用,有以下特性 其使用起来很方便,并且支持中断,使用的寄存器如下 基本上,使用起来就是设置控制为,CPOL ...

  2. JNI介绍(转)

    源:JNI介绍 JNI是在学习Android HAL时必须要面临一个知识点,如果你不了解它的机制,不了解它的使用方式,你会被本地代码绕的晕头转向,JNI作为一个中间语言的翻译官在运行Java代码的An ...

  3. 【转】C/CPP之static

    静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值. 静态变量或静态函数只有本文件内的代码才能访问它,它的名字在其它文件中不可见.用法1:函数内部声明 ...

  4. 已知从BUF开始存放了10个字类型有符号数据,编程求出这10个数中的最大数和最小数(将最大数存入MAX字单元、最小数存入MIN字单元),并将其以10进制数的形式在屏幕上显示出来。

    data segment            pmax db 0dh,0ah , 'MAX :   ','$'    pmin db 0dh,0ah , 'MIN :   ','$'    buf ...

  5. html 上传文件

    1.html代码 <form id="form1" action="TestYield" method="post" enctype= ...

  6. C语言-表达式

    表达式是使用运算符连接起来的式子,C语言中的表达式有以下几种: 1.算数运算符 + - * / % 2.赋值运算符 +=  -=  *=  /=  %= 3.自增.自减 ++   --   a++为先 ...

  7. cocos2d-x---开篇介绍

    关于cocos2d-x这一游戏引擎,现在受到了手机游戏开发者的青睐.其实cocos2d一开始是由于cocos2d-iphone的成功,然后带动各类开源项目越来越火.由苹果独家的Objective-C到 ...

  8. 编写PHP规则

    PHP是运行在服务器端的语言,可以动态生成html页面.这篇博客介绍它的一些编码规则. 一.基本规则 1.PHP代码总是用<?php和?>包围,例如 <?php echo " ...

  9. python with用法

    python中with可以明显改进代码友好度,比如: with open('a.txt') as f: print f.readlines() 为了我们自己的类也可以使用with, 只要给这个类增加两 ...

  10. 常用SQL DDL语句

    常用SQL DDL语句 DDL-数据库定义语言:直接提交的.CREATE:用于创建数据库对象.DECLARE:除了是创建只在过程中使用的临时表外,DECLARE语句和CREATE语句非常相似.唯一可以 ...