青岛黄岛区网站开发,html网页代码大全的阅读,响应式网站建设费用,交流稿 网站建设Windows DLL 注入技术 本文主要介绍四种常见的 Windows DLL 注入技术。分别为全局钩子、远线程钩子、突破 SESSION 0 隔离的远线程注入和 APC 注入。全局钩子注入Windows 中大部分应用是基于 Windows 的消息机制#xff0c;Windows提供截获这些消息的钩子函数。根据钩子作用的… Windows DLL 注入技术 本文主要介绍四种常见的 Windows DLL 注入技术。分别为全局钩子、远线程钩子、突破 SESSION 0 隔离的远线程注入和 APC 注入。全局钩子注入Windows 中大部分应用是基于 Windows 的消息机制Windows提供截获这些消息的钩子函数。根据钩子作用的不同范围钩子可以被分为全局和局部钩子。局部钩子是针对某个线程的全局钩子是只要有使用消息机制的应用。接下来我们主要来看下利用SetWindowsHookEx实现全局钩子。SetWindowsHookEx函数介绍HHOOK SetWindowsHookEx(int idHook, // 要安装的钩子程序的类型 HOOKPROC lpfn, // 指向钩子函数的指针 HINSTANCE hmod, // 指向钩子过程的DLL的句柄 DWORD dwThreadId // 与钩子进程关联的线程标识符);// 具体详细介绍可以查阅msdn文档里面有更为详细的介绍实现过程首先我们需要创建一个windowsHookDll DLL这个DLL在安装全局钩子后只要系统中的其他进程接收到可以发出钩子的消息这个DLL就会被加载到此进程的地址空间中。这样便实现了Dll注入。具体实现代码如下#include Hook.h#include extern HMODULE g_hDllModule;// 共享内存#pragma data_seg(mydata) HHOOK g_hHook NULL;#pragma data_seg()#pragma comment(linker, /SECTION:mydata,RWS)// 钩子回调函数LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam){ return ::CallNextHookEx(g_hHook, code, wParam, lParam);}// 注册钩子BOOL SetHook(){ g_hHook SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0); //使用WH_GETMESSAGE 确保DLL能够注入所有的进程 if (g_hHook) { return TRUE; } return FALSE;}// 卸载钩子BOOL UnSetHook(){ if (g_hHook) { UnhookWindowsHookEx(g_hHook); } return TRUE;}试验结果新建TestHook.exe程序首先加载windowsHookDll.dll导出函数SetHook并调用。在注册成功后用ProcessExplorer.exe察看explorer.exe中的加载情况。windowsHookDll成功被explorer.exe加载如果想要卸载可调用函数UnSetHook执行完成后再观察explorer.exe是否加载了windowsHookDll.dll。远线程注入远线程注入是指一个进程在另一个进程中创建线程的技术。主要是利用LoadLibrary在所有进程空间中的地址是一样进程在另一个进程中创建线程时传入LoadLibrary的地址和我们要注入的DLL的路径这样在另一个进程中就能通过LoadLibray加载DLL到进程空间中。说起来简单但是实现起来却有几大难点需要注意的。如何将DLL路径传给另一个进程因为进程之间是相互隔离的所以我们要在我们要注入的进程中申请内存。需要对打开的进程进行提权这就要求我们的注入程序要有管理员以上的权限。函数介绍HANDLE OpenProcess( DWORD dwDesiredAccess, // 进程访问权限 BOOL bInheritHandle, // 子进程是否继承此句柄 DWORD dwProcessId // 要打开的进程id);// 分配指定进程的内存LPVOID VirtualAllocEx( HANDLE hProcess, // 进程句柄 LPVOID lpAddress, // 要分配内存起始地址为NULL则自动分配 SIZE_T dwSize, // 要分配的内存大小 DWORD flAllocationType,// 内存分配类型 DWORD flProtect // 内存保护(读写));// 写入内存数据BOOL WriteProcessMemory( HANDLE hProcess, // 进程句柄 LPVOID lpBaseAddress, // 目标进程缓冲区地址 LPCVOID lpBuffer, // 要写入数据的地址 SIZE_T nSize, // 数据大小 SIZE_T *lpNumberOfBytesWritten // 写入数据的返回大小 为NULL则忽略此参数);// 在另一个进程中创建线程HANDLE CreateRemoteThread( HANDLE hProcess, // 进程句柄 LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全描述符 SIZE_T dwStackSize, // 堆栈的初始大小 LPTHREAD_START_ROUTINE lpStartAddress, // 函数地址(存在于另一个进程中) LPVOID lpParameter, // 函数的参数 DWORD dwCreationFlags, // 线程创建标志 LPDWORD lpThreadId // 线程标识符);// 详细信息可参阅msdn代码实现/*dwProcessId: 目标进程的pid**pszDllFileName: 要注入DLL的路径*/BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId, char *pszDllFileName){ HANDLE hProcess NULL; SIZE_T dwSize 0; LPVOID pDllAddr NULL; FARPROC pFuncProcAddr NULL; // 打开注入进程获取进程句柄 hProcess ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL hProcess) { EP_ShowError(OpenProcess); return FALSE; } // 在注入进程中申请内存 dwSize 1 ::lstrlenA(pszDllFileName); pDllAddr ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (NULL pDllAddr) { EP_ShowError(VirtualAllocEx); return FALSE; } // 向申请的内存中写入数据 if (FALSE ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL)) { EP_ShowError(WriteProcessMemory); return FALSE; } // 获取LoadLibraryA函数地址 pFuncProcAddr ::GetProcAddress(::GetModuleHandleA(kernel32.dll), LoadLibraryA); if (NULL pFuncProcAddr) { EP_ShowError(GetProcAddress_LoadLibraryA); return FALSE; } // 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入 HANDLE hRemoteThread ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL); if (NULL hRemoteThread) { EP_ShowError(CreateRemoteThread); return FALSE; } // 关闭句柄 ::CloseHandle(hProcess); return TRUE;}试验结果注入成功后效果图在explorer.exe中RemoteThreadDll.dll被正确加载远线程注册进阶 突破SESSION 0隔离在系统普通进程中可以使用远线程注入DLL,但如果要注入系统服务则不行因为有SESSION 0隔离。想要突破隔离需要使用ZwCreateThreadEx函数。这也是和远线程注入的区别。ZwCreateThreadEx 是未公开的函数在ntdll.dll中它的函数声明如下#ifdef _WIN64 typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, ULONG CreateThreadFlags, SIZE_T ZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, LPVOID pUnkown);#else typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD dwStackSize, DWORD dw1, DWORD dw2, LPVOID pUnkown);#endif具体实现代码// 使用 ZwCreateThreadEx 实现远线程注入BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char *pszDllFileName){ HANDLE hProcess NULL; SIZE_T dwSize 0; LPVOID pDllAddr NULL; FARPROC pFuncProcAddr NULL; HANDLE hRemoteThread NULL; DWORD dwStatus 0; // 打开注入进程获取进程句柄 hProcess ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL hProcess) { EP_ShowError(OpenProcess); return FALSE; } // 在注入进程中申请内存 dwSize 1 ::lstrlenA(pszDllFileName); pDllAddr ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (NULL pDllAddr) { EP_ShowError(VirtualAllocEx); return FALSE; } // 向申请的内存中写入数据 if (FALSE ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL)) { EP_ShowError(WriteProcessMemory); return FALSE; } // 加载 ntdll.dll HMODULE hNtdllDll ::LoadLibraryA(ntdll.dll); if (NULL hNtdllDll) { EP_ShowError(LoadLirbary); return FALSE; } // 获取LoadLibraryA函数地址 pFuncProcAddr ::GetProcAddress(::GetModuleHandleA(Kernel32.dll), LoadLibraryA); if (NULL pFuncProcAddr) { EP_ShowError(GetProcAddress_LoadLibraryA); return FALSE; } // 获取ZwCreateThread函数地址#ifdef _WIN64 typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, ULONG CreateThreadFlags, SIZE_T ZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, LPVOID pUnkown);#else typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD dwStackSize, DWORD dw1, DWORD dw2, LPVOID pUnkown);#endif typedef_ZwCreateThreadEx ZwCreateThreadEx (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, ZwCreateThreadEx); if (NULL ZwCreateThreadEx) { EP_ShowError(GetProcAddress_ZwCreateThread); return FALSE; } // 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入 dwStatus ZwCreateThreadEx(hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL); if (NULL hRemoteThread) { EP_ShowError(ZwCreateThreadEx); return FALSE; } // 关闭句柄 ::CloseHandle(hProcess); ::FreeLibrary(hNtdllDll); return TRUE;}试验结果同远线程注入一致只是在服务程序中不能弹窗。APC注入APC(Asynchronous Procedure Call)为异步过程调用APC注入是指利用线程本身的APC队列进行DLL注入。函数介绍// 将异步调用函数添加到指定线程的APC队列中DWORD QueueUserAPC( PAPCFUNC pfnAPC, // 函数指针 HANDLE hThread, // 线程句柄 ULONG_PTR dwData // 函数参数);// 详细信息可参阅msdn实现原理APC队列中的函数需要等待线程挂起时才会被执行所以要保证我们注入的程序能被执行需要将我们的函数插入到进程的所有线程中。具体代码实现如下// apc.h#include #include // 根据进程名称获取PIDDWORD GetProcessIdByProcessName(char *pszProcessName);// 根据PID获取所有的相应线程IDBOOL GetAllThreadIdByProcessId(DWORD dwProcessId, DWORD **ppThreadId, DWORD *dwThreadIdLength);// APC注入BOOL ApcInjectDll(char *pszProcessName, char *pszDllName);//apc.cpp#include APC.hvoid ShowError(char *pszText){ char szErr[MAX_PATH] { 0 }; ::wsprintf(szErr, %s Error[%d]\n, pszText); ::MessageBox(NULL, szErr, ERROR, MB_OK | MB_ICONERROR);}// 根据进程名称获取PIDDWORD GetProcessIdByProcessName(char *pszProcessName){ DWORD dwProcessId 0; PROCESSENTRY32 pe32 { 0 }; HANDLE hSnapshot NULL; BOOL bRet FALSE; ::RtlZeroMemory(pe32, sizeof(pe32)); pe32.dwSize sizeof(pe32); // 获取进程快照 hSnapshot ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (NULL hSnapshot) { ShowError(CreateToolhelp32Snapshot); return dwProcessId; } // 获取第一条进程快照信息 bRet ::Process32First(hSnapshot, pe32); while (bRet) { // 获取快照信息 if (0 ::lstrcmpi(pe32.szExeFile, pszProcessName)) { dwProcessId pe32.th32ProcessID; break; } // 遍历下一个进程快照信息 bRet ::Process32Next(hSnapshot, pe32); } return dwProcessId;}// 根据PID获取所有的相应线程IDBOOL GetAllThreadIdByProcessId(DWORD dwProcessId, DWORD **ppThreadId, DWORD *pdwThreadIdLength){ DWORD *pThreadId NULL; DWORD dwThreadIdLength 0; DWORD dwBufferLength 1000; THREADENTRY32 te32 { 0 }; HANDLE hSnapshot NULL; BOOL bRet TRUE; do { // 申请内存 pThreadId new DWORD[dwBufferLength]; if (NULL pThreadId) { ShowError(new); bRet FALSE; break; } ::RtlZeroMemory(pThreadId, (dwBufferLength * sizeof(DWORD))); // 获取线程快照 ::RtlZeroMemory(te32, sizeof(te32)); te32.dwSize sizeof(te32); hSnapshot ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (NULL hSnapshot) { ShowError(CreateToolhelp32Snapshot); bRet FALSE; break; } // 获取第一条线程快照信息 bRet ::Thread32First(hSnapshot, te32); while (bRet) { // 获取进程对应的线程ID if (te32.th32OwnerProcessID dwProcessId) { pThreadId[dwThreadIdLength] te32.th32ThreadID; dwThreadIdLength; } // 遍历下一个线程快照信息 bRet ::Thread32Next(hSnapshot, te32); } // 返回 *ppThreadId pThreadId; *pdwThreadIdLength dwThreadIdLength; bRet TRUE; } while (FALSE); if (FALSE bRet) { if (pThreadId) { delete[]pThreadId; pThreadId NULL; } } return bRet;}// APC注入BOOL ApcInjectDll(char *pszProcessName, char *pszDllName){ BOOL bRet FALSE; DWORD dwProcessId 0; DWORD *pThreadId NULL; DWORD dwThreadIdLength 0; HANDLE hProcess NULL, hThread NULL; PVOID pBaseAddress NULL; PVOID pLoadLibraryAFunc NULL; SIZE_T dwRet 0, dwDllPathLen 1 ::lstrlen(pszDllName); DWORD i 0; do { // 根据进程名称获取PID dwProcessId GetProcessIdByProcessName(pszProcessName); if (0 dwProcessId) { bRet FALSE; break; } // 根据PID获取所有的相应线程ID bRet GetAllThreadIdByProcessId(dwProcessId, pThreadId, dwThreadIdLength); if (FALSE bRet) { bRet FALSE; break; } // 打开注入进程 hProcess ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL hProcess) { ShowError(OpenProcess); bRet FALSE; break; } // 在注入进程空间申请内存 pBaseAddress ::VirtualAllocEx(hProcess, NULL, dwDllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (NULL pBaseAddress) { ShowError(VirtualAllocEx); bRet FALSE; break; } // 向申请的空间中写入DLL路径数据 ::WriteProcessMemory(hProcess, pBaseAddress, pszDllName, dwDllPathLen, dwRet); if (dwRet ! dwDllPathLen) { ShowError(WriteProcessMemory); bRet FALSE; break; } // 获取 LoadLibrary 地址 pLoadLibraryAFunc ::GetProcAddress(::GetModuleHandle(kernel32.dll), LoadLibraryA); if (NULL pLoadLibraryAFunc) { ShowError(GetProcessAddress); bRet FALSE; break; } // 遍历线程, 插入APC i dwThreadIdLength; for (; i 0; --i) { // 打开线程 hThread ::OpenThread(THREAD_ALL_ACCESS, FALSE, pThreadId[i]); if (hThread) { // 插入APC ::QueueUserAPC((PAPCFUNC)pLoadLibraryAFunc, hThread, (ULONG_PTR)pBaseAddress); // 关闭线程句柄 ::CloseHandle(hThread); hThread NULL; } } bRet TRUE; } while (FALSE); // 释放内存 if (hProcess) { ::CloseHandle(hProcess); hProcess NULL; } if (pThreadId) { delete[]pThreadId; pThreadId NULL; } return bRet;}总结Windows注入技术可以方便我们对目标进程作修改但是也可能使目标进程崩溃在使用的时候需要小心谨慎。长按图片自动识别~~~关注我哦~~~~- END -