一篇在程式還未結束執行時就能把自身刪除的文章(2千字)

看雪資料發表於2002-02-07

下面的程式碼由Gary Nebbett寫就.Gary Nebbett乃是WINDOWS NT/2000 NATIVE API REFERENCE的作者.乃NT系統一等一的高手.下面就分析一些他的這段程式碼.
這段程式碼在PROCESS沒有結束前就將啟動PROCESS的EXE檔案刪除了.
int main(int argc, char *argv[])
{
    HMODULE module = GetModuleHandle(0);
    CHAR buf[MAX_PATH];
    GetModuleFileName(module, buf, sizeof buf);
    CloseHandle(HANDLE(4));
    __asm {
        lea    eax, buf
        push    0
        push    0
        push    eax
        push    ExitProcess
        push    module
        push    DeleteFile
        push    UnmapViewOfFile
        ret
    }
    return 0;
}
現在,我們先看一下堆疊中的東西

偏移 內容
24  0
20  0
16  offset buf
12  address of ExitProcess
8    module
4    address of DeleteFile
0    address of UnmapViewOfFile

呼叫RET返回到了UnmapViewOfFile,也就是棧裡的偏移0所指的地方.當進入UnmapViewOfFile的流程時,棧裡見到的是返回地址DeleteFile和HMODUL module.也就是說呼叫完畢後返回到了DeleteFile的入口地址.當返回到DeleteFile時,看到了ExitProcess的地址,也就是返回地址.和引數EAX,而EAX則是buffer.buffer存的是EXE的檔名.由GetModuleFileName(module, buf, sizeof buf)返回得到.執行了DeleteFile後,就返回到了ExitProcess的函式入口.並且引數為0而返回地址也是0.0是個非法地址.如果返回到地址0則會出錯.而呼叫ExitProcess則應該不會返回.
這段程式碼的精妙之處在於:
1.如果有檔案的HANDLE開啟,檔案刪除就會失敗,所以,CloseHandle(HANDLE(4));是十分巧妙的一手.HANDLE4是OS的硬編碼,對應於EXE的IMAGE.在預設情況下,OS假定沒有任何呼叫會關閉IMAGE SECTION的HANDLE,而現在,該HANDLE被關閉了.刪除檔案就解除了檔案對應的一個控制程式碼.
2.由於UnmapViewOfFile解除了另外一個對應IMAGE的HANDLE,而且解除了IMAGE在記憶體的對映.所以,後面的任何程式碼都不可以引用IMAGE對映地址內的任何程式碼.否則就OS會報錯.而現在的程式碼在UnmapViewOfFile後則剛好沒有引用到任何IMAGE內的程式碼.
3.在ExitProcess之前,EXE檔案就被刪除了.也就是說,程式尚在,而主執行緒所在的EXE檔案已經沒了.(WINNT/9X都保護這些被對映到記憶體的WIN32 IMAGE不被刪除.)

Gary Nebbett果然是WIN系列平臺的頂尖高手之一.能寫出如此程式碼.獨闢蹊徑啊:)

相關文章