Windows Xp Sp2 overflow protection Author: funnywei & jerry
Source: http://www.xfocus.net/Articles/200412/762.html
Date: 2005-01-06
We know that the global pointer often uses the overall pointer when we perform EXP for overflow vulnerabilities. Then the XP's SP2 is handled. Make we unable to use our previous skills to complete our work. For example, both a global pointer is encoded.
So specifically, this article mainly talks about the following
1. Mapping the start address of the PEB management structure to do random processing. Behind we will see this random is very weak, but it is enough to make EXP can't complete or stable work.
2. Protection for TOP SEH
3, VEH Link Pointer _RTLPCalloutentryList protection
4, cookie protection for the block structure
Do not involve content:
1, how to bypass the protection mechanism
2, the details of the heap management, there is no much change
The subject start:
1, randomness of the address of the PEB
Under the XP system, create a process using the _ntcreateProcessEx function, not the _ntcreateprocess function. _NTCREATEPROCESS mainly calls the _pspcreateprocess @ 36 function to complete the creation of the process
Page: 004B4649 Call_PspCreateProcess @ 36; PSpCreateProcess (x, x, x, x, x, x, x, x, x)
The creation of the process mainly includes setting EPRocess, creating an initial process address space. It's not coming here. The setting of the PEB is called _mmcreatepeb.
Page: 004B428E Push Eax
Page: 004B428F PUSH EBX
Page: 004B4290 PUSH DWORD PTR [EBP-60H]
Page: 004B4293 Call_MmcreateProcessAddressSpace @ 12; MmcreateProcessAddressSpace (x, x, x)
Page: 004B43E5 Lea Eax, [EBX 1B0H]
Page: 004B43EB PUSH EAX
Page: 004B43EC Lea Eax, [EBP-40H]
Page: 004B43EF Push EAX
Page: 004B43F0 PUSH EBX
Page: 004B43F1 Call_Mmcreatepeb @ 12; MmcreatePeb (x, x, x)
MmcreatePeb is mainly called _micreatepeborteb
Page: 004B4A61; __STDCALL MMCREATEPEB (X, X, X)
Page: 004B4A61 _MMCreatepeb @ 12 proc near; code XREF: PSpCreateProcess (x, x, x, x, x, x, x, x, x) 303p
Page: 004B4A61
Page: 004B4A61; Function CHUNK AT Page: 005267ff Size 000000dc Bytes
Page: 004B4A61
Page: 004B4A61 PUSH 3CH
Page: 004B4A63 PUSH OFFSET DWORD_42DAA8PAGE: 004B4A68 CALL __SEH_PROLOG
Page: 004B4A6D XOR EBX, EBX
Page: 004B4A6F MOV [EBP-20H], EBX
Page: 004B4A72 MOV [EBP-4CH], EBX
Page: 004B4A75 MOV [EBP-48H], EBX
Page: 004B4A78 MOV [EBP-2CH], EBX
Page: 004B4A7B MOV ESI, [EBP 8]
Page: 004B4A7E PUSH ESI
Page: 004B4A7f call_keattachprocess @ 4; KeattachProcess (x)
Page: 004B4A84 PUSH 2
Page: 004B4A86 POP EDI
Page: 004B4A87 Push EDI
Page: 004B4A88 PUSH (Offset Loc_4fffffe 2)
Page: 004B4A8D PUSH 1
Page: 004B4A8F LEA EAX, [EBP-2CH]
Page: 004B4A92 PUSH EAX
Page: 004B4A93 LEA EAX, [EBP-4CH]
Page: 004B4A96 PUSH EAX
Page: 004B4A97 PUSH EBX
Page: 004B4A98 PUSH EBX
Page: 004B4A99 LEA EAX, [EBP-20H]
Page: 004B4A9C Push EAX
Page: 004B4A9D PUSH ESI
Page: 004B4A9E Push DS: _initnlssectionPointer
Page: 004B4AA4 CALL _MMMAPVIEWOFSECTION @ 40; MmmapViewOfsection (x, x, x, x, x, x, x, x)
Page: 004B4AA9 MOV [EBP-24H], EAX
Page: 004B4AAC CMP EAX, EBX
Page: 004B4AAE JL LOC_5267FF
Page: 004B4AB4 LEA EAX, [EBP-1CH]
Note the next 210 parameter below, similar to a FLAG. Later, you will find that if the parameter is not equal to 210, the mapped PEB address will not generate a random value, but always in the 7FFDF000 position as before.
Page: 004B4AB7 Push EAX
Page: 004B4AB8 PUSH 210H; Pay attention to this parameter!
Page: 004B4ABD PUSH ESI
Page: 004B4Abe Call_MicreatePeborteb @ 12; MicreatePeborteb (x, x, x)
Really completed
_Micreatepeborteb @ 12 functions
Page: 004B01AE CALL _EXALLOCATEPOOLWITHTAG @ 12; ExallocatePoolwithtag (x, x, x)
Page: 004B01B3 MOV ESI, EAX
Page: 004B01B5 TEST ESI, ESI
Page: 004B01B7 JZ LOC_52678E
Page: 004B01BD MOV EAX, [EBP ARG_8]
Page: 004B01C0 MOV ECX, [EBP ARG_8]
Page: 004B01C3 and Eax, 0FFFH
Page: 004B01C8 NEG EAX
Page: 004B01CA SBB EAX, EAX
Page: 004B01CC NEG EAX
Page: 004B01CE SHR ECX, 0CH
Page: 004B01FB CMP [EBP ARG_8], 210H
Page: 004B0202 JZ LOC_4B4A0A
This is compared to the parameters of the 210 and the stack, if the stack is not 210?
Page: 004B0208 LOC_4B0208:; Code Xref: micreatepeborteb (x, x, x) 48adj
Page: 004B0208 MOV EDI, [EBP ARG_C]
Page: 004B020B MOV Eax, _mmhighestuseraddress
Page: 004B0210 PUSH EDI
Page: 004B0211 PUSH DWORD PTR [EBX 11CH]
Page: 004B0217 Add Eax, 0FFFFF0001H
Page: 004B021C Push 1000H
Page: 004B0221 PUSH EAX
Page: 004B0222 MOV EAX, [EBP ARG_8]
Page: 004B0225 Add Eax, 0FFFH
Page: 004B022A and Eax, 0FFFFF000H
Page: 004B022F Push EAX
Page: 004B0230 Call_MifindemptyAddressRangedowntreE @ 20; MifindemptyaddressRangedownTree (x, x, x, x, x) Page: 004B0235 TEST EAX, EAX
Page: 004B0237 MOV [EBP ARG_C], EAX
Page: 004B023A JL LOC_5267A5
The key is here
Page: 004B4A0A LOC_4B4A0A:; Code XREF: MicroBorteb (x, x, x) 66j
Page: 004B4A0A MOV EDI, _MMHIGHESTUSERADDRESS
Always 7FFEFFFFF
Page: 004B4A10 LEA EAX, [EBP VAR_C]
Page: 004B4A13 PUSH EAX
Page: 004B4A14 Add EDI, 0FFFF0001H
At this time, EDI is 7FFE0000
Page: 004B4A1A Call_KequeryTickCount @ 4; KequeryTickCount (x)
Page: 004B4A1F MOV EAX, [EBP VAR_C]
Page: 004B4A22 and Eax, 0fh
Only the value of the last byte, for example, 0C
Page: 004B4A25 CMP EAX, 1
Seeing Eax is not 01 at this time.
Page: 004B4A28 MOV [EBP VAR_C], EAX
Page: 004B4A2B Jbe Loc_4b4928
If you jump to the process
Page: 004B4A31 LOC_4B4A31:; Code XREF: Micretepeborteb (x, x, x) 4792j
Page: 004B4A31 SHL EAX, 0CH
Page: 004B4A34 SUB EDI, EAX
Page: 004B4A36 LEA EAX, [EDI 0FFFH]
Page: 004B4A3C Push EAX
Page: 004B4A3D Push EDI
Page: 004B4A3E Push EBX
Page: 004B4A3F MOV [EBP VAR_4], EDI
Page: 004B4928 Loc_4b4928:; code Xref: micreatepeborteb (x, x, x) 488fj
If EAX is 1, then change to 2. This avoids the last calculation of 7FFDF000. But 7FFDE000
Page: 004B4928 PUSH 2
Page: 004B492A POP EAX
Page: 004B492B MOV [EBP VAR_C], EAXPage: 004B492E JMP LOC_4B4A31
Because KeetickCount is a time count of the process, it is not possible to predict.
.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
After analysis, we know, if Eax is randomly coming out of 1, 2, then the address of the last allocated PEB is 7ffde000, which is to avoid the previous
The appearance of the 7FFDF000 address allows the previous heap to use the code. :)
1, 2 7ffde000
3 7ffdd000
4 7FFDC000
5 7FFDB000
67ffda000
77ffd9000
8 7ffd8000
97ffd7000
A 7FFD6000
B7FFD5000
C7FFD4000
D7FFD3000
E 7FFD2000
F 7FFD1000
0 7ffde000
All possible values that can be seen in PEB can be seen, and you can see the highest probability of 7ffde000, 1/8, and others are 1/16. :), but even if this is, it is impossible to stabilize.
2. Protection for TOP SEH
Microsoft has made significant adjustments to the code of the function setunhandleDexceptionFilter. SetunHandledExceptionFilter is a function exported in kernel32.dll to set up a filter exception handle, this return function does not replace the system's default exception handler, but only has some prerequisites, operation results Also sent to the system default exception handler, this process is equivalent to a screening of exceptions.
The SETUNHANDEXCEPTIONFILTER call mode of the function is:
LPTOP_LEVEL_EXCEPTION_FILTER setunhandledExceptionFilter
LPTOP_LEVEL_EXCEPTION_FILTER LPTOPLEVELEXCEPTIONFILTER
);
The unique parameter of this function is the address of the callback function that needs to be set, and the return value is the address of the back-off function set up. This function is not hung before the original returned function, but replaces the original return function with this new return function. If the address parameter is specified as NULL, the system will remove this "screen" and send exceptions to the default exception handler. WinXP SP2 has changed this function. Before replacing the original return function, first, first, the address of the new return function will be encrypted, and then replace the original return function. Decrypt it before returning the original return function address. This function is relatively simple:
.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
Here is the first to encrypt the address lptoplevelexceptionfilter
.TEXT: 7C81038B Push [EBP LPTOPLEVELEXCEPTIONFILTER]
.Text: 7C81038E Call RtlencodePointer
Then, after the addition of the addresses and the original return function address are written, that is, write the addresses after encryption to
In a global variable, return the original return function address in the global variable.
.TEXT: 7C810393 Push Eax; Value
.Text: 7c810394 Push Offset Target; Target
.text: 7c810399 Call InterlocKedexchange
; Decrypt before returning to the original return function address, because the original return function address has also been encrypted
.Text: 7C81039E Push EAX
.TEXT: 7C81039F Call RTLDECodePointer
.TEXT: 7C8103A4 POP EBP
.TEXT: 7C8103A5 RETN 4
.TEXT: 7C8103A5 setunhandledExceptionFilter Endp; sp = -8
.TEXT: 7C8103A5
It used to write the address of the return function directly into the global variable, and there is no process. It can be seen that we will never use the stack overflow by overwriting the function pointer as before. And after analysis, WinXP SP2 has been encrypted for all global pointers. Then look down how it is encrypted on the address.
RTLENCODEPOINTER and RTLDECodePointer are all virtually NTDLL.DLL exports, and RTLENCODepointer is used to encrypt a pointer, and RTLDECodePointer is used to decrypt a pointer. In fact, the entire encrypted decryption process is very simple, and when encrypted, the pointer and one random number are different, and when decrypt, the random number is different.
Encryption: Point = Point ^ Rand
Decryption: Point = Point ^ Rand
RAND is a random number associated with the process, by calling the function ZWQueryInformationProcess, each process is different.
To avoid you again, you will post these two functions.
The code of the RTLENCodePointer function is as follows:
.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
; Call function ZWQUERYINFORMATIONPROCESS gets a random number associated with the process
.text: 7c93391c Push ECX
.TEXT: 7C93391D PUSH 0
.TEXT: 7C93391F PUSH 4
Here, you get the address of a temporary variable in the stack, and finally the random number will be saved in this temporary variable.
.Text: 7c933921 Lea Eax, [EBP VAR_4]
.text: 7c933924 Push EAX
.TEXT: 7C933925 PUSH 24H; Subfunction code is 0x24
.TEXT: 7C933927 Push 0FFFFFFFH
.Text: 7c933929 Call ZwQueryInformationProcess
The resulting random number and pointer are different, so that encryption is completed.
; The process of decryption is the same as the process of encryption
.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
The function RTLDECodePointer is simpler, but directly to RTLENCODepointer execution, because the process of decryption is identical to the process of encryption.
.text: 7c93393d RTLDECodePointer Proc Near
; Below, four jump statements do not work
.Text: 7C93393D MOV EDI, EDI
.TEXT: 7C93393F PUSH EBP
.Text: 7C933940 MOV EBP, ESP
.TEXT: 7C933942 POP EBP
The following statements go to the RTLENCODEPOINTER execution, in fact, it is equivalent to calling the function directly.
Rtlencodepointer
.text: 7c933943 JMP Short RtlencodePointer
.TEXT: 7C933943 RTLDECodePointer Endp
ZwQueryInformationProcess finally calls a system call, go to the kernel run, and finally call the function ntqueryInformationProcessProcess in the kernel, and call the function of the function to 0x24. The sub-function directly removes a random number saved in the process and copies it into a temporary variable in the user stack. If the random number is 0, it is also necessary to regenerate the random number based on the system time, which is usually when the process is just started, and the random number is 0, which will regenerate the random number. This random number is unable to guess because the random number is related to the process created by the process. This function is exported in ntoskrnl.exe, and the function code related to this feature is: Page: 004970cc LOC_4970CC:
; The following code gets the only random number of the process, the sub-function code is 0x24
Page: 004970CC CMP EDI, EDX; Case 0x24
Page: 004970 CE JNZ LOC_497349
Page: 004970D4 CMP DWORD PTR [EBP 8], 0FFFFFFFH
Page: 004970D8 JNZ LOC_4977B8
; The following code gets the address that saves the random number.
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
The EDI address saved is a random number associated with the process, and this random number is taken here.
Page: 004970F3 MOV Eax, [EDI]
Page: 004970F5 Test Eax, EAX
Page: 004970F7 JZ LOC_4B2379
{
If the random number is 0, the random number is re-obtained, and the process of obtaining the random number is as follows:
1, first get the time of the system,
2, then make this time and a value in the system kernel constantly different or operation,
I have a random number
Page: 004B2379
Page: 004B2379 LOC_4B2379:
Get system time
Page: 004b2379 Lea Eax, [EBP-3CH]
Page: 004B237C Push EAX
Page: 004B237D Call KequerySystemTime
Page: 004B2382 DB 3EH
Get a global variable in the system kernel, the global variable estimate is also a random number
Page: 004B2382 MOV Eax, DS: 0FFDFF020H
Page: 004B2388 MOV ECX, [EAX 518H] Page: 004B238E x ECX, [EAX 4B8H]
; Will result in the random number and the system time is different or
Page: 004b2394 xor ECX, [EBP-38H]
Page: 004B2397 XOR ECX, [EBP-3CH]
; Save the calculated random number in the above-related global variables, the EDI is saved.
;This address.
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
Reversion to LOC_4970EA, once again get the random number of current generated, if the resulting random number is
; 0, will also be generated.
Page: 004B23BD JMP LOC_4970EA
}
After getting a random number, copy it to a temporary variable in the user stack, the ESI saves this temporary
The address of the variable. At this point, it has been obtained with a process-related random number, and the random number is the creation time of the process.
Related.
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
Here we have fully understood the entire random number of acquisition processes. The random number is related to the creation time of the process, and we can see that we can't guess the random number. However, this random number is only generated when the process is created, and until the process ends, the random number will not change. So, if we can get the random number, it is still available before the end of the process. For example, we can do it with our jump address or by overflowing it to the highest overflow processing address, you can use it as before.
However, this method is unavailable for remote overflow. But if you can overwrite the import table or static data segment, it is the ideal situation. However, the import table of the system DLL cannot be modified, but the import table of the general program is also changeable, so it is still the possibility of utilization. If there is a pointer to some functions in the static data segment, it can be covered, so that the general purpose to be utilized if this is existed.
3, VEH Link Pointer _RTLPCalloutentryList protection
We know a trick that the heap overflow is often used to modify the chain pointer of VEH. This is good in XP SP0 and SP1. But SP2 also blocks this path. XP_SP2
Abnormal processing process
KiuseRexceptionDispatcher
|
________Rtldispatchexception
|
___________RtlcallvectoredExceptionHandlers
In SP2, the pointer is located
.DATA: 7C99C320 _RTLPCalloutentryList DD 0; DATA XREF: LDRPInitializeProcess (x, x, x, x, x) 2efo
.DATA: 7C99C320; LDRPInitializeProcess (x, x, x, x) 2f9w ...
Let's take a look at the RTLCallVectoredExceptionHandlers function.
.Text: 7c95779c; __stdcall RTLCallVectorDExceptionHandlers (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
Here, the VEH's linked list is empty, that is, do you point to yourself. If you are empty, you don't have to say it, and you will turn to the call to the pointer.
.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: RTLINIALIZESOURCE (X) 21C3DJ
.Text: 7C962DC1 Push DWORD PTR [ESI 8]
The code does not explain so much, you can see that the pointer must be decoded before use, and this function has been explained before.
.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, 0FFFFFFFH
.TEXT: 7C962DD2 JZ Short Loc_7c962dee
.Text: 7C962DD4 MOV ESI, [ESI]
So you can see the skills that cannot be used in SP2 to cover the VEH linked list pointer.
Give a general pointer to XP SP1
XP SP1
.Text: 77f60c26; __stdcall RTLCallVectorDExceptionHandlers (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
Here we can see the value of 77FC3210 in EDI, then compare the contents of the address, if no veh is installed, then this address
The content is also 77fc3210, and it will not jump to 77f7f485. If the user has Veh installed, it will jump to 77f7f485
.TEXT: 77F60C37 JNZ LOC_77F7F485.TEXT: 77F60C3D XOR Al, Al
.TEXT: 77F60C3F
.Text: 77f60c3f Loc_77f60c3f:; code Xref: rtLinitializResource (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)
Key Next to this section, remove the installed processing function addresses from 77FC3210
.Text: 77f7f49e mov esi, _rtlpcalloutentryList
.TEXT: 77F7F4A4 JMP Short Loc_77F7F4B4
.TEXT: 77F7F4A6 LOC_77F7F4A6:; Code Xref: rtLinitializResource (x) 1B6BCJ
.Text: 77f7f4a6 Lea Eax, [EBP-8]
.TEXT: 77F7F4A9 PUSH EAX
.text: 77f7f4aa call dword ptr [ESI 8]
Here ESI points to the struct _vectored_exception_node structure, its 0x08 is m_pfnvectoredhandler
Seeing this here, we will understand, if we can control the pointer, then we can control the process of the program!
.TEXT: 77F7F4AD CMP EAX, 0FFFFFFFFH
.TEXT: 77F7F4B4 LOC_77F7F4B4:; Code Xref: rtLinitializResource (x) 1B6AAJ
.TEXT: 77F7F4B4 CMP ESI, EDI.TEXT: 77F7F4B6 JNZ SHORT LOC_77F7F4A6
XP_SP0
_RtlpCalloutentryList is located in 77fc5bd0
.DATA: 77FC5BD0 _RTLPCALLOUTRYLIST DD 0; DATA XREF: RTLCallVectoredExceptionHandlers (x, x) 6o
.DATA: 77FC5BD0; RTLCallVectoredExceptionHandlers (x, x) br ...
4, cookie protection of the stack
Now the structure of the stack
HEAP_ENTRY STRUC; (SIZEOF = 0x8)
Size dw?
PREVSIZE DW?
Cookie DB?
Flags DB?
UnuseDBYTES DB?
INDEX DB?
HEAP_ENTRY ENDS
Air idle block management structure
_RTL_HEAP_FREE_BLOCK STRUC; (SIZEOF = 0x10)
Entry _rtl_heap_entry?
List List_ENTRY?
_RTL_HEAP_FREE_BLOCK ENDS
Contrast a previous stack structure
Typedef struct _heap_entry {
/ * 0x00 * / ushort size;
/ * 0x02 * / ushort previoussize;
/ * 0x04 * / uchar segmentindex;
/ * 0x05 * / uchar flags;
/ * 0x06 * / uchar unusedbytes;
/ * 0x07 * / uchar smaltagindex;
} Heap_ENTRY, * PHEAP_ENTRY;
You can see that SmallTagIndex is discarded, and segmentIndex moves back, and the 5th byte is changed to cookie.
Cookie's calculation formula:
The pile of head addresses are different from the cookies in the overall management structure of the HEAP.
code show as below
.Text: 7C931487 MOV EDX, ESI; ESI point Heap_Entry
.Text: 7c931489 SHR EDX, 3
.Text: 7c93148c xor Eax, EAX
.TEXT: 7C93148E MOV Al, [EDI 4]; Cookie processing, at this time, EDI points to the heap management structure allocation head
.text: 7c931491 xor Eax, EDX
.Text: 7C931493 MOV [ESI 4], Al
Then we can see that cookies have 256 possible values, so you don't have to spend your heart thinking about how to override cookies without being wrong. Of course, there are many ways to bypass cookie detection.
XP SP2 has not changed much for the management of the heap, but the heap management structure, a stack, and some fields of the Lookaside table have changed, such as some fields become DW from DD, so add a few Field. These details are not here.