首页 电脑 电脑学堂 查看内容

Widows Xp Sp2溢出保护

2004-12-18 12:08 821 0

摘要: funnywei & jerry我们知道在我们对溢出漏洞进行exp的时候,经常要利用全局性的指针,利用异常处理。那么XP的sp2对此作了处理。使得我们无法运用以前的技巧来完成我们的工作。例如,...
关键词: nbsp text 随机数 004 函数 PAGE push mov ebp eax

funnywei & jerry我们知道在我们对溢出漏洞进行exp的时候,经常要利用全局性的指针,利用异常处理。那么XP的sp2对此作了处理。使得我们无法运用以前的技巧来完成我们的工作。例如,对全局性的指针都作了编码处理。那么具体来讲,本文主要谈到以下1、映射给PEB管理结构的起始地址做了随机处理。后面我们会看到这种随机是很弱的,但已经足够让exp无法完成或者说是稳定的工作。2、对TOP SEH的保护3、VEH链表指针_RtlpCalloutEntryList的保护4、堆块结构的cookie保护不涉及内容:1、如何绕过保护机制2、堆管理的细节,其实没有太大的变化主题开始:1、PEB的地址的随机xp系统下,创建进程使用的是_NtCreateProcessEx函数,而不是_NtCreateProcess函数。_NtCreateProcess主要调用_PspCreateProcess@36函数来完成进程的创建工作PAGE:004B4649                 call    _PspCreateProcess@36 ; PspCreateProcess(x,x,x,x,x,x,x,x,x)进程的创建主要包括设置EPROCESS,创建初始进程地址空间等。这里就不罗嗦了。PEB的设置通过调用_MmCreatePeb.PAGE:004B428E                 push    eaxPAGE:004B428F                 push    ebxPAGE:004B4290                 push    dword ptr [ebp-60h]PAGE:004B4293                 call    _MmCreateProcessAddressSpace@12 ; MmCreateProcessAddressSpace(x,x,x)PAGE:004B43E5                 lea     eax, [ebx+1B0h]PAGE:004B43EB                 push    eaxPAGE:004B43EC                 lea     eax, [ebp-40h]PAGE:004B43EF                 push    eaxPAGE:004B43F0                 push    ebxPAGE:004B43F1                 call    _MmCreatePeb@12 ; MmCreatePeb(x,x,x)而MmCreatePeb又主要通过调用_MiCreatePebOrTebPAGE:004B4A61 ; __stdcall MmCreatePeb(x,x,x)PAGE:004B4A61 _MmCreatePeb@12 proc near               ; CODE XREF: PspCreateProcess(x,x,x,x,x,x,x,x,x)+303pPAGE:004B4A61PAGE:004B4A61 ; FUNCTION CHUNK AT PAGE:005267FF SIZE 000000DC BYTESPAGE:004B4A61PAGE:004B4A61                 push    3ChPAGE:004B4A63                 push    offset dword_42DAA8PAGE:004B4A68                 call    __SEH_prologPAGE:004B4A6D                 xor     ebx, ebxPAGE:004B4A6F                 mov     [ebp-20h], ebxPAGE:004B4A72                 mov     [ebp-4Ch], ebxPAGE:004B4A75                 mov     [ebp-48h], ebxPAGE:004B4A78                 mov     [ebp-2Ch], ebxPAGE:004B4A7B                 mov     esi, [ebp+8]PAGE:004B4A7E                 push    esiPAGE:004B4A7F                 call    _KeAttachProcess@4 ; KeAttachProcess(x)PAGE:004B4A84                 push    2PAGE:004B4A86                 pop     ediPAGE:004B4A87                 push    ediPAGE:004B4A88                 push    (offset loc_4FFFFE+2)PAGE:004B4A8D                 push    1PAGE:004B4A8F                 lea     eax, [ebp-2Ch]PAGE:004B4A92                 push    eaxPAGE:004B4A93                 lea     eax, [ebp-4Ch]PAGE:004B4A96                 push    eaxPAGE:004B4A97                 push    ebxPAGE:004B4A98                 push    ebxPAGE:004B4A99                 lea     eax, [ebp-20h]PAGE:004B4A9C                 push    eaxPAGE:004B4A9D                 push    esiPAGE:004B4A9E                 push    ds:_InitNlsSectionPointerPAGE:004B4AA4                 call    _MmMapViewOfSection@40 ; MmMapViewOfSection(x,x,x,x,x,x,x,x,x,x)PAGE:004B4AA9                 mov     [ebp-24h], eaxPAGE:004B4AAC                 cmp     eax, ebxPAGE:004B4AAE                 jl      loc_5267FFPAGE:004B4AB4                 lea     eax, [ebp-1Ch]注意下面这个210参数,类似一个Flag。在后面你会发现,如果该参数不等于210,那么映射的PEB地址将不会产生随机值,而是会跟以前的一样,始终在7FFDF000位置。PAGE:004B4AB7                 push    eaxPAGE:004B4AB8                 push    210h;注意这个参数!PAGE:004B4ABD                 push    esiPAGE:004B4ABE                 call    _MiCreatePebOrTeb@12 ; MiCreatePebOrTeb(x,x,x)真正完成工作_MiCreatePebOrTeb@12 函数PAGE:004B01AE                 call    _ExAllocatePoolWithTag@12 ; ExAllocatePoolWithTag(x,x,x)PAGE:004B01B3                 mov     esi, eaxPAGE:004B01B5                 test    esi, esiPAGE:004B01B7                 jz      loc_52678EPAGE:004B01BD                 mov     eax, [ebp+arg_8]PAGE:004B01C0                 mov     ecx, [ebp+arg_8]PAGE:004B01C3                 and     eax, 0FFFhPAGE:004B01C8                 neg     eaxPAGE:004B01CA                 sbb     eax, eaxPAGE:004B01CC                 neg     eaxPAGE:004B01CE                 shr     ecx, 0ChPAGE:004B01FB                 cmp     [ebp+arg_8], 210hPAGE:004B0202                 jz      loc_4B4A0A;这里将210与压栈的参数比较,如果压入栈的不是210呢PAGE:004B0208 loc_4B0208:                             ; CODE XREF: MiCreatePebOrTeb(x,x,x)+48ADjPAGE:004B0208                 mov     edi, [ebp+arg_C]PAGE:004B020B                 mov     eax, _MmHighestUserAddressPAGE:004B0210                 push    ediPAGE:004B0211                 push    dword ptr [ebx+11Ch]PAGE:004B0217                 add     eax, 0FFFF0001hPAGE:004B021C                 push    1000hPAGE:004B0221                 push    eaxPAGE:004B0222                 mov     eax, [ebp+arg_8]PAGE:004B0225                 add     eax, 0FFFhPAGE:004B022A                 and     eax, 0FFFFF000hPAGE:004B022F                 push    eaxPAGE:004B0230                 call    _MiFindEmptyAddressRangeDownTree@20 ; MiFindEmptyAddressRangeDownTree(x,x,x,x,x)PAGE:004B0235                 test    eax, eaxPAGE:004B0237                 mov     [ebp+arg_C], eaxPAGE:004B023A                 jl      loc_5267A5关键是这里PAGE:004B4A0A loc_4B4A0A:                             ; CODE XREF: MiCreatePebOrTeb(x,x,x)+66jPAGE:004B4A0A                 mov     edi, _MmHighestUserAddress;总是7FFEFFFFPAGE:004B4A10                 lea     eax, [ebp+var_C] PAGE:004B4A13                 push    eaxPAGE:004B4A14                 add     edi, 0FFFF0001h;此时edi为7FFE0000PAGE:004B4A1A                 call    _KeQueryTickCount@4 ; KeQueryTickCount(x)PAGE:004B4A1F                 mov     eax, [ebp+var_C]PAGE:004B4A22                 and     eax, 0Fh;只取最后一个字节的值,比如此时为0CPAGE:004B4A25                 cmp     eax, 1;看eax此时是不是为01PAGE:004B4A28                 mov     [ebp+var_C], eaxPAGE:004B4A2B                 jbe     loc_4B4928;如果是就跳到去处理PAGE:004B4A31 loc_4B4A31:                             ; CODE XREF: MiCreatePebOrTeb(x,x,x)+4792jPAGE:004B4A31                 shl     eax, 0ChPAGE:004B4A34                 sub     edi, eaxPAGE:004B4A36                 lea     eax, [edi+0FFFh]PAGE:004B4A3C                 push    eaxPAGE:004B4A3D                 push    ediPAGE:004B4A3E                 push    ebxPAGE:004B4A3F                 mov     [ebp+var_4], ediPAGE:004B4928 loc_4B4928:                             ; CODE XREF: MiCreatePebOrTeb(x,x,x)+488Fj如果eax为1,那么就更改为2.这样避免最后计算出来为7FFDF000.而是为7FFDE000PAGE:004B4928                 push    2PAGE:004B492A                 pop     eaxPAGE:004B492B                 mov     [ebp+var_C], eaxPAGE:004B492E                 jmp     loc_4B4A31因为KeTickCount是进程的一个时间计数,所以无法预测。.text:0041CAA8                 mov     edi, edi.text:0041CAAA                 push    ebp.text:0041CAAB                 mov     ebp, esp.text:0041CAAD                 mov     ecx, _KeTickCount.High1Time.text:0041CAB3                 mov     eax, [ebp+arg_4].text:0041CAB6                 mov     [eax+4], ecx.text:0041CAB9                 mov     edx, _KeTickCount.LowPart.text:0041CABF                 mov     [eax], edx经过上面的分析我们知道,如果如果eax随机出来是1,2,那么最后分配的PEB的地址都是7FFDE000,这是为了避免以前的7FFDF000地址的出现,使得以前的堆利用代码都失效。:)1,2    7FFDE0003    7FFDD0004    7FFDC0005    7FFDB0006    7FFDA0007    7FFD90008    7FFD80009    7FFD7000A    7FFD6000B    7FFD5000C    7FFD4000D    7FFD3000E    7FFD2000F    7FFD10000    7FFDE000上面列出了可以看到PEB的所有可能值,可以看到7FFDE000的概率最高,1/8,其他都是1/16。:),但即使这样,也没法稳定利用了。2、对TOP SEH的保护微软对函数SetUnhandledExceptionFilter的代码进行了重大的调整。SetUnhandledExceptionFilter是kernel32.dll中导出的一个函数,用来设置一个筛选器异常处理回掉函数,这个回掉函数不替换系统默认的异常处理程序,而只是在它前面进行了一些预处理,操作的结果还是会送到系统默认的异常处理程序中去,这个过程就相当于对异常进行了一次筛选。函数的SetUnhandledExceptionFilter调用方式为:LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);这个函数唯一的一个参数就是需要设置的回调函数的地址,返回值为上一次设置的回掉函数的地址。该函数不是在原来的回掉函数前再挂一个回掉函数,而是用这个新的回掉函数替换原来的那个回掉函数。如果地址参数被指定为NULL,那么系统将去掉这个“筛子”而直接将异常送往默认的异常处理程序。winxp sp2对这个函数做了重大的改变,在替换原来的回掉函数之前,首先会先对新的回掉函数的地址进行加密,而后再替换原来的回掉函数。在返回原回掉函数地址之前,会对其进行解密。该函数比较简单:.text:7C810386 SetUnhandledExceptionFilter proc near.text:7C810386 lpTopLevelExceptionFilter = dword ptr  8.text:7C810386 .text:7C810386                 mov     edi, edi.text:7C810388                 push     ebp.text:7C810389                 mov     ebp, esp;这里先对地址lpTopLevelExceptionFilter进行加密.text:7C81038B                 push     [ebp+ lpTopLevelExceptionFilter].text:7C81038E                 call      RtlEncodePointer;而后将加密之后的地址和原回掉函数地址进行交换,也就是将加密之后的地址写入到;一个全局变量中,同时将该全局变量中的原回掉函数地址返回.text:7C810393                 push     eax             ; Value.text:7C810394                 push     offset Target      ; Target.text:7C810399                 call      InterlockedExchange;在返回原回掉函数地址之前先进行解密,因为原回掉函数地址也进行了加密.text:7C81039E                 push     eax.text:7C81039F                 call      RtlDecodePointer.text:7C8103A4                 pop     ebp.text:7C8103A5                 retn    4.text:7C8103A5 SetUnhandledExceptionFilter endp ; sp = -8.text:7C8103A5而以前都是直接将回掉函数的地址写入到全局变量中,没有经过任何的处理。可见,我们再也无法像以前一样通过覆盖该函数指针来利用堆溢出了。而且经过分析发现,winxp sp2对所有的全局指针都进行了这样的加密处理。接着往下看它是怎么对地址进行加密的。RtlEncodePointer和RtlDecodePointer都是ntdll.dll导出的函数,RtlEncodePointer用来对一个指针进行加密,RtlDecodePointer用来对一个指针进行解密。其实整个个加密解密过程都很简单,加密时直接将指针和一个的随机数进行异或,解密时再和该随机数进行异或。加密:point = point ^ rand解密:point = point ^ randrand是一个跟进程相关的随机数,通过调用函数ZwQueryInformationProcess得到,每个进程该随机数都不一样。为了避免你再次进行反汇编,这里贴出这两个函数的代码。RtlEncodePointer函数的代码如下:.text:7C933917 RtlEncodePointer proc near .text:7C933917 var_4           = dword ptr -4.text:7C933917 arg_4           = dword ptr  8.text:7C933917 .text:7C933917                 mov     edi, edi.text:7C933919                 push    ebp.text:7C93391A                 mov     ebp, esp;调用函数ZwQueryInformationProcess得到一个跟进程相关的随机数.text:7C93391C                 push    ecx.text:7C93391D                 push    0.text:7C93391F                 push    4;这里得到堆栈中的一个临时变量的地址,最后得到的随机数将保存在这个临时变量中。.text:7C933921                 lea     eax, [ebp+var_4].text:7C933924                 push    eax.text:7C933925                 push    24h ;子功能代码为0x24.text:7C933927                 push    0FFFFFFFFh.text:7C933929                 call    ZwQueryInformationProcess;将得到的随机数和指针进行异或,这样就完成了加密。 ;解密的过程和加密的过程相同.text:7C93392E                 mov     eax, [ebp+var_4].text:7C933931                 xor     eax, [ebp+arg_4].text:7C933934                 leave.text:7C933935                 retn    4.text:7C933935 RtlEncodePointer endp ; sp =  4函数RtlDecodePointer更简单,只是直接转到RtlEncodePointer执行,因为解密的过程和加密的过程完全相同。.text:7C93393D RtlDecodePointer proc near             ;下面这四跳语句没有任何的作用.text:7C93393D                 mov     edi, edi.text:7C93393F                 push    ebp.text:7C933940                 mov     ebp, esp.text:7C933942                 pop     ebp;下面这条语句转到RtlEncodePointer执行,其实就相当于直接调用了函数;RtlEncodePointer.text:7C933943                 jmp     short RtlEncodePointer.text:7C933943 RtlDecodePointer endpZwQueryInformationProcess最后会调用一个系统调用,转到内核运行,最后会调用内核中的函数NtQueryInformationProcess,并且调用该函数的子功能代码为0x24。该子功能直接取出保存在进程中的一个随机数,并将其拷贝到用户堆栈中的一个临时变量中。如果该随机数为0,则还要根据系统时间重新生成该随机数,一般在进程刚开始创建的时候,这个随机数为0,从而会重新生成该随机数。由于该随机数跟进程创建的时间有关,所以这个随机数是无法猜测的。该函数在ntoskrnl.exe中导出,跟这个功能相关的函数代码为:PAGE:004970CC loc_4970CC:                            ;下面的代码得到一个进程唯一的随机数,子功能代码为0x24PAGE:004970CC                 cmp     edi, edx        ; case 0x24PAGE:004970CE                 jnz     loc_497349PAGE:004970D4                 cmp     dword ptr [ebp+8], 0FFFFFFFFhPAGE:004970D8                 jnz     loc_4977B8;下面的代码得到保存随机数的地址PAGE:004970DE                 mov     eax, large fs:124hPAGE:004970E4                 mov     eax, [eax+44h]PAGE:004970E7                 mov     [ebp-34h], eaxPAGE: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, eaxPAGE: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], 15hPAGE:00497104                 mov     [esi], eaxPAGE:00497106                 test    ebx, ebxPAGE:00497108                 jnz     loc_497AA5PAGE:0049710E                 jmp     loc_4955F5到这里我们已经完全清楚了整个随机数的获取过程。该随机数跟进程的创建时间相关,可见我们是无法猜得该随机数的。不过这个随机数只是再进程创建的时候产生,并且直到进程结束,该随机数都不会改变。所以,如果我们可以得到该随机数,在进程结束之前还是可以利用的。比如我们可以将其和我们的跳转地址进行异或,通过溢出将其写入到最高溢出处理地址,就可以像以前一样利用了。不过这种方法对于远程溢出是无法利用的。但是如果能够覆盖程序的导入表或者静态数据段,那就是最理想的情况了。不过系统DLL的导入表不能够修改,但是一般程序的导入表还都是可以改的,所以还是有利用的可能性的。如果在静态数据段中存在某些函数的指针,则可以进行覆盖,从而加以利用,如果存在这种情况的话,要做到利用的通用还是有可能的。3、VEH链表指针_RtlpCalloutEntryList的保护我们知道堆溢出经常用的一个技巧就是修改VEH的链表指针。这在xp sp0和sp1的环境下都好使。但是sp2同样堵住了这条路。xp_sp2下异常处理过程KiUserExceptionDispatcher|________RtlDispatchException        |        ___________RtlCallVectoredExceptionHandlerssp2中,该指针位于.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的链表是不是空的,也就是看自己是否指向自己。如果是空的就不用说了,非空就转向该指针的调用.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_EXCEPTION_NODE结构,其0x08处为m_pfnVectoredHandler;看到这里我们也就明白了,如果我们可以控制该指针,那么我们就可以控制程序的流程了!.text:77F7F4AD                 cmp     eax, 0FFFFFFFFh.text:77F7F4B4 loc_77F7F4B4:                           ; CODE XREF: RtlInitializeResource(x)+1B6AAj.text:77F7F4B4                 cmp     esi, edi.text:77F7F4B6                 jnz     short loc_77F7F4A6xp_sp0下_RtlpCalloutEntryList 位于77FC5BD0.data:77FC5BD0 _RtlpCalloutEntryList dd 0              ; DATA XREF: RtlCallVectoredExceptionHandlers(x,x)+6o.data:77FC5BD0                                         ; RtlCallVectoredExceptionHandlers(x,x)+Br ...4、堆块的cookie保护现在堆块的结构HEAP_ENTRY      struc ; (sizeof=0X8)Size            dw ?PrevSize        dw ?Cookie          db ?Flags           db ?UnusedBytes     db ?Index           db ?HEAP_ENTRY      ends空闲块管理结构_RTL_HEAP_FREE_BLOCK struc ; (sizeof=0X10)Entry           _RTL_HEAP_ENTRY ?List            LIST_ENTRY ?_RTL_HEAP_FREE_BLOCK ends对比一下以前的堆块结构typedef struct _HEAP_ENTRY {/*0x00*/    USHORT Size;/*0x02*/    USHORT PreviousSize;/*0x04*/    UCHAR SegmentIndex;/*0x05*/    UCHAR Flags;/*0x06*/    UCHAR UnusedBytes;/*0x07*/    UCHAR SmallTagIndex;} HEAP_ENTRY, *PHEAP_ENTRY;可以看到SmallTagIndex被舍弃了,SegmentIndex挪动到后面,而第5个字节更改为cookie。Cookie的计算公式:堆块头部地址除以8,然后跟Heap的总体管理结构中的cookie来异或就得到了cookie的值。代码如下.text:7C931487                 mov     edx, esi             ;ESI指向HEAP_ENTRY.text:7C931489                 shr     edx, 3.text:7C93148C                 xor     eax, eax.text:7C93148E                 mov     al, [edi+4]     ; 进行Cookie处理,此时edi指向堆管理结构分配头部.text:7C931491                 xor     eax, edx.text:7C931493                 mov     [esi+4], al那么我们可以看到cookie有256, 的值,所以你也就不用费尽心思来想怎么覆盖cookie而不出错了。当然有很多办法绕过cookie的检测。xp sp2对于堆的管理并没有太大的变化,但是堆的管理结构,堆块,还有Lookaside表的某些字段发生了变化,比如说有的字段从dd变成了dw,因此加了几个字段。这些细节就不在这里罗嗦了。 , 个可能的值,所以你也就不用费尽心思来想怎么覆盖cookie而不出错了。当然有很多办法绕过cookie的检测。xp sp2对于堆的管理并没有太大的变化,但是堆的管理结构,堆块,还有Lookaside表的某些字段发生了变化,比如说有的字段从dd变成了dw,因此加了几个字段。这些细节就不在这里罗嗦了。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部