2017-03-04 28 views
1

考慮這個代碼中,我故意導致訪問衝突:如果在任何時候發生異常,EFLAGS如何被信任,從而破壞EFLAGS?

#include <Windows.h> 

int main(int argc, char** argv) 
{ 
    __try 
    { 
     *((unsigned char*)0) = 0; 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     __asm int 3; 
    } 

    return 0; 
} 

在的非法訪問的指令,EFLAGS0x282(之前執行它)。當我單打步驟時,它變爲0x10382。然後我再一步將異常傳遞給應用程序。異常處理程序處理異常並返回到正常的執行流程。但是,這次EFLAGS已更改爲0x244。其他一些寄存器也被改變了。

如果潛在的任何指令,可能會出現異常時,編譯器如何可在EFLAGS用途及其他寄存器所以一定時,一個異常被處理之後,EFLAGS和可能的其它寄存器可包含比現有的不同值到什麼時候發生異常?這將會破壞其後的每個分支決策。

回答

2

你的問題是基於不正確的前提下,即,

異常處理程序處理該異常並返回到正常的執行流程。

可以要麼運行異常處理程序返回到正常的執行流程,但不可能兼顧。在您的發佈代碼的情況下,控制流程從__except塊到return語句,它不會重新輸入__try塊。

編譯器(無法知道是否會觸發異常)將始終生成可以在任何情況下工作的代碼。

如果你想真正看到這種情況發生在調試器,你需要生成一個可從持續異常的一些代碼:

#include <Windows.h> 
#include <stdio.h> 

static char * ptr; 

int filter(void) 
{ 
    __asm int 3; // breakpoint A 
    if (VirtualAlloc(ptr, 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE) == NULL) 
    { 
     return EXCEPTION_EXECUTE_HANDLER; 
    } 
    else 
    { 
     return EXCEPTION_CONTINUE_EXECUTION; 
    } 
} 

int main(int argc, char** argv) 
{ 
    ptr = (char *)VirtualAlloc(NULL, 1, MEM_RESERVE, PAGE_EXECUTE_READWRITE); 

    __try 
    { 
     __asm int 3; // breakpoint B 
     *ptr = 0; 
     __asm int 3; // breakpoint C 
     printf("Hi\n"); 
    } 
    __except (filter()) 
    { 
     printf("Oops\n"); 
    } 

    return 0; 
} 

這一計劃將首先擊中斷點B.你可能想利用截圖或記錄寄存器值。

enter image description here

由於存儲器塊被保留但未提交,試圖寫入它將導致拋出異常;這將調用filter()並命中斷點A.各種標誌和寄存器已經更改,並且隨着filter()的運行,更多標誌和寄存器會發生更改,但是一旦控制流返回到發生異常的位置,即斷點C被擊中時,您會發現所有原始寄存器值已經恢復:

enter image description here

這是可能的,因爲內核存儲程序上下文中發生異常。

另請參閱GetExceptionInformation,它允許篩選表達式確定關於異常的信息,包括在引發異常時保存的寄存器值。

相關問題