Initially released in the QQ space, see:PROLOG and epilog in seh, Contains textures.
All Codes Using seh need to build stack tokens that support Exception Processing, while repeated codes should be extracted into functions. Microsoft will naturally not be an exception. For this reason, the system provides PROLOG and epilog series. Similar functions have many versions, but they are similar. This time, you don't need a debugger to analyze the two functions _ seh_prolog4_gs and _ seh_epilog4_gs to see how they work with Stack rollback structures that support exceptions.
Let's take a look at Prolog. This is the code for calling the kernel function kidispatchexception _ seh_prolog4_gs,
000 push 0F8h004 push offset off_8488DCE0008 call __SEH_prolog4_GS
Two parameters are passed before the function is called. One is the size of the stack to be retained, and the other is the pointer.
Let's look at the Function Code itself. The detailed comments are behind the code,
; two instrucitons before call it. ; ; take KiDispatchException as example, ; ; 000 push 0F8h ; it's used as a stack size ; 004 push offset off_8488DCE0 ; it's pointer to scope table entry. __SEH_prolog4_GS proc near arg_4= dword ptr 8000 push offset __except_handler4004 push large dword ptr fs:0008 mov eax, [esp+8+arg_4] ; so now there are 5 values in stack. ; ; f8 ; 8488dce0 ; return address of call ; _except_handler4 ; old fs:0 ; ; follwing is additional information ; to be pointer to EXCEPTION_POINTERS ; to be esp value ; to be cookie value008 mov [esp+8+arg_4], ebp ; push current ebp value into place ; where 0f8 is here.008 lea ebp, [esp+8+arg_4] ; update ebp to current frame pointer008 sub esp, eax ; reserve stack008 push ebx00C push esi010 push edi014 mov eax, ___security_cookie014 xor [ebp-4], eax ; encrypt pointer to scope table entry014 xor eax, ebp014 mov [ebp-1Ch], eax ; store cookie value014 push eax018 mov [ebp-18h], esp ; store current esp; middle part018 push dword ptr [ebp-8] ; push "return address" of current call ; for next ret instruction01C mov eax, [ebp-4] ; mov [ebp-4] to [ebp-8]01C mov dword ptr [ebp-4], 0FFFFFFFEh ; initialize try level01C mov [ebp-8], eax ; so far, the stack is following: ; ; ebp ; -1 ; 8488DCE0 xor ___security_cookie ; _except_handler4 ; old fs:[0] ; to be pointer to EXCEPTION_POINTERS ; current esp value ; cookie value (___security_cookie xor ebp) ; ... ; ebx ; esi ; edi ; cookie value ; return address to parent function01C lea eax, [ebp-10h]01C mov large fs:0, eax ; update fs:[0] to current frame01C retn ; return to parent function.
Since the annotations are more detailed, I will not talk much about them. I will add a few images.
The stack after the function starts to execute two push commands,
The stack at the center is as follows. Pay attention to the numerical order.
Execute the stack before the final retn, at this time (ebp-10) has built the exception stack stacking structure, (ebp-18) (ebp-1c) also assigned the corresponding value.
Next, analyze the epilog to see how kidispatchexception calls it,
; why is there 118?11C lea esp, [ebp-118h] ; sizeof exception_frame + F8(includes additional information) + sizeof( ebx + esi + edi + cookie ) ; ebp - (10+F8+10)000 call __SEH_epilog4_GS000 retn 14h
Correct the stack pointer to the appropriate position, which is actually the position of the stack after the _ seh_prolog4_gs function returns. Then call the function _ seh_epilog4_gs. Note that the call command will push the returned address to the stack.
Let's look at the implementation part of the function,
__SEH_epilog4_GS proc near000 mov ecx, [ebp-1Ch] ; cookie value (___security_cookie xor ebp)000 xor ecx, ebp000 call @__security_check_cookie@4 ; ; cmp ecx, ___security_cookie ; jnz ___report_gsfailure ; retn000 jmp __SEH_epilog4 __SEH_epilog4_GS endp
Check whether the cookie is damaged. If no problem exists, jump to _ seh_epilog4.
__SEH_epilog4 proc near000 mov ecx, [ebp-10h] ; restore old fs:[0]000 mov large fs:0, ecx000 pop ecx ; return address of parent function-04 pop edi ; another cookie value besides [ebp-1c]-08 pop edi-0C pop esi-10 pop ebx-14 mov esp, ebp ; restore esp and ebp000 pop ebp-04 push ecx000 retn __SEH_epilog4 endp
This function is much simpler than Prolog, restoring FS: [0], restoring registers, and returning to the place where _ seh_epilog4_gs is called.
The analysis of these two functions eventually evolved into an understanding of the data structure in the stack. The observed data structure in IDA is as follows, and comments are added to the members:
EXCEPTION_POINTERS struc ; (sizeof=0x8, standard type)ExceptionRecord dd ? ; pointer to ExceptionRecordContextRecord dd ? ; pointer to ContextRecordEXCEPTION_POINTERS ends
CPPEH_RECORD struc ; old_esp dd ? ; esp positionexc_ptr dd ? ; pointer to EXCEPTION_POINTERSprev_er dd ? ; pointer to old fs:[0]handler dd ? ; exception handlermsEH_ptr dd ? ; pointer to scope table entry (might be encrytped)disabled dd ? ; try levelCPPEH_RECORD ends
Note that the order of stack data is from high to low, and the data members in the above structure are from low to high, which is the opposite. In addition, cppeh_record actually has two different values, one of which is on old_esp to put the cookie value. The other is under disabled and used to store the previous EBP value (compared with the previous figure ). In the exception handling function, you can access this data structure to obtain the information you need.
This reminds me of a sentence in the Mythical man-month. "Show me your flowchart while hiding your table. I am still confused. Show me the flowchart hidden in your table. They are so obvious. "The" table "here refers to the data structure, which ultimately determines the implementation of the Code.