DeAssembly with VC8.0 Copyright (c) 2012, getok.org 转载请注明出处。

_CXXTHROWEXCEPTION


首先是 _CxxThrowException 函数,这个函数很简单,以下还原的代码基本就是源代码的完全呈现:

EHExceptionRecord ExceptionTemplate = {
    0xe06d7363, // ExceptionCode
    1,      // ExceptionFlags (注:EH_UNWIND 是 2)
    0,      // ExceptionRecord*
    0,      // ExceptionAddress
    3,      // NumberParamters
    {       // params
        0x19930520, // magicNumber
        0,      // pExceptionObject
        0,      // pThrowInfo
    }
};

_CxxThrowException (void* pExceptionObject, const _s_ThrowInfo *pThrowInfo)
{
    EHExceptionRecord ThisException;

    ThisException = ExceptionTemplate;
    ThisExcepion.params.pExceptionObject = pExceptionObject;
    ThisException.params.pThrowInfo = pThrowInfo;

    if (pThrowInfo && pThrowInfo->attributes & 8 != 0)
        ThisException.params.magicNumber = 0x1994000;

    __imp__RaiseException(&ThisException,
                              ThisException.ExceptionFlags,
                              ThisException.NumberParamters,
                              &ThisException.magicNumber);

}

ThrowInfo 包含异常对象的信息,如析构函数和类型信息。

typedef struct
{
    unsigned int attribues;
    void (*pmfnUnwind)(void);           // destructor
    int (*pForwardCompat) (...);
    const _s_CatchableTypeArray *pCatchableTypeArray;
} _s_ThrowInfo;

当我们写下抛出异常的代码:

throw E();

会被转为:

E e = E();
_CxxThrowException(&e, &_ThrowInfoOfe);

小结:_CxxThrowException 把异常对象和 ThrowInfo 打包在 EXCEPTION_RECORD 中交给内核,最后会调用一系列内核的函数,并进入内核态。内核处理中断。这里跳过所有内核代码。因为最终内核会调用 KiUserExceptionDispatcher。调用流程如下:

_CxxThrowException                            (msvcr80d.dll)
    _RaiseException                           (kernel32.dll)
        [Kernel Interrupt]
            KiUserExceptionDispatcher          (ntdll.dll)
                RtlDispatchException           (ntdll.dll)
                    ExcuteHandler              (ntdll.dll)

KIUSEREXCEPTIONDISPATCHER, RTLDISPATCHEXCEPTION, EXCUTEHANDLER


KiUserExceptionDispatcher, RtlDispatchException 和 ExcuteHandler 都属于 Windows SEH 中的内容。首先看 KiUserExceptionDispatcher,这个函数主要调用 RtlDispatchException, 这个调用开始遍历 FS:[0] 指向的 exception handler 链表知道找到异常处理程序。如果程序处理了异常,则 RtlDispatchException 不会返回。如果它返回了,则只有两种可能:要么调用 NtContinue 使进程继续,要么产生另一个异常。

 KiUserExceptionDispatcher( PEXCEPTION_RECORD pExcptRec, CONTEXT *pContext )
 {
     DWORD retValue;

     // Note: If the exception is handled, RtlDispatchException() never returns
     if ( RtlDispatchException( pExceptRec, pContext ) )
         retValue = NtContinue( pContext, 0 );
     else
         retValue = NtRaiseException( pExceptRec, pContext, 0 );

     EXCEPTION_RECORD excptRec2;

     excptRec2.ExceptionCode = retValue;
     excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
     excptRec2.ExceptionRecord = pExcptRec;
     excptRec2.NumberParameters = 0;

     RtlRaiseException( &excptRec2 );
 }

再看 RtlDispatchException, 首先调用 RtlpGetRegistrationHead() 获得 pRegistrationFrame, 然后调用 RtlpExecuteHandlerForException。

 int RtlDispatchException( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )
 {
     DWORD   stackUserBase;
     DWORD   stackUserTop;
     PEXCEPTION_REGISTRATION pRegistrationFrame;
     DWORD hLog;

     // Get stack boundaries from FS:[4] and FS:[8]
     RtlpGetStackLimits( &stackUserBase, &stackUserTop );

     pRegistrationFrame = RtlpGetRegistrationHead();

     while ( -1 != pRegistrationFrame )
     {
         PVOID justPastRegistrationFrame = &pRegistrationFrame + 8;
         if ( stackUserBase > justPastRegistrationFrame )
         {
             pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
             return DISPOSITION_DISMISS; // 0
         }

         if ( stackUsertop < justPastRegistrationFrame )
         {
             pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
             return DISPOSITION_DISMISS; // 0
         }

         if ( pRegistrationFrame & 3 )   // Make sure stack is DWORD aligned
         {
             pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
             return DISPOSITION_DISMISS; // 0
         }

         if ( someProcessFlag )
         {
             // Doesn't seem to do a whole heck of a lot.
             hLog = RtlpLogExceptionHandler( pExcptRec, pContext, 0,
                                             pRegistrationFrame, 0x10 );
         }

         DWORD retValue, dispatcherContext;

         retValue= RtlpExecuteHandlerForException(pExcptRec, pRegistrationFrame,
                                                  pContext, &dispatcherContext,
                                                  pRegistrationFrame->handler );

         // Doesn't seem to do a whole heck of a lot.
         if ( someProcessFlag )
             RtlpLogLastExceptionDisposition( hLog, retValue );

         if ( 0 == pRegistrationFrame )
         {
             pExcptRec->ExceptionFlags &= ~EH_NESTED_CALL;   // Turn off flag
         }

         EXCEPTION_RECORD excptRec2;

         DWORD yetAnotherValue = 0;

         if ( DISPOSITION_DISMISS == retValue )
         {
             if ( pExcptRec->ExceptionFlags & EH_NONCONTINUABLE )
             {
                 excptRec2.ExceptionRecord = pExcptRec;
                 excptRec2.ExceptionNumber = STATUS_NONCONTINUABLE_EXCEPTION;
                 excptRec2.ExceptionFlags = EH_NONCONTINUABLE;
                 excptRec2.NumberParameters = 0
                 RtlRaiseException( &excptRec2 );
             }
             else
                 return DISPOSITION_CONTINUE_SEARCH;
         }
         else if ( DISPOSITION_CONTINUE_SEARCH == retValue )
         {
         }
         else if ( DISPOSITION_NESTED_EXCEPTION == retValue )
         {
             pExcptRec->ExceptionFlags |= EH_EXIT_UNWIND;
             if ( dispatcherContext > yetAnotherValue )
                 yetAnotherValue = dispatcherContext;
         }
         else    // DISPOSITION_COLLIDED_UNWIND
         {
             excptRec2.ExceptionRecord = pExcptRec;
             excptRec2.ExceptionNumber = STATUS_INVALID_DISPOSITION;
             excptRec2.ExceptionFlags = EH_NONCONTINUABLE;
             excptRec2.NumberParameters = 0
             RtlRaiseException( &excptRec2 );
         }

         pRegistrationFrame = pRegistrationFrame->prev;  // Go to previous frame
     }

     return DISPOSITION_DISMISS;
 }


 PEXCEPTION_REGISTRATION
 RtlpGetRegistrationHead( void )
 {
     return FS:[0];
 }

_RtlpExecuteHandlerForException 会把自己的 exception handler 存在 EDX,然后跳转到 ExcuteHandler:

 _RtlpExecuteHandlerForException:    // Handles exception (first time through)
     MOV     EDX,XXXXXXXX
     JMP     ExecuteHandler

 RtlpExecutehandlerForUnwind:        // Handles unwind (second time through)
     MOV     EDX,XXXXXXXX

ExcuteHandler 真正调用我们的 exception handler,在调用前,安装了一个 exception handler:(因此这个 exception handler 实际上在我们的 exception handler 的前面,当处理完异常,要将 FS:[0] 指向我们原先的那个,也就是这个的previous)

 int ExecuteHandler( PEXCEPTION_RECORD pExcptRec
                     PEXCEPTION_REGISTRATION pExcptReg
                     CONTEXT * pContext
                     PVOID pDispatcherContext,
                     FARPROC handler ) // Really a ptr to an _except_handler()

     // Set up an EXCEPTION_REGISTRATION, where EDX points to the
     // appropriate handler code shown below
     PUSH    EDX
     PUSH    FS:[0]
     MOV     FS:[0],ESP

     // Invoke the exception callback function
     EAX = handler( pExcptRec, pExcptReg, pContext, pDispatcherContext );

     // Remove the minimal EXCEPTION_REGISTRATION frame 
     MOV     ESP,DWORD PTR FS:[00000000]
     POP     DWORD PTR FS:[00000000]

     return EAX;
 }

对于每个线程,其 FS:[0] 总是指向 exception handler 的链表头。ExcuteHandler 调用这些 exception handler。MSVC 为异常调用链上的每个函数都安插了 exception handler,这些 exception handler 都会将函数的 funcinfo 传给 _CxxFrameHandler 并调用它。类似下面的代码:

_ehhandler:
    mov eax, OFFSET _ehfuncinfo
    jmp _CxxFrameHandler3

_CXXFRAMEHANDLER3


以下是 exception handler 的原型及其返回值,定义在 excpt.h。

/*
 * Exception disposition return values.
 */
typedef enum _EXCEPTION_DISPOSITION {
    ExceptionContinueExecution,
    ExceptionContinueSearch,
    ExceptionNestedException,
    ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;

EXCEPTION_DISPOSITION __cdecl _except_handler (
    __in struct _EXCEPTION_RECORD *_ExceptionRecord,
    __in void * _EstablisherFrame,
    __inout struct _CONTEXT *_ContextRecord,
    __inout void * _DispatcherContext
    );

前面说过,异常调用链上的每个函数都会生成一个 exception handler,比如叫做 _ehhandler,那么调用流程将是:

ExcuteHandler                              (ntdll.dll)
    _ehhandler                             (our code)
        _CxxFrameHandler3                  (msvcr80d.dll)
            __InternalFrameHandler         (msvcr80d.dll)

下图展示了 _CxxFrameHandler3 的伪代码,它将会调用 __InternalFrameHandler:

_CxxFrameHandler3(EHExceptionRecord * pExcept, 
        EHRegistrationNode * pRN, 
        void * pContext, 
        void * pDC)

{
    EXCEPTION_DISPOSITION result;
    DWORD pFuncInfo;

    CLD

       // eax 就是 funcinfo 的地址
    mov dword ptr [pFuncInfo], eax

    result = __InternalCxxFrameHandler(pExcept, pRN, pContext, pDC, pFuncInfo, 0, 0, 0);

    return result;
}

参数 EHExceptionRecord 与 winnt.h 中的 EXCEPTION_RECORD 是一样的结构,只不过这个是 msvcr 使用的。里面都是包含了异常对象的指针及其类型信息(_s_ThrowInfo)。

参数 EHRegistrationNode 的结构如下:

typedef struct {
    EHRegistrationNode *pNext;
    void *frameHandler;
    int state;
} EHRegistrationNode;

这是对线程的 SEH 结构添加一个 state 域的结果:

typedef struct {
    EXCEPTION_REGISTRATION *prev;
    DWORD handler;
} EXCEPTION_REGISTRATION;

每个线程的FS:[0]总是指向 EXCEPTION_REGISTRATION 链表的表头,EXCEPTION_REGISTRATION 结构被放在每个函数的栈顶。如果函数有 try 块,在 EXCEPTION_REGISTRATION 上面还放着一个 id,也就是 EHRegistrationNode 中的 state。这样,这个结构体就扩展为 EHRegistrationNode。线程的 FS:[0] 依旧指向 EHRegistrationNode 链表的表头。

这意味着:pRN + sizeof(EHRegistrationNode) + 4 (EBP),亦即 pRN + 0x0C 就是目标函数的 EBP! 这是异常处理结束后激活 catch 块所在函数栈帧的关键!

关于 FUNCINFO


这是编译器内建的一个数据结构:

typedef struct {
    unsigned int  magicNumber;
    int  maxState;
    const _s_UnwindMapEntry  *pUnwindMap;
    unsigned int  nTryBlocks;
    const _s_TryBlockMapEntry  *pTryBlockMap;
    unsigned int  nIPMapEntries;          // not used in x86
    void  *pIPtoStateMap;                 // not used int x86
    const _s_ESTypeList *pESTypeList;     // VC7+ only
    int  EHFlags;
} _s_FuncInfo;

pUnwindMap 就是通常所说的 unwind_table,pTryBlockMap 就是 tryblock_table。

__INTERNALFRAMEHANDLER


这个函数首先判断是不是Unwinding,如果不是,会判断有无 TryBlock,如果有,会调用 FindHandler,否则返回继续;若当前是在Unwinding,则会调用 _FrameUnwindToState。

以下是还原后的C代码,这个函数的还原度跟 _CxxThrowException 一样,基本就是源代码的原貌:

__InternalCxxFrameHandler(EHExceptionRecord *pExcept, 
        EHRegistrationNode *pRN, 
        _CONTEXT *pContext, 
        void *pDC, 
        const _s_FuncInfo *pFuncInfo, 
        int CatchDepth, 
        EHRegistrationNode *pMarkerRN, 
        unsigned char recursive)
{
    DWORD pfn;

        if (_getptd()->_cxxReThrow != 0 ||
        pExcept->ExceptionCode == 0xe06d7363 ||
        pExcept->ExceptionCode == 0x80000026 ||
        (pFuncInfo->magicNumber & 0x1FFFFFFF) < 0x19930521 ||
        pFuncInfo->EHFlags & 1 == 0)
    {
        if (pExcept->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT == 0)
        {
            if (pFuncInfo->nTryBlocks == 0 && 
                               ((pFuncInfo->magicNumber & 0x1FFFFFFF) < 0x19930521 ||
                                 pFuncInfo->pESTypeList == 0))
                 return ExceptionContinueSearch;

            pfn = pExcept->params.pThrowInfo->pForwardCompat;

            if (pExcept->ExceptionCode != 0xe06d7363 ||
                pExcept->NumberParameters < 3 ||
                pExcept->params.magicNumber <= 0x19930522 ||
                pfn == 0)
                 FindHandler(pExcept, pRN, pContext, pDC, 
                                              pFuncInfo, recursive, CatchDepth, pMarker);
            else
                 return (*pfn)(pExcept, pRN, pContext, pDC, 
                                            pFuncInfo, CatchDepth, pMarkerRN, recursive);
        }
        else
        {
            if (pFuncInfo->maxState == 0 || CatchDepth != 0)
                    return ExceptionContinueSearch;

            __FrameUnwindToState(pRN, pDC, pFuncInfo, -1);
        }   
    }

    return ExceptionContinueSearch;
}

其中, _ptiddata 定义在 mtdll.h 中,_getptd() 定义在 tidtable.cpp 中。

EXCEPTION_UNWIND_CONTEXT 表示正在进行栈回退,定义在 exsup.inc:

EXCEPTION_UNWINDING     equ     2
EXCEPTION_EXIT_UNWIND   equ     4
EXCEPTION_UNWIND_CONTEXT equ    EXCEPTION_UNWINDING OR EXCEPTION_EXIT_UNWIND

上述的还原代码中,pExcept->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT == 0 一句,实际上的汇编码是 pExcept->ExceptionFlags & 0×66 == 0,低位的6便是 EXCEPTION_UNWIND_CONTEXT 的值,高位的6不知何物,但不影响理解。

由于涉及了一些 magic number,使上述代码有点晦涩,这里要说的是,我在 VC8.0 下看到的 magicNumber 是 0×19930522。还有,0xe06d7363 是 WinNT 中 C++ 异常代码。

FINDHANDLER


FindHandler 对 TryBlockMap 遍历,若找到 curState 所在的 [tryLow, tryHigh] 闭区间并且 _TypeMatch 成功,表示找到了处理异常的 catch 块,此时会调用 CatchIt。CatchIt 不会返回。调用流程图如下:

FindHandler                                    (msvcr80.dll)
    CatchIt                                    (msvcr80.dll)
        _UnwindNestedFrames                    (msvcr80.dll)
            RtlUnwind                           (ntdll.dll)
                RtlExecutehandlerForUnwind      (ntdll.dll)
                    ExcuteHandler               (ntdll.dll)
                        _enhandler               (our code)

FindHandler 函数很长,包含3层 for 循环,但逻辑很简单:

FindHandler(EHExceptionRecord * pExcept, 
        EHRegistrationNode * pRN, 
        _CONTEXT * pContext, 
        void * pDC, 
        const _s_FuncInfo * pFuncInfo, 
        unsigned char recursive, 
        int CatchDepth, 
        EHRegistrationNode * pMarkerRN)
{
    BOOL IsReThrow = 0;
    BOOL gotMatch = 0;
    int curState;
    const _s_TryBlockMapEntry *pEntry;
    unsigned int end;
    unsigned int curTry;
    const _s_HandlerType *pCatch;
    int catches;
    const _s_CatchableType *pCatchable;
    const _s_CatchableType * const *ppCatchable;
    int catchables;
    void *pSaveException;
    void *pSaveExContext;
    void *pCurrentFuncInfo;

    if (pFuncInfo->maxState > 0x80)
        curState = pRN->state;
    else
        curState = pRN->state & 0x0FF;

    if (curState < -1 || curState >= pFuncInfo->maxState)
        _inconsistency();

    if (pExcept->ExceptionCode == 0x0E06D7363 && 
            pExcept->NumberParameters == 3 &&
            (pExcept->params.magicNumber == 0x19930520 || 
                pExcept->params.magicNumber == 0x19930521 || 
                pExcept->params.magicNumber == 0x19930522) && 
            pExcept->params.pThrowInfo == 0)
    {
        if (_getptd()->_curexception == 0)
            return;

        pExcept = _getptd()->_curexcepion;
        pContext = _getptd()->_curcontext;
        IsReThrow = 1;

        if (_ValidateRead(pExcept, 1) == 0)
            _inconsistency();

        if (pExcept->ExceptionCode == 0x0E06D7363 && 
                pExcept->NumberParameters == 3 &&
                (pExcept->params.magicNumber == 0x19930520 || 
                    pExcept->params.magicNumber == 0x19930521 || 
                    pExcept->params.magicNumber == 0x19930522) &&
                pExcept->params.pThrowInfo == 0)
            _inconsistency();


        if (_getptd()->_curexcspec)
        {
            pCurrentFuncInfo = _getptd()->_curexcspec;
            _getptd()->_curexcspec = 0;

            if (!IsInExceptionSpec(pExcept, pCurrentFuncInfo))
            {
                if (Is_bad_exception_allowed(pCurrentFuncInfo))
                {
                    __DestructExceptionObject(pExcept, 1);
                    throw std::bad_exception("bad exception");
                }
                else
                    terminate();
            }
        }
    }


    if (pExcept->ExceptionCode == 0x0E06D7363 && 
            pExcept->NumberParameters == 3 && 
            (pExcept->params.magicNumber == 0x19930520 || 
                pExcept->params.magicNumber == 0x19930521 ||
                pExcept->params.magicNumber == 0x19930522))
    {
        if (pFuncInfo->nTryBlocks > 0)
        {
            pEntry = _GetRangeOfTrysToCheck(pFuncInfo, CatchDepth, 
                                                           curState, &curTry, &end);

            for ( ; curTry < end; curTry++, pEntry++)
            {
                if (pEntry->tryLow > curState || curState > pEntry->tryHigh)
                    continue;

                pCatch = pEntry->pHandlerArray;
                catches = pEntry->nCatches;

                for ( ; catches > 0; catches--, pCatch++)
                {
              ppCatchable = pExcept->params.pThrowInfo->pCatchableTypeArray                 
                                                   + sizeof(_s_CatchableTypeArray);
              catchables = pExcept->params.pThrowInfo->pCatchableTypeArray->nCatchableTypes;

                    for ( ; catchables > 0; catchables--, ppCatchable++)
                    {
                        pCatchable = *ppCatchable;

                        if (!__TypeMatch(pCatch, 
                                                                 pCatchable, 
                                                                 pExcept->params.pThrowInfo))
                            continue;

                        gotMatch = 1;

                        CatchIt(pExcept, pRN, pContext, pDC, 
                                                         pFuncInfo, pCatch, pCatchable,
                                 pEntry, CatchDepth, pMarkerRN, IsReThrow);

                        goto NextTryBlock;
                    }
                }

            NextTryBlock:
                ;       // nop, continue
            }
        }

        if (recursive)
            __DestructExceptionObject(pExcept, 1);

        if (!gotMatch && (pFuncInfo->magicNumber & 0x1FFFFFFF) >= 0x19930521 &&
                pFuncInfo->pESTypeList && 
                !IsInExceptionSpec(pExcept, pFuncInfo->pESTypeList))
        {
            pSaveException = _getptd()->_curexception;
            pSaveExContext = _getptd()->_curcontext;
            _getptd()->_curexception = pExcept;
            _getptd()->_curcontext = pContext;

            if (pMarkerRN)
                _UnwindNestedFrames(pMarkerRN, pExcept);
            else
                _UnwindNestedFrames(pRN, pExcept);

            __FrameUnwindToState(pRN, pDC, pFuncInfo, -1);

            CallUnexpected(pFuncInfo->pESTypeList);

            _getptd()->_curexception = pExcept;

            _getptd()->_curcontext = pContext;
        }
    }
    else if (pFuncInfo->nTryBlocks > 0)
    {
        if (recursive)
            terminate();
        else
            FindHandlerForForeignException(pExcept, pRN, pContext, 
                                    pDC, pFuncInfo, curState, CatchDepth, pMarkerRN);
    }


    if (_getptd()->_curexcspec)
        _inconsistency();

    return;
}

CATCHIT


这个函数首先调用 _UnwindNestedFrames 对从 “抛出异常的函数” 到 “catch块所在函数的前一个函数” 之间的函数进行 Unwinding 清理局部对象。具体是调用 RtlUnwind,RtlUnwind 会将 ExceptionFlags 已被设置为 EH_UNWINDING,调用 ExcuteHandler,这是第二次调用 exception handler,此时 __InternalCxxFrameHandler 会调用 __FrameUnwindToState。每次对这些函数 Unwinding 后,都会将函数的 EHRegistrationNode 从 FS:[0] 链中移除。

然后调用 _FrameUnwindToState 对 catch 块所在函数进行 Unwinding。

接着调用 CallCatchBlock 执行 catch 块代码。

最后调用 _JumpToContinuation,设置正确的 EBP 和 ESP 后跳到 catch 块所在函数执行。到此为止,异常处理全部结束。

CatchIt(EHExceptionRecord *pExcept,
        EHRegistrationNode *pRN, 
        _CONTEXT *pContext, 
        void *pDC, 
        const _s_FuncInfo *pFuncInfo, 
        const _s_HandlerType *pCatch, 
        const _s_CatchableType *pConv, 
        const _s_TryBlockMapEntry *pEntry, 
        int CatchDepth, 
        EHRegistrationNode *pMarkerRN, 
        unsigned char IsReThrow)
{
    EHRegistrationNode *pEstablisher = pRN;
    void *continuationAddress;

    if (pConv)
        __BuildCatchObject(pExcept, pEstablisher, pCatch, pConv);

    if (pMarkerRN)
        _UnwindNestedFrames(pMarkerRN, pExcept);
    else
        _UnwindNestedFrames(pRN, pExcept);

    __FrameUnwindToState(pEstablisher, pDC, pFuncInfo, pEntry->tryLow);

    pRN->state = pEntry->tryHigh + 1;

    continuationAddress = CallCatchBlock(pExcept, pEstablisher, pContext, 
            pFuncInfo, pCatch->addressOfHandler, CatchDepth, 0x100);

    if (continuationAddress)
        _JumpToContinuation(continuationAddress, pRN);
}

_JUMPTOCONTINUATION


这个函数是异常处理的最后一个函数:设置 catch 块所在函数的 EBP 和 ESP,这些都可以间接从 pRN 中取得。然后就是移除掉第一个 RegistrationNode(在 ExcuteHandler 时插入的),使 FS:[0] 指向 catch 块所在函数的 RegistrationNode,最后一个跳转指令,跳转到 catch 块后面的代码继续程序的执行,异常处理到此结束!

_JumpToContinuation(void * target, EHRegistrationNode * pRN)
{
    long targetEBP;

    targetEBP = pRN + 0x0C;

    // ExceuteHandler (ntdll.dll会加入一个,所以这里取前一个)
    fs:[0] = fs:[0]->prev;

    ebp = targetEBP;
    esp = [pRN - 4];

    jmp target;
}

还有一些函数的反汇编结果我没贴出来,这些函数对理解不是必需的,反而会陷入无穷无尽的细节当中。