APC注入(Ring3)
首先简单介绍一下APC队列和Alertable.
看看MSDN上的一段介绍(https://msdn.microsoft.com/en-us/library/ms810047.aspx):
The system delivers most user-mode APCs when a thread unwinds from kernel mode back to user mode after an alertable wait. User-mode APCs do not interrupt user-mode code. After an application queues a user-mode APC to a thread, the application can cause the system to deliver the APCs by calling a wait function with the Alertable parameter set to TRUE. (The user-mode terminate APC is an exception. This APC is queued to terminate a thread, and the system delivers it whenever the thread unwinds back to user mode from kernel mode, not only after an alertable wait.)
上述写道,正常情况下,用户模式的APC是不会打断用户态程序的执行流的。除非,线程是Alertable——可唤醒的。
所以存在的一个麻烦就是,我想要注入的对方进程,哪个线程是Alertable的状态,所以采取了一种暴力的方式——向目标进程的所有线程的UserMode Apc队列(线程有两个Apc队列:Kernel和User)上插入Apc对象。
代码流程:
1.提权(EnableSeDebugPrivilege)
(1)获得令牌token,OpenThreadToken(),OpenProcessToken ()
WINADVAPI
BOOL
WINAPI
OpenThreadToken(
_In_ HANDLE ThreadHandle,
_In_ DWORD DesiredAccess,
_In_ BOOL OpenAsSelf,
_Outptr_ PHANDLE TokenHandle
);
OpenAsSelf参数
[in] true 指定应使用调用线程的进程安全上下文执行访问检查;
false 指定应使用调用线程本身的安全上下文执行访问检查。
如果线程正在模拟客户端,则此安全上下文可以是一个客户端进程的安全上下文。
WINADVAPI
BOOL
WINAPI
OpenProcessToken(
_In_ HANDLE ProcessHandle,
_In_ DWORD DesiredAccess,
_Outptr_ PHANDLE TokenHandle
);
(2)将提升的权限放到TokenPrivileges结构中
WINADVAPI
BOOL
WINAPI
AdjustTokenPrivileges(
_In_ HANDLE TokenHandle,
_In_ BOOL DisableAllPrivileges, 标志这个函数是否禁用该令牌的所有特权.如果为TRUE,这个函数禁用所有特权,NewState参数无效.
如果为假,以NewState参数指针的信息为基础来修改特权.
_In_opt_ PTOKEN_PRIVILEGES NewState,
_In_ DWORD BufferLength,
_Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState,
_Out_opt_ PDWORD ReturnLength
);
(3)将获取的令牌TokenHandle与TokenPrivileges结构关联
2.通过进程ImageName获取进程ID(GetProcessIDByProcessImageName)
(1)给系统的所有进程快照ProcessSnapshotHandle
函数原型:
HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等
DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取 当前进程快照时可以设为0
);
指定快照中包含的系统内容,dwFlags这个参数能够使用下列数值(常量)中的一个或多个。
TH32CS_INHERIT - 声明快照句柄是可继承的。
TH32CS_SNAPALL - 在快照中包含系统中所有的进程和线程。
TH32CS_SNAPHEAPLIST - 在快照中包含在th32ProcessID中指定的进程的所有的堆。
TH32CS_SNAPMODULE - 在快照中包含在th32ProcessID中指定的进程的所有的模块。
TH32CS_SNAPPROCESS - 在快照中包含系统中所有的进程。
TH32CS_SNAPTHREAD - 在快照中包含系统中所有的线程。
#define TH32CS_SNAPHEAPLIST 0x00000001
#define TH32CS_SNAPPROCESS 0x00000002
#define TH32CS_SNAPTHREAD 0x00000004
#define TH32CS_SNAPMODULE 0x00000008
#define TH32CS_SNAPMODULE32 0x00000010
#define TH32CS_SNAPALL (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
#define TH32CS_INHERIT 0x80000000
(2)通过PROCESSENTRY32结构得到ProcessID
PROCESSENTRY32,用来存放快照进程信息的一个结构体。(存放进程信息和调用成员输出进程信息)
用来 Process32First指向第一个进程信息,并将进程信息抽取到PROCESSENTRY32中。
用Process32Next指向下一条进程信息。
typedef struct tagPROCESSENTRY32
{
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID; // this process
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID; // associated exe
DWORD cntThreads;
DWORD th32ParentProcessID; // this process's parent process
LONG pcPriClassBase; // Base priority of process's threads
DWORD dwFlags;
CHAR szExeFile[MAX_PATH]; // Path
} PROCESSENTRY32;
process32First,Process32Next是两个个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后,
我们可以利用process32First函数来获得第一个进程的句柄,利用Process32Next函数来获得下一个进程的句柄。
3.通过进程ID获取线程ID
4.注入
(1)在对方进程空间申请内存,
LPVOID
WINAPI
VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
flAllocationType参数设置:MEM_COMMIT | MEM_RESERVE
(如果物理内存申请失败,将保留进程的虚拟地址空间,到真正执行时,会触发异常,进行物理内存分配)
MEM_COMMIT:为特定的页面区域分配内存中或磁盘的页面文件中的物理存储
MEM_RESERVE:保留进程的虚拟地址空间,而不分配任何物理存储。保留页面可通过继续调用VirtualAlloc()而被占用
(2)将DllFullPath写入内存当中
WriteProcessMemory()函数能写入某一进程的内存区域。入口区必须可以访问,否则操作将失败。
BOOL
WINAPI
WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_reads_bytes_(nSize) LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_opt_ SIZE_T * lpNumberOfBytesWritten
);
(3)加载dll文件
LoadLibraryWAddress = (UINT_PTR)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
// QueryUserAPC.cpp : 定义控制台应用程序的入口点。
// #include "QueryUserAPC.h" int main()
{
if (EnableSeDebugPrivilege(L"SeDebugPrivilege", TRUE) == FALSE)
{
return 0;
}
SeQueueUserAPC(L"explorer.exe", L"Dll.dll");
return 0;
}
BOOL EnableSeDebugPrivilege(IN const WCHAR* PriviledgeName, BOOL IsEnable)
{
HANDLE ProcessHandle = GetCurrentProcess();
HANDLE TokenHandle = NULL;
TOKEN_PRIVILEGES TokenPrivileges = { 0 };
if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
{
return FALSE;
}
LUID v1;
if (!LookupPrivilegeValue(NULL, PriviledgeName, &v1))
{
CloseHandle(TokenHandle);
TokenHandle = NULL;
return FALSE;
} TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = IsEnable == TRUE ? SE_PRIVILEGE_ENABLED : 0;
TokenPrivileges.Privileges[0].Luid = v1;
if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges,
sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
printf("%d\r\n", GetLastError());
CloseHandle(TokenHandle);
TokenHandle = NULL;
return FALSE;
}
CloseHandle(TokenHandle);
TokenHandle = NULL;
return TRUE;
}
BOOL SeQueueUserAPC(WCHAR* ProcessImageName, WCHAR* DllNameData)
{
TCHAR DllFullPathData[MAX_PATH];
GetFullPathName(DllNameData, MAX_PATH, DllFullPathData, NULL); DWORD ProcessID{};
vector<DWORD> ThreadID{}; if (!SeEnumProcessThreadIDByToolhelp32(ProcessImageName, ProcessID, ThreadID))
{
return FALSE;
} auto ProcessHandle = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, ProcessID);
if (!ProcessHandle)
{
printf("OpenProcess() Error\r\n");
return FALSE;
} auto RemoteBufferLength = 0x2000;
auto RemoteBufferData = VirtualAllocEx(ProcessHandle,
NULL,
RemoteBufferLength,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!WriteProcessMemory(ProcessHandle, RemoteBufferData, DllFullPathData, sizeof(DllFullPathData), NULL))
{ printf("WriteProcessMemory() Error\r\n");
VirtualFreeEx(ProcessHandle, RemoteBufferData, RemoteBufferLength, MEM_RELEASE);
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
} /* for (const auto &v1 : ThreadID) //Win7 崩溃
{
auto ThreadHandle = OpenThread(THREAD_SET_CONTEXT, FALSE, v1);
if (ThreadHandle)
{ //向目标进程中的各个线程的APC队列插入执行体
QueueUserAPC(
(PAPCFUNC)GetProcAddress(
GetModuleHandle(L"kernel32"),
"LoadLibraryW"),
ThreadHandle,
(ULONG_PTR)RemoteBufferData); CloseHandle(ThreadHandle);
}
}*/ int i = 0;
for (int i=ThreadID.size()-1;i>=0;i--) //Win10 Win7 通用
{
auto ThreadHandle = OpenThread(THREAD_SET_CONTEXT, FALSE, ThreadID[i]);
if (ThreadHandle)
{ //向目标进程中的各个线程的APC队列插入执行体
QueueUserAPC(
(PAPCFUNC)GetProcAddress(
GetModuleHandle(L"kernel32"),
"LoadLibraryW"),
ThreadHandle,
(ULONG_PTR)RemoteBufferData); CloseHandle(ThreadHandle);
}
}
CloseHandle(ProcessHandle);
return TRUE;
}
BOOL SeEnumProcessThreadIDByToolhelp32(PCWSTR ProcessImageName, DWORD& ProcessID, vector<DWORD>& ThreadID)
{
auto SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
if (SnapshotHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
ProcessID = 0; PROCESSENTRY32 ProcessEntry32 = { sizeof(ProcessEntry32) };
if (::Process32First(SnapshotHandle, &ProcessEntry32))
{
do {
if (_wcsicmp(ProcessEntry32.szExeFile, ProcessImageName) == 0)
{
ProcessID = ProcessEntry32.th32ProcessID;
THREADENTRY32 ThreadEntry32 = { sizeof(ThreadEntry32) };
if (Thread32First(SnapshotHandle, &ThreadEntry32)) {
do {
if (ThreadEntry32.th32OwnerProcessID == ProcessID) {
ThreadID.push_back(ThreadEntry32.th32ThreadID);
}
} while (Thread32Next(SnapshotHandle, &ThreadEntry32));
}
break;
}
} while (Process32Next(SnapshotHandle, &ProcessEntry32));
} CloseHandle(SnapshotHandle);
return ProcessID > 0 && !ThreadID.empty();
}
APC注入(Ring3)的更多相关文章
- Dll注入:Ring3 层 APC注入
APC,即Asynchronous procedure call,异步程序调用APC注入的原理是:在一个进程中,当一个执行到SleepEx()或者WaitForSingleObjectEx()时,系统 ...
- 分析恶意驱动(进程启动apc注入dll)
一.前言 用IDA也有好些时间了,以前就只会用F5功能玩无壳无保护的裸驱动,感觉太坑了,这两天就开始看网上大牛的逆向. 今天记录一下sudami曾经逆向过的fuck.sys.第一遍自己走的时候漏掉了 ...
- APC注入
0X01 注入原理 当线程被唤醒时APC中的注册函数会被执行的机制,并依此去调用我们的DLL加载代码,进而完成注入的目的 具体的流程: 1 当EXE里的某个线程执行到sleepEX(),或者waitF ...
- 常见注入手法第二讲,APC注入
常见注入手法第二讲,APC注入 转载注明出处 首先,我们要了解下什么是APC APC 是一个简称,具体名字叫做异步过程调用,我们看下MSDN中的解释,异步过程调用,属于是同步对象中的函数,所以去同步对 ...
- 注入理解之APC注入
近期学习做了一个各种注入的MFC程序,把一些心得和体会每天分享一些 APC(Asynchronous procedure call)异步程序调用,在NT中,有两种类型的APCs:用户模式和内核模式.用 ...
- Dll注入技术之APC注入
APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下: 1)当EXE里某个线程执行到SleepEx( ...
- windows:shellcode 代码远程APC注入和加载
https://www.cnblogs.com/theseventhson/p/13197776.html 上一章介绍了通用的shellcode加载器,这个加载器自己调用virtualAlloc分配 ...
- DLL注入-APC注入
APC注入 APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下: 1)当EXE里某个线程执行到Sl ...
- 注入 - Ring3 APC注入
系统产生一个软中断,当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数,利用QueueUserAPC()这个API,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的, 1.根据进 ...
随机推荐
- The MySQL Server
mysqld is the MySQL server. configuring the server. The mysql server, mysqld,has many command option ...
- LeetCode--003--无重复字符的最长子串
问题描述: 给定一个字符串,找出不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc" ...
- 20171205xlVBA往返航班组合
'ClassPlan Public Org As String Public Des As String Public FlyNo As String Public StartDate As Vari ...
- 20170912xlVBA批量导入txt文件
Public Sub BatchImportTextFiles() AppSettings 'On Error GoTo ErrHandler Dim StartTime, UsedTime As V ...
- You Don't Know JS: Scope & Closures (第3章: 函数 vs 块作用域)
第二章,作用域由一系列的bubbles组成.每一个都代表了一个container或bucket,装着被声明的identifiers(variables, functions).这些bubbles相互嵌 ...
- apiCloud 选择图片,选择视频,压缩图片
选择视频或图片,只需要一个 UIMediaScanner 模板就可以实现,点击链接查看api https://docs.apicloud.com/Client-API/UI-Layout/UIMedi ...
- 完整的Django入门指南学习笔记4
前言 这一章节将会全面介绍 Django 的身份认证系统,我们将实现注册.登录.注销.密码重置和密码修改的整套流程. 同时你还会了解到如何保护某些试图以防未授权的用户访问,以及如何访问已登录用户的个人 ...
- Linux中磁盘分区——理论篇
Linux中磁盘分区——理论篇 现在主流的分区的方式有两种——MBR分区和GPT分区,本文将着重介绍MBR分区底层原理,及用相关命令验证相关原理 Linux中磁盘分区理论篇 为什么要对磁盘进行分区 M ...
- 向java高级工程师和项目经理的道路进发【转】
转自https://www.cnblogs.com/ahudyan-forever/p/5263296.html 宏观 一. JAVA.要想成为JAVA(高级)工程师肯定要学习JAVA.一般的程序员或 ...
- oracle数据库中字符乱码
1.1 88.152 os已安装中文包,以下确认os层面中文是否可以显示 1.2 88.153 os没有安装中文包,以下确认os层面中文无法显示 1.3 ...