Windows NT/2000內部資料結構探究(http://webcrazy.yeah.net)

來源:互聯網
上載者:User
 Windows NT/2000內部資料結構探究
                   WebCrazy(tsu00@263.net)
                        注:本文最初見於www.nsfocus.com

    WINDOWS系統隱含了不少內部資料結構,其記錄著與系統相關的所有重要訊息如線程、進程、核心調用等等,具體如Windows NT/2000模組ntoskrnl.exe中的NtBuildNumber與KeServiceDescriptorTable等(用SoftICE或Visual Studio所帶的Dependency Walker之類的可以看到),前者只是指出當前Windows的Build號(如SoftICE下可用dw命令查出我的機器中為0893h 即十進位2195);後者是指向如下資料結構的指標:
    struct _ServiceDescriptorEntry {
       unsigned int *ServiceTableBase;
       unsigned int *ServiceCounterTableBase;
       unsigned int NumberOfServices;
       unsigned char *ParamTableBase;
    }ServiceDescriptorTableEntry

    其典型應用為Mark Russinovich與Bryce Cogswell的Regmon,具體可以參閱www.sysinternals.com.
    本文僅在Intel i386的Windows 2000 Server(Build 2195)中對TEB(Thread Environment Block)作初步介紹.
    TEB在Windows 9x系列中稱為TIB(Thread Information Block),她紀錄著線程的重要訊息,每一個線程對應一個TEB結構。其格式如下(摘自Matt Pietrek的Under the Hood專欄-MSJ 1996):
    typedef struct _TIB
    {
        PEXCEPTION_REGISTRATION_RECORD pvExcept; // 00h Head of exception record list
        PVOID pvStackUserTop; // 04h Top of user stack
        PVOID pvStackUserBase; // 08h Base of user stack

        union // 0Ch (NT/Win95 differences)
        {
            struct // Win95 fields
            {
                WORD pvTDB; // 0Ch TDB
                WORD pvThunkSS; // 0Eh SS selector used for thunking to 16 bits
                DWORD unknown1; // 10h
            } WIN95;

            struct // WinNT fields
            {
                PVOID SubSystemTib; // 0Ch
                ULONG FiberData; // 10h
            } WINNT;
        } TIB_UNION1;

        PVOID pvArbitrary; // 14h Available for application use
        struct _tib *ptibSelf; // 18h Linear address of TIB structure

        union // 1Ch (NT/Win95 differences)
        {
            struct // Win95 fields
            {
                WORD TIBFlags; // 1Ch
                WORD Win16MutexCount; // 1Eh
                DWORD DebugContext; // 20h
                DWORD pCurrentPriority; // 24h
                DWORD pvQueue; // 28h Message Queue selector
            } WIN95;

            struct // WinNT fields
            {
                DWORD unknown1; // 1Ch
                DWORD processID; // 20h
                DWORD threadID; // 24h
                DWORD unknown2; // 28h
            } WINNT;
        } TIB_UNION2;

        PVOID* pvTLSArray; // 2Ch Thread Local Storage array

        union // 30h (NT/Win95 differences)
        {
            struct // Win95 fields
            {
                PVOID* pProcess; // 30h Pointer to owning process database
            } WIN95;
        } TIB_UNION3;

     } TIB, *PTIB;

  在Windows 2000 DDK中定義為:
    typedef struct _NT_TIB
    {
        struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
        PVOID StackBase;
        PVOID StackLimit;
        PVOID SubSystemTib;
        union {
            PVOID FiberData;
            ULONG Version;
        };
        PVOID ArbitraryUserPointer;
        struct _NT_TIB *Self;
    } NT_TIB;

    慶幸的是,Windows在調入進程,建立線程時,作業系統均會為每個線程分配TEB,而且都將FS段選取器(i386)指向當前線程的TEB資料(單CPU機器在任何時刻系統中只有一條線程在執行),這就為我們提供了存取TEB資料的途徑。實際上Windows都是通過這種方法來為你的應用程式提供資訊的,讓我們來看一個例子吧!大家都知道用GetCurrentThreadID API來獲得當前線程ID的,其在Kernel32.dll是如下實現的:

    GetCurrentThreadID:
    mov eax, FS:[00000018] ; 18h Linear address of TIB structure(TIB結構線性地址)
    mov eax, [eax+24] ; 24h ThreadID
    ret ; 將EAX中的值返回給調用者

    由於TEB結構過於龐大,我現在只來談談位移量為00h的struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList,並結合CIH 1.3源碼來說說它具體用處。ExceptionList主要用於處理SEH(Structured Exception Handling)的。如果你連C語言中新增的_try,_except與_finally也不熟悉的話,建議請先看看Jeffery Richter的<<Advanced Windows NT>>或之類的。

  首先讓我們來看看_EXCEPTION_REGISTRATION_RECORD結構,在CRT(C++ RunTime library)源碼中它如下定義:

    // Exsup.INC ---Microsoft Visual C++ CRT 源檔案

    _EXCEPTION_REGISTRATION struc
    prev dd ?
    handler dd ?
    _EXCEPTION_REGISTRATION ends

    其中prev是指向前一_EXCEPTION_REGISTRATION的指標,形成一鏈狀結構,這樣才會在EXCPT.H中有EXCEPTION_CONTINUE_SEARCH這樣的定義(參閱&t;<Advanced Windows NT>>);handler指向異常處理代碼。

    CIH正是利用了這一機制,將handler指向它自己程式中。在它入口處有如下代碼:

       .
       .
       .

    ; *********************************************************
    ; * Ring3 Virus Game Initial Program *
    ; *********************************************************

    MyVirusStart: ; Ring3代碼進入點
    push ebp

    ; *************************************
    ; * Let's Modify Structured Exception *
    ; * Handing, Prevent Exception Error *
    ; * Occurrence, Especially in NT. *
    ; *************************************

    lea eax, [esp-04h*2]                 ;在棧中分配8位元組存放_EXCEPTION_REGISTRATION結構
                     ;相當於C中基於棧的資料,即局部變數(C編譯器中完成)
                                         ;這樣EAX即指向_EXCEPTION_REGISTRATION的指標,但此時
                     ;_EXCEPTION_REGISTRATION結構未初始化
                                         ;具體實現機制可翻閱編譯原理書籍和Matt Pietrek大師文章

                             
    xor ebx, ebx ;0->EBX
    xchg eax, fs:[ebx] ;FS:[0]<->EAX     ;此時EAX存放的是原來異常處理代碼,FS:[0]指向TEB中
                      ;ExceptionList(FS指向TEB,ExceptionList位移為0,即FS:[0])

    call @0
    @0:
    pop ebx                              ;此三行計算代碼入口,此時ebx就是@0的地址
    lea ecx, StopToRunVirusCode-@0[ebx]  ;將ecx指向自己內部代碼處
    push ecx                             ;填充_EXCEPTION_REGISTRATION結構的handler
                     ;在發生異常時,作業系統會自動調用,此時為CIH代碼

    push eax                             ;EAX為原來異常處理代碼
                                         ;填充_EXCEPTION_REGISTRATION結構的prev

       .
       .
       .

    這其後CIH調用int 3使系統發生異常,仍能進入自已的代碼,這可從CIH原始碼中的如下注釋得到證實:

    ; *************************************
    ; * Generate Exception to Get Ring0 *
    ; *************************************

    int HookExceptionNumber               ; GenerateException
  HookExceptionNumber定義為3,此段代碼會產生異常,具體請參閱CIH原始碼。

    因為如上代碼比較抽象,我特意將它稍加修改,以便於理解(PE格式可直接在Windows下執行):

    // TestCIH.C 有任何問題聯絡tsu00@263.net

    #include <windows.h>
    #include <stdio.h>

    EXCEPTION_DISPOSITION __cdecl _except_handler(  //例外處理常式段               
        struct _EXCEPTION_RECORD *ExceptionRecord,
        void * EstablisherFrame,
        struct _CONTEXT *ContextRecord,
        void * DispatcherContext )
    {
        printf( "CIH Run Here.../n" );
        exit(0); //由於堆棧已被程式打亂,有興趣的可以自己將它恢複,這兒我只簡單的退出
    }

    void main(void)
    {
        _asm
        {
            push ebp

            mov eax, esp
            sub eax, 8         //這兩行相當於lea eax, [esp-04h*2]
            xor ebx, ebx
            xchg eax, fs:[ebx]

            call next
      next:
            pop ebx                    //這三行在這沒實在意義,只是為了與CIH對比

            lea ecx, _except_handler  //將_except_handler設為異常處理入口
            push ecx

            push eax
        }

        _asm
        {
            mov eax,0
            mov [eax],0       //發生STATUS_ACCESS_VIOLATION異常讓作業系統調用_except_handler
        }
    }

    _except_handler回呼函數原形可參閱EXCPT.H 
    在main函數中第一個_asm段與前面討論的CIH代碼基本一致,而第二個_asm段則試圖寫系統保留記憶體位址,發生異常。
    使用Visual C++如下編譯:
        c:>Cl testCIH.c
        c:>testCIH
           CIH Run Here...
    在Windows 2000中,運行此段代碼時,出現異常後作業系統將控制權交給_except_handler執行,這樣CIH代碼在NT/2000環境下在系統修改被其保護的記憶體位址時(IDT地區),不至於出現非法操作等提示,以達到保護自己的目的!

    我總覺得瞭解系統安全,首先必須對這個系統有足夠的瞭解,就像瞭解CIH病毒一樣,而目前國內在這方面的資料可真謂少之又少,本文僅在這方面說出我自己的一些切身實踐,錯誤之處,在所難免。如果您有任何發現,如果您對這方面有比較有興趣,請聯絡tsu00@263.net.

    最後很感謝綠盟高手的指點與協助!

    參考文獻:

        1.Jeffrey Richter <<Advanced Windows NT>>
        2.Matt Pietrek <<A Crash Course on the Depths of Win32 Structured Exception Handling>>
        3.CIH 1.3原始碼

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.