APC注入

原文轉(zhuǎn)自:http://blog.csdn.net/swanabin/article/details/21459243
APC注入的原理是利用當(dāng)線程被喚醒時(shí)APC中的注冊(cè)函數(shù)會(huì)被執(zhí)行的機(jī)制,并以此去執(zhí)行我們的DLL加載代碼,進(jìn)而完成DLL注入的目的,其具體流程如下:
1)當(dāng)EXE里某個(gè)線程執(zhí)行到SleepEx()或者WaitForSingleObjectEx()時(shí),系統(tǒng)就會(huì)產(chǎn)生一個(gè)軟中斷。
2)當(dāng)線程再次被喚醒時(shí),此線程會(huì)首先執(zhí)行APC隊(duì)列中的被注冊(cè)的函數(shù)。
3)利用QueueUserAPC()這個(gè)API可以在軟中斷時(shí)向線程的APC隊(duì)列插入一個(gè)函數(shù)指針,如果我們插入的是Loadlibrary()執(zhí)行函數(shù)的話,就能達(dá)到注入DLL的目的。

1.編寫測(cè)試文件
新建MFC工程,添加按鈕控件,雙擊寫代碼如下所示:
<code>
void CMfcTextApcInjectDlg::OnBnClickedSleepex()
{
// TODO: 在此添加控件通知處理程序代碼
SleepEx(5000,TRUE);
}
</code>
這里我們需要注意一下SleepEx中第二個(gè)參數(shù)為TRUE,查下msdn,上面寫到:
<code>
bAlertable [in]
If this parameter is FALSE, the function does not return until the time-out period has elapsed. If an I/O completion callback occurs, the function does not return and the I/O completion function is not executed. If an APC is queued tothe thread, the function does not return and the APC function is not executed.
</code>
大概意思是說(shuō)當(dāng)?shù)诙€(gè)參數(shù)為FALSE,APC是不被執(zhí)行的,從此可以認(rèn)為APC注入的使用條件還是有很大約束的。
.編寫APC注入程序
由于我們需要時(shí)使用LoadLibrary()函數(shù)完成注入,因此需要為其先準(zhǔn)備好必要的參數(shù),需要我們可以通過(guò)在遠(yuǎn)程進(jìn)程中申請(qǐng)空間的方式寫入LoadLibrary()函數(shù)所需要的參數(shù)(也就是DLL的路徑)。關(guān)鍵代碼如下所示:
<code>
//打開遠(yuǎn)程進(jìn)程
handle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);
if (handle)
{
//在遠(yuǎn)程進(jìn)程申請(qǐng)空間
lpData = VirtualAllocEx(handle,
NULL,
1024,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);

    if (lpData)  
    {  
        //在遠(yuǎn)程進(jìn)程申請(qǐng)空間中寫入待注入DLL的路徑  
        bRet = WriteProcessMemory(handle,  
            lpData,  
            (LPVOID)sDllName,  
            1024,&dwRet);  
    }  
    //關(guān)閉句柄  
    CloseHandle(handle);  

}
</code>
當(dāng)我們準(zhǔn)備好用于注入DLL的LoadLibrary()函數(shù)后,接下來(lái)需要使用QueueUserAPC()函數(shù)將此函數(shù)插入到軟中斷線程的APC隊(duì)列中。但是由于QueueUserAPC()函數(shù)的第三個(gè)參數(shù)是線程ID,因此我們需要根據(jù)現(xiàn)有進(jìn)程ID,并通過(guò)遍歷對(duì)比得到線程ID,具體API如下表所示:
<code>
CreateToolhelp32Snapshot 創(chuàng)建線程快照
Thread32First 得到第一個(gè)線程快照
Thread32Next 循環(huán)下一個(gè)線程快照
關(guān)鍵代碼如下所示:
THREADENTRY32 te = {0};
te.dwSize = sizeof(THREADENTRY32);
//得到線程快照
HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
if (INVALID_HANDLE_VALUE == handleSnap)
{
return FALSE;
}

BOOL bStat = FALSE;  
//得到第一個(gè)線程  
if (Thread32First(handleSnap,&te))  
{  
    do   
    {  
        //進(jìn)行進(jìn)程ID對(duì)比  
        if (te.th32OwnerProcessID == dwProcessId)  
        {  
            //得到線程句柄  
            HANDLE handleThread = OpenThread(  
                THREAD_ALL_ACCESS,  
                FALSE,  
                te.th32ThreadID);  

            if (handleThread)  
            {  
                //向線程插入APC  
                dwRet = QueueUserAPC(  
                    (PAPCFUNC)LoadLibrary,  
                    handleThread,  
                    (ULONG_PTR)lpData);  
                if (dwRet > 0)  
                {  
                    bStat = TRUE;  
                }  
                //關(guān)閉句柄  
                CloseHandle(handleThread);  
            }  
        }  
        //循環(huán)下一個(gè)線程  
    } while (Thread32Next(handleSnap,&te));  
}  

CloseHandle(handleSnap);
</code>
3.MFC工程設(shè)置和提升權(quán)限
經(jīng)過(guò)以上兩步的操作,我們已經(jīng)準(zhǔn)備好APC注入的關(guān)鍵代碼,現(xiàn)在我們需要將自己的程序提升權(quán)限以方便注入操作(另,動(dòng)態(tài)MFC庫(kù)編譯有可能造成注入失?。?。主要代碼如下:
<code>
int CApcInjectDll::EnablePrivilege(bool isStart)
{
//1. 得到令牌句柄
HANDLE hToken = NULL; //令牌句柄
if (!::OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ,
&hToken))
{
return FALSE;
}

//2. 得到特權(quán)值  
LUID    luid = {0};         //特權(quán)值  
if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))  
{  
    return FALSE;  
}  

//3. 提升令牌句柄權(quán)限  
TOKEN_PRIVILEGES tp = {0};  //令牌新權(quán)限  
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. 關(guān)閉令牌句柄  
::CloseHandle(hToken);  
return 0;  

}
</code>
4.測(cè)試注入效果
點(diǎn)擊待注入的EXE進(jìn)行SleepEx,這時(shí)EXE的窗口是不可以移動(dòng)的,因?yàn)橹挥幸粋€(gè)線程,處于SleepEx的掛起狀態(tài),然后進(jìn)行注入,我們此時(shí)會(huì)發(fā)現(xiàn)處于掛起狀態(tài)的進(jìn)程窗口突然可以移動(dòng)了,這是因?yàn)檫M(jìn)程在掛起狀態(tài)等待時(shí),如果有APC隊(duì)列就會(huì)退出等待并執(zhí)行APC隊(duì)列中的函數(shù),然后程序繼續(xù)運(yùn)行。
APC注入因?yàn)槭苣繕?biāo)進(jìn)程使用API的條件而受限,并且處于等待的線程被注入后會(huì)立即返回,也有可能造成線程的運(yùn)行錯(cuò)誤,所以應(yīng)用起來(lái)不是很通用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容