DLL注入技术之远线程注入

来源:互联网 发布:南昌大学怎么样知乎 编辑:程序博客网 时间:2024/05/21 17:10
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关闭句柄
    主要代码如下:

int CRemoteThreadInjectDLL::InjectDll(DWORD dwProcessId, PTCHAR szDllName){    if (szDllName[0] == NULL)        return -1;    //提高权限相关操作    EnablePrivilege(TRUE);    //1. 打开进程    HANDLE hProcess = ::OpenProcess(  PROCESS_ALL_ACCESS,   //打开进程权限        FALSE,                                              //是否可继承         dwProcessId);                                       //进程ID    if (hProcess == INVALID_HANDLE_VALUE)        return -1;    //2. 在远程进程中申请空间    LPVOID pszDllName = ::VirtualAllocEx(hProcess, //远程进程句柄        NULL,                                  //建议开始地址        4096,                                  //分配空间大小        MEM_COMMIT,                            //空间初始化全0        PAGE_EXECUTE_READWRITE);               //空间权限    if (NULL == pszDllName)    {        return -1;    }    //3. 向远程进程中写入数据    BOOL bRet = ::WriteProcessMemory( hProcess, pszDllName,         szDllName, MAX_PATH, NULL);    if (NULL == bRet)    {        return -1;    }    //4. 在远程进程中创建远程线程    m_hInjecthread = ::CreateRemoteThread(hProcess,      //远程进程句柄        NULL,                                            //安全属性        0,                                               //栈大小        (LPTHREAD_START_ROUTINE)LoadLibrary,             //进程处理函数            pszDllName,                                      //传入参数        NULL,                                            //默认创建后的状态        NULL);                                           //线程ID    if (NULL == m_hInjecthread)    {        DWORD dwErr = GetLastError();        return -1;    }    //5. 等待线程结束返回    DWORD dw = WaitForSingleObject(m_hInjecthread, -1);    //6. 获取线程退出码,即LoadLibrary的返回值,即dll的首地址    DWORD dwExitCode;    GetExitCodeThread(m_hInjecthread, &dwExitCode);    m_hMod = (HMODULE)dwExitCode;    //7. 释放空间    BOOL bReturn = VirtualFreeEx(hProcess, pszDllName,         4096, MEM_DECOMMIT);    if (NULL == bReturn)    {        return -1;    }    CloseHandle(hProcess);    hProcess = NULL;    //恢复权限相关操作    EnablePrivilege(FALSE);    return 0;}

此外,我们还需要提升进程权限以便于提高注入成功率,所需API如下表所示:
OpenProcessToken得到令牌句柄LookupPrivilegeValue得到权限值AdjustTokenPrivileges提升令牌句柄权限
int CRemoteThreadInjectDLL::EnablePrivilege(bool isStart){            //1. 得到令牌句柄    HANDLE  hToken = NULL;      //令牌句柄      if (!OpenProcessToken( GetCurrentProcess(),         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ,         &hToken))    {           return FALSE;    }    //2. 得到特权值    LUID    luid = {0};         //特权值    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))    {        return FALSE;    }    //3. 提升令牌句柄权限    TOKEN_PRIVILEGES tp = {0};  //令牌新权限    tp.PrivilegeCount = 1;     tp.Privileges[0].Luid = luid;    tp.Privileges[0].Attributes = isStart ? SE_PRIVILEGE_ENABLED : 0;    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))    {        return FALSE;    }    //4. 关闭令牌句柄    CloseHandle(hToken);    return 0;}

当要在指定的进程中加载DLL时,我们就需要过滤指定名称的进程,这时遍历进程ID并进行对比,得到所指定的进程,所需API如表所示:CreateToolhelp32Snapshot  创建进程快照  Process32First  第一个进程快照Process32Next  循环下一个进程快照  
DWORD CRemoteThreadInjectDLL::GetProcessId(PTCHAR pszProcessName){    HANDLE hProcess = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    if (INVALID_HANDLE_VALUE == hProcess)    {        return 0;    }    DWORD dwProcessId = 0;    PROCESSENTRY32 process32 = {0};    process32.dwSize = sizeof(PROCESSENTRY32);    BOOL bRetProcess = FALSE;    bRetProcess = ::Process32First(hProcess, &process32);    do    {        if (_tcscmp(pszProcessName, process32.szExeFile) == 0)        {            dwProcessId = process32.th32ProcessID;            break;        }        bRetProcess = ::Process32Next(hProcess, &process32);    }while (bRetProcess);    ::CloseHandle(hProcess);    return dwProcessId;}

远线程注入API使用较多,不易实现。但是可以批量注入和卸载,这样对于需要反复调试的注入就非常的方便。

0 0