Dll注入技术之远程线程注入

偶尔善良 提交于 2020-02-26 13:22:50

DLL注入技术之远线程注入

    DLL注入技术指的是将一个DLL文件强行加载到EXE文件中,并成为EXE文件中的一部分,这样做的目的在于方便我们通过这个DLL读写EXE文件内存数据,(例如 HOOK EXE文件中的API),或以被注入EXE的身份去执行一些操作等等。
    远线程注入原理是利用Windows 系统中CreateRemoteThread()这个API,其中第4个参数是准备运行的线程,我们可以将LoadLibrary()填入其中,这样就可以执行远程进程中的LoadLibrary()函数,进而将我们自己准备的DLL加载到远程进程空间中执行。
    当然除了CreateRemoteThread()和LoadLibrary()这个两个主要的API还是远远不够的,我们还需要以下表格所示的API:
OpenProcess 打开远程进程
VirtualAllocEx 在远程进程中申请空间
WriteProcessMemory 在远程进程中写入数据
WaitForSingleObject 等待信号量
VirtualFreeEx 释放远程进程中申请空间
CloseHandle 关闭句柄

    主要代码如下:

  1. int CRemoteThreadInjectDLL::InjectDll(DWORD dwProcessId, PTCHAR szDllName)  
  2. {  
  3.     if (szDllName[0] == NULL)  
  4.         return -1;  
  5.     //提高权限相关操作  
  6.     EnablePrivilege(TRUE);  
  7.     //1. 打开进程  
  8.     HANDLE hProcess = ::OpenProcess(  PROCESS_ALL_ACCESS,   //打开进程权限  
  9.         FALSE,                                              //是否可继承   
  10.         dwProcessId);                                       //进程ID  
  11.   
  12.     if (hProcess == INVALID_HANDLE_VALUE)  
  13.         return -1;  
  14.   
  15.     //2. 在远程进程中申请空间  
  16.     LPVOID pszDllName = ::VirtualAllocEx(hProcess, //远程进程句柄  
  17.         NULL,                                  //建议开始地址  
  18.         4096,                                  //分配空间大小  
  19.         MEM_COMMIT,                            //空间初始化全0  
  20.         PAGE_EXECUTE_READWRITE);               //空间权限  
  21.   
  22.     if (NULL == pszDllName)  
  23.     {  
  24.         return -1;  
  25.     }  
  26.   
  27.     //3. 向远程进程中写入数据  
  28.     BOOL bRet = ::WriteProcessMemory( hProcess, pszDllName,   
  29.         szDllName, MAX_PATH, NULL);  
  30.   
  31.     if (NULL == bRet)  
  32.     {  
  33.         return -1;  
  34.     }  
  35.   
  36.     //4. 在远程进程中创建远程线程  
  37.     m_hInjecthread = ::CreateRemoteThread(hProcess,      //远程进程句柄  
  38.         NULL,                                            //安全属性  
  39.         0,                                               //栈大小  
  40.         (LPTHREAD_START_ROUTINE)LoadLibrary,             //进程处理函数      
  41.         pszDllName,                                      //传入参数  
  42.         NULL,                                            //默认创建后的状态  
  43.         NULL);                                           //线程ID  
  44.   
  45.     if (NULL == m_hInjecthread)  
  46.     {  
  47.         DWORD dwErr = GetLastError();  
  48.         return -1;  
  49.     }  
  50.   
  51.     //5. 等待线程结束返回  
  52.     DWORD dw = WaitForSingleObject(m_hInjecthread, -1);  
  53.     //6. 获取线程退出码,即LoadLibrary的返回值,即dll的首地址  
  54.     DWORD dwExitCode;  
  55.     GetExitCodeThread(m_hInjecthread, &dwExitCode);  
  56.     m_hMod = (HMODULE)dwExitCode;  
  57.   
  58.     //7. 释放空间  
  59.     BOOL bReturn = VirtualFreeEx(hProcess, pszDllName,   
  60.         4096, MEM_DECOMMIT);  
  61.   
  62.     if (NULL == bReturn)  
  63.     {  
  64.         return -1;  
  65.     }  
  66.   
  67.     CloseHandle(hProcess);  
  68.     hProcess = NULL;  
  69.     //恢复权限相关操作  
  70.     EnablePrivilege(FALSE);  
  71.   
  72.     return 0;  
  73. }  

此外,我们还需要提升进程权限以便于提高注入成功率,所需API如下表所示:
OpenProcessToken 得到令牌句柄
LookupPrivilegeValue 得到权限值
AdjustTokenPrivileges 提升令牌句柄权限
  1. int CRemoteThreadInjectDLL::EnablePrivilege(bool isStart)  
  2. {          
  3.     //1. 得到令牌句柄  
  4.     HANDLE  hToken = NULL;      //令牌句柄    
  5.     if (!OpenProcessToken( GetCurrentProcess(),   
  6.         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ,   
  7.         &hToken))  
  8.     {     
  9.         return FALSE;  
  10.     }  
  11.   
  12.     //2. 得到特权值  
  13.     LUID    luid = {0};         //特权值  
  14.     if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))  
  15.     {  
  16.         return FALSE;  
  17.     }  
  18.     //3. 提升令牌句柄权限  
  19.     TOKEN_PRIVILEGES tp = {0};  //令牌新权限  
  20.     tp.PrivilegeCount = 1;   
  21.     tp.Privileges[0].Luid = luid;  
  22.     tp.Privileges[0].Attributes = isStart ? SE_PRIVILEGE_ENABLED : 0;  
  23.     if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))  
  24.     {  
  25.         return FALSE;  
  26.     }  
  27.     //4. 关闭令牌句柄  
  28.     CloseHandle(hToken);  
  29.     return 0;  
  30. }  

当要在指定的进程中加载DLL时,我们就需要过滤指定名称的进程,这时遍历进程ID并进行对比,得到所指定的进程,所需API如表所示:
CreateToolhelp32Snapshot   创建进程快照  
Process32First   第一个进程快照
Process32Next   循环下一个进程快照  
  1. DWORD CRemoteThreadInjectDLL::GetProcessId(PTCHAR pszProcessName)  
  2. {  
  3.     HANDLE hProcess = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  
  4.   
  5.     if (INVALID_HANDLE_VALUE == hProcess)  
  6.     {  
  7.         return 0;  
  8.     }  
  9.   
  10.     DWORD dwProcessId = 0;  
  11.   
  12.     PROCESSENTRY32 process32 = {0};  
  13.     process32.dwSize = sizeof(PROCESSENTRY32);  
  14.   
  15.     BOOL bRetProcess = FALSE;  
  16.     bRetProcess = ::Process32First(hProcess, &process32);  
  17.   
  18.     do  
  19.     {  
  20.         if (_tcscmp(pszProcessName, process32.szExeFile) == 0)  
  21.         {  
  22.             dwProcessId = process32.th32ProcessID;  
  23.             break;  
  24.         }  
  25.   
  26.         bRetProcess = ::Process32Next(hProcess, &process32);  
  27.     }while (bRetProcess);  
  28.     ::CloseHandle(hProcess);  
  29.   
  30.     return dwProcessId;  
  31. }  

远线程注入API使用较多,不易实现。但是可以批量注入和卸载,这样对于需要反复调试的注入就非常的方便。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!