Dll注入技術之遠程線程注入

轉自:黑客反病毒

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使用較多,不易實現。但是可以批量注入和卸載,這樣對於需要反覆調試的注入就非常的方便。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章