2010-11-22 50 views
3

我目前正在調查一個Windows崩潰轉儲,並在打開轉儲文件時,Visual Studio調試器向我顯示「非法指令0xC000001D」。它示出該錯誤的代碼位置示出了沿着以下示例的拆解:是否可以在Windows XP下用普通的C++程序覆蓋代碼段?

void g(int x) { 
00401E80 push  ebp 
00401E81 mov   ebp,esp 
    if(x > 20) { 
00401E83 cmp   dword ptr [x],14h 
00401E87 jle   g+14h (401E94h) 
     x *= 4; 
>00401E89 db   0fh // illegal instruction here 
00401E8A db   0fh 
00401E8B xadd  eax,esp 
00401E8E add   cl,byte ptr [ecx+9EB0845h] 
     x += 42; 
00401E94 mov   ecx,dword ptr [x] 
... 

我手動通過改寫與在調試程序存儲器窗口一些無效值的功能碼創建在調試器上面的例子,但故障轉儲我調查顯示同樣的db 0fh條目,顯然表明一條無效指令。該代碼也類似於我的轉儲文件顯示的內容,因爲無效指令之前的指令都顯得有效且與源代碼匹配。

現在問題是是否有可能在所有的正常編譯的C++程序 - 圍繞不惹內存頁面的訪問限制 - (在Windows XP中的Visual C++ 2005)弄亂的代碼段處理?

如果我嘗試從代碼中寫入上述示例中的函數地址,我總是得到一個訪問衝突,即代碼段內存頁似乎是寫保護的。

{ 
    void* fnAddr = &g; // non-portable but OK in VC++ 
    unsigned int x = 0xDEADBEEF; 
    // Simulate memory corruption: Try to write something to the code segment: 
    memcpy((char*)fnAddr+4, &x, sizeof(x)); // generated 0xC0000005 Access Violation 
    g(42); // call messed up function - never get here 
} 

您是否知道實際上可能會無意中覆蓋代碼段中某些內容的任何情況?

我應該補充一點,真正的程序很複雜,有很多虛函數,一些成員函數指針等等,這個問題很遺憾不能重現,我們目前只有這個轉儲文件看起來很好除此以外。 - 儘管如此,轉儲文件在代碼段中顯示非法指令,我不會認爲有可能弄亂代碼段。

回答

3

不,包含代碼的內存頁面是寫保護的。這種損壞只能發生在進程初始化時。但更可能的來源是軟RAM錯誤。請您的客戶運行一個RAM測試程序。考慮文件損壞是錯誤是可重複的。

+0

這些文件看起來不錯。內存錯誤似乎不太可能,但我們會測試。也許轉儲文件沒有向我展示我認爲給我看的東西。 – 2010-11-23 07:41:44

0

是的,在部分代碼段已被應用程序寫入的情況下,例如在Java JIT中,Java字節碼即時編譯爲本機代碼。

+1

答案應該從「否」開始,因爲問題是:*是否可以在通常編譯的C++程序中使用 - 不會混淆內存頁訪問限制 - 將進程的代碼段搞亂? * – 2010-11-23 08:04:07

0

默認.text部分有RX訪問權限。但是,使用VirtualProtect您可以獲得這些內存頁面的寫入限制。但是,看看這個..

我想這應該是代碼:

code:00401000 55        push ebp 
code:00401001 89 E5        mov  ebp, esp 
code:00401003 81 7D 08 14 00 00+    cmp  dword ptr [ebp+8], 14h 
code:0040100A 7E 0B        jle  short loc_401017 
code:0040100A     ; --------------------------------------------------------------------------- 
code:0040100C 0F        db 0Fh // here should be x += 10.5; ?? 
code:0040100D 0F        db 0Fh 
code:0040100E 0F        db 0Fh 
code:0040100F     ; --------------------------------------------------------------------------- 
code:0040100F C1 E0 02       shl  eax, 2 ; //x *= 4 
code:00401012 
code:00401012     loc_401012: 
code:00401012 89 45 08       mov  [ebp+8], eax // save x 
code:00401015 EB 09        jmp  short near ptr unk_401020 
code:00401017     ; --------------------------------------------------------------------------- 
code:00401017 
code:00401017     loc_401017:        ; CODE XREF: code:0040100Aj 
code:00401017 8B 4D 08       mov  ecx, [ebp+8] 

如果我猜的操作碼,那麼失蹤部分應增加10.5到EAX,沒有的東西很有可能。你可以嘗試的好奇心,使其

if (x > 20){ 
     x *= 4; 
     x += 40; 
}; 

你能還與它的ASM上市在一起後整個g(int)功能? (如果可能的話,在我的例子中使用二進制操作碼值)。

+0

ruslik - 我在這裏介紹的操作碼是由我在調試器內存視圖中覆蓋內存創建的。在寫這篇文章時,我沒有訪問原始轉儲列表,所以我用我的測試程序「手動」搞砸了內存。 – 2010-11-23 08:06:24

1

你的困難最可能的原因是你溢出了一個局部變量(比如說一個字符串)並覆蓋了你的堆棧幀。子例程退出時,它會從堆棧中彈出返回地址,並開始執行它在其中找到的任何指令。這是通過緩衝區溢出攻擊獲得利用的機制。

+0

堆棧溢出無法修改代碼段。該函數中有無效的操作碼。 – ruslik 2010-11-22 22:31:13

相關問題