萬盛學電腦網

 萬盛學電腦網 >> 健康知識 >> 對Windows XP SP2溢出漏洞進行保護(下)

對Windows XP SP2溢出漏洞進行保護(下)

  ZwQueryInformationProcess最後會調用一個系統調用,轉到內核運行,最後會調用內核中的函數NtQueryInformationProcess,並且調用該函數的子功能代碼為0x24。該子功能直接取出保存在進程中的一個隨機數,並將其拷貝到用戶堆棧中的一個臨時變量中。如果該隨機數為0,則還要根據系統時間重新生成該隨機數,一般在進程剛開始創建的時候,這個隨機數為0,從而會重新生成該隨機數。由於該隨機數跟進程創建的時間有關,所以這個隨機數是無法猜測的。該函數在ntoskrnl.exe中導出,跟這個功能相關的函數代碼為:    PAGE:004970CC loc_4970CC:  ;下面的代碼得到一個進程唯一的隨機數,子功能代碼為0x24  PAGE:004970CC cmp edi, edx ; case 0x24  PAGE:004970CE jnz loc_497349  PAGE:004970D4 cmp dword ptr [ebp 8], 0FFFFFFFFh  PAGE:004970D8 jnz loc_4977B8  ;下面的代碼得到保存隨機數的地址  PAGE:004970DE mov eax, large fs:124h  PAGE:004970E4 mov eax, [eax 44h]  PAGE:004970E7 mov [ebp-34h], eax  PAGE:004970EA  PAGE:004970EA loc_4970EA:  PAGE:004970EA mov edi, [ebp-34h]  PAGE:004970ED add edi, 258h  ;edi地址中保存的是一個跟進程相關的隨機數,這裡取出這個隨機數  PAGE:004970F3 mov eax, [edi]  PAGE:004970F5 test eax, eax  PAGE:004970F7 jz loc_4B2379  {  ;如果得到的隨機數為0,則重新得到隨機數,得到隨機數的過程如下:  ;1、先得到系統的時間,  ;2、而後將這個時間和系統內核中的一個值進行不斷的異或操作,  ;就產生了一個隨機數  PAGE:004B2379  PAGE:004B2379 loc_4B2379:  ;得到系統時間  PAGE:004B2379 lea eax, [ebp-3Ch]  PAGE:004B237C push eax  PAGE:004B237D call KeQuerySystemTime  PAGE:004B2382 db 3Eh  ;得到系統內核中的一個全局變量,該全局變量估計也是一個隨機數  PAGE:004B2382 mov eax, ds:0FFDFF020h  PAGE:004B2388 mov ecx, [eax 518h]  PAGE:004B238E xor ecx, [eax 4B8h]  ;將得到的隨機數和得到系統時間進行異或  PAGE:004B2394 xor ecx, [ebp-38h]  PAGE:004B2397 xor ecx, [ebp-3Ch]  ;將計算得到的隨機數保存在上面的跟進程相關的全局變量中,edi中保存的就是  ;這個地址。  PAGE:004B239A mov [ebp-0CCh], ecx  PAGE:004B23A0 mov [ebp-0D4h], edi  PAGE:004B23A6 mov eax, 0  PAGE:004B23AB mov ecx, [ebp-0D4h]  PAGE:004B23B1 mov edx, [ebp-0CCh]  PAGE:004B23B7 cmpxchg [ecx], edx  PAGE:004B23BA push 4  PAGE:004B23BC pop edx  ;重新轉到loc_4970EA,再一次得到剛才生成的隨機數,如果該生成的隨機數為  ;0,則還會重新生成。  PAGE:004B23BD jmp loc_4970EA  }  ;得到隨機數之後,將其拷貝到用戶棧中的一個臨時變量中,esi保存的就是這個臨時  ;變量的地址。至此,就得到了一個跟進程相關的隨機數,該隨機數跟進程的創建時間  ;相關。  PAGE:004970FD mov dword ptr [ebp-4], 15h  PAGE:00497104 mov [esi], eax  PAGE:00497106 test ebx, ebx  PAGE:00497108 jnz loc_497AA5  PAGE:0049710E jmp loc_4955F5    到這裡我們已經完全清楚了整個隨機數的獲取過程。該隨機數跟進程的創建時間相關,可見我們是無法猜得該隨機數的。不過這個隨機數只是再進程創建的時候產生,並且直到進程結束,該隨機數都不會改變。所以,如果我們可以得到該隨機數,在進程結束之前還是可以利用的。比如我們可以將其和我們的跳轉地址進行異或,通過溢出將其寫入到最高溢出處理地址,就可以像以前一樣利用了。    不過這種方法對於遠程溢出是無法利用的。但是如果能夠覆蓋程序的導入表或者靜態數據段,那就是最理想的情況了。不過系統DLL的導入表不能夠修改,但是一般程序的導入表還都是可以改的,所以還是有利用的可能性的。如果在靜態數據段中存在某些函數的指針,則可以進行覆蓋,從而加以利用,如果存在這種情況的話,5自學網,要做到利用的通用還是有可能的。    3、VEH鏈表指針_RtlpCalloutEntryList的保護    我們知道堆溢出經常用的一個技巧就是修改VEH的鏈表指針。這在XP sp0和sp1的環境下都好使。但是sp2同樣堵住了這條路。    XP_sp2下    異常處理過程  KiUserExceptionDispatcher  |  ________RtlDispatchException  |  ___________RtlCallVectoredExceptionHandlers    sp2中,該指針位於  .data:7C99C320 _RtlpCalloutEntryList dd 0 ; DATA XREF: LdrpInitializeProcess(x,x,x,x,x) 2EFo  .data:7C99C320 ; LdrpInitializeProcess(x,x,x,x,x) 2F9w ...    我們就直接看看RtlCallVectoredExceptionHandlers函數    .text:7C95779C ; __stdcall RtlCallVectoredExceptionHandlers(x,x)  .text:7C95779C _RtlCallVectoredExceptionHandlers@8 proc near  .text:7C95779C ; CODE XREF: RtlDispatchException(x,x) 14p  .text:7C95779C mov edi, edi  .text:7C95779E push ebp  .text:7C95779F mov ebp, esp  .text:7C9577A1 push ecx  .text:7C9577A2 push ecx  .text:7C9577A3 push edi  這裡就比較VEH的鏈表是不是空的,5自學網,也就是看自己是否指向自己。如果是空的就不用說了,非空就轉向該指針的調用  .text:7C9577A4 mov edi, offset _RtlpCalloutEntryList  .text:7C9577A9 cmp _RtlpCalloutEntryList, edi  .text:7C9577AF jnz loc_7C962DA0      .text:7C962DA0 loc_7C962DA0: ; CODE XREF: RtlCallVectoredExceptionHandlers(x,x) 13j   .text:7C962DA0 mov eax, [ebp arg_4]  .text:7C962DA3 push ebx  .text:7C962DA4 push esi  .text:7C962DA5 mov [ebp var_8], eax  .text:7C962DA8 mov eax, [ebp arg_8]  .text:7C962DAB mov ebx, offset _RtlpCalloutEntryLock  .text:7C962DB0 push ebx  .text:7C962DB1 mov [ebp var_4], eax  .text:7C962DB4 call _RtlEnterCriticalSection@4 ; RtlEnterCriticalSection(x)  .text:7C962DB9 mov esi, _RtlpCalloutEntryList  .text:7C962DBF jmp short loc_7C962DD6    .text:7C962DC1 loc_7C962DC1: ; CODE XREF: RtlInitializeResource(x) 21C3Dj  .text:7C962DC1 push dword ptr [esi 8]    代碼就不解釋那麼多了,可以看到指針在使用前必須先解碼,這個函數前面已經講解過了。  .text:7C962DC4 call _RtlDecodePointer@4 ; RtlDecodePointer(x)  .text:7C962DC9 lea ecx, [ebp var_8]  .text:7C962DCC push ecx  .text:7C962DCD call eax  .text:7C962DCF cmp eax, 0FFFFFFFFh  .text:7C962DD2 jz short loc_7C962DEE  .text:7C962DD4 mov esi, [esi]    所以可以看到在sp2下無法利用這個覆蓋VEH鏈表指針的技巧了。    給出XP sp1下通用的指針    XP sp1下  .text:77F60C26 ; __stdcall RtlCallVectoredExceptionHandlers(x,x)  .text:77F60C26 _RtlCallVectoredExceptionHandlers@8 proc near  .text:77F60C26 ; CODE XREF: RtlDispatchException(x,x) Ep  .text:77F60C26 push ebp  .text:77F60C27 mov ebp, esp  .text:77F60C29 push ecx  .text:77F60C2A push ecx  .text:77F60C2B push edi  .text:77F60C2C mov edi, offset _RtlpCalloutEntryList  .text:77F60C31 cmp _RtlpCalloutEntryList, edi  ;這裡我們可以看到將77FC3210的值放入edi,然後和該地址的內容相比較,如果沒有安裝VEH,那麼該地址  ;的內容也是77FC3210,就不會跳轉到77F7F485。如果用戶安裝了VEH,那麼就會跳到77F7F485  .text:77F60C37 jnz loc_77F7F485  .text:77F60C3D xor al, al  .text:77F60C3F  .text:77F60C3F loc_77F60C3F: ; CODE XREF: RtlInitializeResource(x) 1B6CDj  .text:77F60C3F pop edi  .text:77F60C40 leave  .text:77F60C41 retn 8    .text:77F7F485 loc_77F7F485: ; CODE XREF: RtlCallVectoredExceptionHandlers(x,x) 11j  .text:77F7F485 mov eax, [ebp 8]  .text:77F7F488 push ebx  .text:77F7F489 push esi  .text:77F7F48A mov [ebp-8], eax  .text:77F7F48D mov eax, [ebp 0Ch]  .text:77F7F490 mov ebx, offset _RtlpCalloutEntryLock  .text:77F7F495 push ebx  .text:77F7F496 mov [ebp-4], eax  .text:77F7F499 call _RtlEnterCriticalSection@4 ; RtlEnterCriticalSection(x)    關鍵的下面這個部分,從77FC3210裡面取出安裝的處理函數地址    .text:77F7F49E mov esi, _RtlpCalloutEntryList  .text:77F7F4A4 jmp short loc_77F7F4B4  .text:77F7F4A6 loc_77F7F4A6: ; CODE XREF: RtlInitializeResource(x) 1B6BCj  .text:77F7F4A6 lea eax, [ebp-8]  .text:77F7F4A9 push eax  .text:77F7F4AA call dword ptr [esi 8]  ;這裡esi指向struct _VECTORED_EX
copyright © 萬盛學電腦網 all rights reserved