Windbg K命令分析

Windbg K命令分析

RtlpWalkFrameChain

ULONG
RtlpWalkFrameChain (
    OUT PVOID *Callers,
    IN ULONG Count,
    IN ULONG Flags,
    )
ULONG LowLimit;//[ebp-20h]
ULONG HightLimit;//[ebp-24h]
ULONG* ebp;//[ebp-28h]
int i;//[ebp-2Ch]
PETHREAD thread;//[ebp-30h][ebp-3Ch]
PKTRAP_FRAME frame;//[ebp-34h]
PTEB teb;//[ebp-38h]

if(!Flags)
{
        ebp=EBP
        if(!RtlpCaptureStackLimits(&LowLimit,&HighLimit))
                return 0;
}
if(Flags == 1)
{
        thread=PsGetCurrentThread();
        frame=thread->TrapFrame
        teb=thread->Teb;
        if(!teb || frame < MmSystemRangeStart || frame <= thread.StackLimit || thread->ApcStateIndex == 1)
                return 0;
        if(KeGetCurrentIrql()?=2)
                return 0;
        LowLimit = teb->NtTib.StackLimit;
        HightLimit = teb->NtTib.StackBase;
        ebp=teb->ebp;
        if(LowLimit>=HightLimit)
                return 0;
        if(HightLimit<=MmUserProbeAddress (805599d4))
                ....
}
for(i=0;i<Count;i++)
{
        if(ebp>=HightLimit)
                break;
        ............
        ULONG nextebp=[ebp];
        Callers[i]=[ebp+4];
        ebp=nextebp;
}

X86栈分析

  栈回溯,一是用于调试,便于分析程序流程,另一是用于开发中,可以观察调用者是否自身进程,之前用过也简要分析过RtlpWalkFrameChain的原理,然而无论是用该函数,还是用dbghelp的stackwalk函数,都是利用微软的x86栈桢结构。如果自己简单做用ebp链完全可以,然而这样做了你会发现得到的结果,比Windbg k命令得到的回溯栈少好多,这是为什么呢,这篇帖子及该系列就来探究这个问题。
  dbghelp.dll是用c++写的因此分析流程比较麻烦,请做好心理准备,本文先从简单ebp链入来思考这一问题。众所周知,微软函数(vs系)编译器会自动生成栈桢结构,而api本身也是这种结构,下面以2层调用为例:

funcA:
xor edi,edi  //对齐字节
push ebp    //开始创建当前层栈桢
mov ebp,esp
sub esp,X
......
    push param1
    push param2
    ..........
    push paramN
    call funcB
        funcB:
        xor edi,edi  //对齐字节
        push ebp
        mov ebp,esp            -------------假设执行到这里
        sub esp,Y
        .......
        mov esp,ebp
        pop ebp
        ret ?
......
mov esp,ebp   //开始销毁栈桢
pop ebp
ret ?

这样一来,栈中的布局:

..........
———————
Y


———————
funcB.ebp                          ->     当前ebp指向
———————
funcB.nexteip
———————
funcB.paramN
———————
.........
———————
funcB.param1
———————
X


———————
funcA.ebp
———————
funcA.paramN
———————
.........
———————
funcA.param1
———————
nexteip
———————
.........

这种布局是重复的,因此当前ebp位置处可以看做链表(而标准函数中ebp一般是一成不变的,用于保存栈桢):

ebp:
+00  上层ebp
+04  返回地址
+08  paramN
.......
+??  分配的栈变量空间
+??  上上层ebp
+??  上上层返回地址
..............

再来看非标准栈桢(不使用ebp)

..........
———————
Y


———————
funcB.nexteip
———————
funcB.paramN
———————
.........
———————
funcB.param1
———————
X


———————
funcA.paramN
———————
.........
———————
funcA.param1
———————
nexteip
———————
.........

  所以根据该链表很容易得到调用栈,然而我们的程序中并不能遇到“理想”的情况,因为以上布局是假设函数存在创建和销毁栈桢的过程,假设该函数没用ebp做栈桢,或者压根没使用栈桢,那么这种方法肯定是行不通了。然而windbg却仍能正确找到,这是为什么呢?最直观的想法是解析了上述栈桢,计算出X,Y param1-N,然后把他们所占的从2个相邻ebp节点中除去,剩下的部分,探测是否返回地址,然后根据解析的返回地址位置重构每一层函数栈,当然返回地址处前一条指令必须是函数调用指令,而且调用地址应该是下一层函数起始位置。

K命令分析

  为了验证这个问题,需要研究windbg执行原理,而这就需要用windbg动态调试windbg。由于知道windbg必从栈桢得到返回地址,因此可以对ReadProcessMemory下断:

0:000> g
(a34.17b8): Break instruction exception - code 80000003 (first chance)
eax=cccccccc ebx=7f1e9000 ecx=00000000 edx=00000001 esi=00d11069 edi=002dfe38
eip=00d11360 esp=002dfd68 ebp=002dfe38 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
*** WARNING: Unable to verify checksum for teststack.exe
teststack!func3:
00d11360 cc              int     3

观察到ebp以后,在另一个windbg中对齐下断:

bp kernelbase!ReadProcessMemory ".if poi(esp+8)!=0x2dfe38 {gc}"

再在之前的windbg运行k命令,即可断下,此时查看调用栈:

078dc44c 67ad1432 KERNELBASE!ReadProcessMemory
078dc470 678f4fb0 dbgeng!LiveUserDebugServices::ReadVirtual+0x22
078dc4b0 678f4e6c dbgeng!LiveUserTargetInfo::ReadVirtualUncached+0xa0
078dc4d4 67a29116 dbgeng!LiveUserTargetInfo::ReadVirtual+0x3c
078dc500 676c94fe dbgeng!SwReadMemory+0xe6
078dc528 67702d02 dbghelp!DbhStackServices::ReadMemory+0x2e
078dc548 67736cd7 dbghelp!DbsX86WalkFrame::readMemory+0x32
078dc568 677501c8 dbghelp!CDiaStackWalkHelper::readMemory+0x27
078dc5d0 6775058c dbghelp!StackWalkVM::Operator+0x1b8
078dc600 677506ea dbghelp!StackWalkVM::Statement+0x4c
078dc624 677247ce dbghelp!StackWalkVM::next+0x4a
078dc7f4 67749d07 dbghelp!CStackFrameTrav::next+0x6e
078dc80c 6774b294 dbghelp!CFrameDataFrameTrav::next+0x67
078dc850 6774b6ff dbghelp!CStackTrav::next+0x524
078dc864 6773af4a dbghelp!CStackTrav::execute+0x4f
078dcb6c 67708695 dbghelp!CDiaFrameData::execute+0xda
078dcc08 67703787 dbghelp!DbsX86StackUnwinder::ApplyUnwindInfo+0x2f5
078dcc30 67701dde dbghelp!DbsX86StackUnwinder::Unwind+0x187
078dcc40 676e761e dbghelp!DbsStackUnwinder:bhUnwind+0x19e
078dcd40 676e7a24 dbghelp!PickX86Walk+0x17e
078dda10 67a29ee4 dbghelp!StackWalk64+0x154
078de6a4 67a2a52c dbgeng!TargetInfo::GetTargetStackFrames+0x6a4
078de738 679b4ce2 dbgeng!DoStackTrace+0x1cc
078de7bc 679b6369 dbgeng!WrapParseStackCmd+0x162
078de8a0 679b71a9 dbgeng!ProcessCommands+0xad9
078de8e4 678e76c9 dbgeng!ProcessCommandsAndCatch+0x49
078ded7c 678e794a dbgeng!Execute+0x2b9
078dedac 00c090f6 dbgeng!DebugClient::ExecuteWide+0x6a
078dee58 00c09612 windbg!ProcessCommand+0x156
078dfe78 00c0b8f6 windbg!ProcessEngineCommands+0xb2

其中dbghelp中使我们最感兴趣的,如果对dbgeng中的函数下断,会发现做了N层循环,每执行一次StackWalk64就会得到一层调用栈。

// TargetInfo::GetTargetStackFrames:
for ( i = 0; i < *(_DWORD *)(a1 + 24); ++i )
  {
    v36 = 0;
    v35 = 0;
    v33 = 1;
    if ( g_DebugClrStack )
      dprintf(L"Frame %d\n", i);
    if ( *(_DWORD *)(a1 + 16) )
    {
      FrameInfo::SetToDefault((FrameInfo *)(*(_DWORD *)(a1 + 16) + 152 * i));
      *(_DWORD *)(*(_DWORD *)(a1 + 16) + 152 * i + 132) = i + *(_DWORD *)(a1 + 44);
    }
    if ( *(_DWORD *)(a1 + 20) )
      qmemcpy((void *)(*(_DWORD *)(a1 + 20) + 0xA70 * i), &v104, 0xA70u);
    if ( v39 && v40 )
    {
      if ( v38 && !ProcessInfo::IsClrMethod(**(ProcessInfo ***)(a1 + 8), v53) )
      {
        if ( !StackWalk64(
                **(_DWORD **)(v105 + 44),
                *(HANDLE *)(**(_DWORD **)(a1 + 8) + 88),
                *(HANDLE *)(*(_DWORD *)(a1 + 8) + 40),
                (LPSTACKFRAME64)&v49,
                &v104,
                SwReadMemory,
                SwFunctionTableAccess,
                SwGetModuleBase,
                SwTranslateAddress) )
          break;
        v35 = 1;
      }
      if ( *(_DWORD *)(a1 + 16) )
        v20 = ProcessClrFrame(
                v39,
                i,
                (struct _CROSS_PLATFORM_CONTEXT *)&v104,
                v40,
                (struct FrameInfo *)(*(_DWORD *)(a1 + 16) + 152 * i),
                (struct _tagSTACKFRAME64 *)&v49);
      else
        v20 = ProcessClrFrame(v39, i, (struct _CROSS_PLATFORM_CONTEXT *)&v104, v40, 0, (struct _tagSTACKFRAME64 *)&v49);
      v33 = v20;
      if ( v20 < 0 )
      {
        v21 = FormatStatusCode(v20);
        ErrOut(L"Managed frame processing failed, %s\n", v21);
        v33 = 1;
      }
      v36 = v33 == 0;
    }
    v38 = 0;
    if ( v33 == 1 || !v40 )
    {
      if ( !v35
        && !StackWalk64(
              **(_DWORD **)(v105 + 44),
              *(HANDLE *)(**(_DWORD **)(a1 + 8) + 88),
              *(HANDLE *)(*(_DWORD *)(a1 + 8) + 40),
              (LPSTACKFRAME64)&v49,
              &v104,
              SwReadMemory,
              SwFunctionTableAccess,
              SwGetModuleBase,
              SwTranslateAddress) )
        break;
      v38 = 1;
      if ( i && *(_DWORD *)(a1 + 20) )
        qmemcpy((void *)(*(_DWORD *)(a1 + 20) + 2672 * i), &v104, 0xA70u);
      if ( v39 && !v40 )
      {
        if ( *(_DWORD *)(a1 + 16) )
          v22 = ProcessClrFrame(
                  v39,
                  i,
                  (struct _CROSS_PLATFORM_CONTEXT *)&v104,
                  0,
                  (struct FrameInfo *)(*(_DWORD *)(a1 + 16) + 152 * i),
                  (struct _tagSTACKFRAME64 *)&v49);
        else
          v22 = ProcessClrFrame(v39, i, (struct _CROSS_PLATFORM_CONTEXT *)&v104, 0, 0, (struct _tagSTACKFRAME64 *)&v49);
        v34 = v22;
        if ( v22 < 0 )
        {
          v23 = FormatStatusCode(v22);
          ErrOut(L"Managed frame processing failed, %s\n", v23);
        }
        v36 = v34 == 0;
      }
      if ( *(_DWORD *)(a1 + 16) )
      {
        if ( !v36 )
        {
          v32 = (UnmanagedFrameInfo *)TypedData::operator new(0x98u, (void *)(*(_DWORD *)(a1 + 16) + 152 * i));
          v112 = 0;
          if ( v32 )
            UnmanagedFrameInfo::UnmanagedFrameInfo(v32);
          v112 = -1;
        }
        if ( **(_DWORD **)(v105 + 44) == 332 )
        {
          v24 = 152 * i;
          v25 = *(_DWORD *)(a1 + 16);
          *(_DWORD *)(v25 + v24 + 144) = v62;
          *(_DWORD *)(v25 + v24 + 148) = v63;
        }
        v26 = *(_DWORD *)(a1 + 16) + 152 * i + 8;
        *(_DWORD *)v26 = v49;
        *(_DWORD *)(v26 + 4) = v50;
        *(_QWORD *)(v26 + 8) = v53;
        *(_DWORD *)(v26 + 16) = v54;
        *(_DWORD *)(v26 + 20) = v55;
        *(_DWORD *)(v26 + 24) = v58;
        *(_DWORD *)(v26 + 28) = v59;
        *(_QWORD *)(v26 + 32) = v66;
        *(_DWORD *)(v26 + 120) = v68;
        v27 = v26 + 72;
        *(_DWORD *)v27 = v69;
        *(_DWORD *)(v27 + 4) = v70;
        *(_DWORD *)(v27 + 8) = v71;
        *(_DWORD *)(v27 + 12) = v72;
        *(_DWORD *)(v27 + 16) = v73;
        *(_DWORD *)(v27 + 20) = v74;
        v28 = v26 + 96;
        *(_DWORD *)v28 = 0;
        *(_DWORD *)(v28 + 4) = 0;
        *(_DWORD *)(v28 + 8) = 0;
        *(_DWORD *)(v28 + 12) = 0;
        *(_DWORD *)(v28 + 16) = 0;
        *(_DWORD *)(v28 + 20) = 0;
        qmemcpy((void *)(v26 + 40), &v67, 0x20u);
      }
      if ( **(_DWORD **)(v105 + 44) == 512 && v107 && *(_DWORD *)(v107 + 8) == 1 )
      {
        if ( *(_QWORD *)&v49 >= 0xE0000000FFA00000ui64 && *(_QWORD *)&v49 < 0xE0000000FFA02000ui64 )
        {
          v29 = *(_QWORD *)&v49
              - __PAIR__(
                  -536870912 - ((unsigned int)(*(_DWORD *)(v107 + 1408) > 0xFFA00000) + *(_DWORD *)(v107 + 1412)),
                  -6291456 - *(_DWORD *)(v107 + 1408));
          v49 -= -6291456 - *(_DWORD *)(v107 + 1408);
          v50 = HIDWORD(v29);
        }
        if ( i
          && *(_DWORD *)(a1 + 16)
          && *(_QWORD *)(*(_DWORD *)(a1 + 16) + 152 * (i - 1) + 8) >= 0xE0000000FFA00000ui64
          && *(_QWORD *)&v49 < 0xE0000000FFA02000ui64 )
        {
          v30 = 152 * (i - 1);
          v31 = *(_DWORD *)(a1 + 16);
          *(_DWORD *)(v31 + v30 + 16) = v49;
          *(_DWORD *)(v31 + v30 + 20) = v50;
        }
      }
    }
    if ( *(_DWORD *)(a1 + 40) || *(_DWORD *)(a1 + 36) & 0x10 )
    {
      if ( *(_DWORD *)(a1 + 16) )
        FrameInfo::OutputFrameOfTrace(
          i,
          *(_DWORD *)(a1 + 24),
          *(struct FrameInfo **)(a1 + 16),
          *(struct _CROSS_PLATFORM_CONTEXT **)(a1 + 20),
          (struct _CROSS_PLATFORM_CONTEXT *)&v104,
          *(_DWORD *)(a1 + 40),
          &v106);
    }
}

*(_DWORD *)(a1 + 24)正是需要回溯的层数,而且该函数还支持clr(C#)函数回溯,而最重要的操作还是在stackwalk64中,先来看dbghelp的帮助文件:

BOOL WINAPI StackWalk64(
  __in          DWORD MachineType,
  __in          HANDLE hProcess,
  __in          HANDLE hThread,
  __in_out      LPSTACKFRAME64 StackFrame,
  __in_out      PVOID ContextRecord,
  __in          PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  __in          PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  __in          PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
  __in          PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
// MachineType:处理器类型
// IMAGE_FILE_MACHINE_I386 0x014c Intel x86
// IMAGE_FILE_MACHINE_IA64 0x0200 Intel Itanium Processor Family (IPF)
// IMAGE_FILE_MACHINE_AMD64 0x8664 x64 (AMD64 or EM64T)
// hProcess 目标进程句柄
// hThread 目标线程句柄
// StackFrame 提供一个初始化过得STACKFRAME64,包括eip,ebp,esp等 ,用于迭代得到回溯栈
// ContextRecord 提供一个初始化的CONTEXT结构 ,用于非x86架构
// ReadMemoryRoutine 读取内存的例程,用于解析栈桢
// FunctionTableAccessRoutine 访问运行时函数表的例程,x86下,该函数返回FPO_DATA结构体指针,该函数解析目标地址处函数的栈桢信息
// GetModuleBaseRoutine 根据给定虚拟地址求模块基址的例程
// TranslateAddress 用于16bit地址翻译例程

typedef struct _FPO_DATA
{  
    DWORD ulOffStart;  函数起始位置
    DWORD cbProcSize;  函数大小
    DWORD cdwLocals;   局部变量栈大小
    WORD cdwParams;    参数个数
    WORD cbProlog  :8; Prolog字节数
    WORD cbRegs  :3;   保存寄存器个数
    WORD fHasSEH  :1;  是否SEH
    WORD fUseBP  :1;   是否使用EBP
    WORD reserved  :1;
    WORD cbFrame  :2;  栈帧类型
} FPO_DATA,  *PFPO_DATA
FRAME_FPO 0 FPO frame
FRAME_NONFPO 3 Non-FPO frame
FRAME_TRAP 1 Trap frame
FRAME_TSS 2 TSS frame
typedef struct _tagSTACKFRAME64 {
    ADDRESS64   AddrPC;               // EIP StIIP RIP
    ADDRESS64   AddrReturn;           // 返回地址
    ADDRESS64   AddrFrame;            // EBP AddrBstore RBP/RDI
    ADDRESS64   AddrStack;            // ESP SP RSP
    ADDRESS64   AddrBStore;           // RsBSP
    PVOID       FuncTableEntry;       //  FPO_DATA 指针
    DWORD64     Params[4];            // 推导函数参数
    BOOL        Far;                  // WOW far call
    BOOL        Virtual;              // 是否Virtual Frame
    DWORD64     Reserved[3];
    KDHELP64    KdHelp;                      //用于内核回调桢
} STACKFRAME64, *LPSTACKFRAME64;

BOOL __stdcall StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress)
{
  v22 = 0;
  DbhStackServices::DbhStackServices(&a2);
  if ( StackFrame )
  {
    v13 = hProcess;
    v14 = hThread;
    dword_31142D0 = MachineType;
    if ( FunctionTableAccessRoutine )
    {
      v16 = FunctionTableAccessRoutine;
    }
    else
    {
      v16 = FunctionTableAccessRoutineLocal;
      v22 = 1;
    }
    if ( GetModuleBaseRoutine )
    {
      v17 = GetModuleBaseRoutine;
    }
    else
    {
      v17 = GetModuleBaseRoutineLocal;
      v22 = 1;
    }
    if ( ReadMemoryRoutine )
      v15 = ReadMemoryRoutine;
    else
      v15 = (PREAD_PROCESS_MEMORY_ROUTINE64)ReadMemoryRoutineLocal;
    if ( TranslateAddress )
      v18 = TranslateAddress;
    else
      v18 = TranslateAddressRoutineLocal;
    if ( !v22 || TrySymInit(hProcess) )
    {
      a1 = 0;
      v11 = DbsStackUnwinder::New(
              (struct DbsStackServices *)&a2,
              MachineType,
              (ACCESS_MODE)StackFrame->AddrPC.Mode,
              &v20,
              3200u,
              &a1);
      if ( !v11 )
      {
        v19 = DbsStackUnwinder::GetFunctionEntryBytes(a1);
        if ( MachineType == 332 )
        {
          v11 = PickX86Walk(a1, (DbhStackServices *)&a2, StackFrame, ContextRecord);
        }
        else if ( ContextRecord )
        {
          v10 = GetTlsPtr();
          v11 = DbsStackUnwinder::DbhUnwind(
                  a1,
                  StackFrame,
                  (unsigned __int16)gApiRevision,
                  (char *)v10 + 96,
                  800u,
                  ContextRecord);
        }
        else
        {
          v11 = 0x80070057;
        }
      }
      if ( a1 )
        (**(void (__thiscall ***)(DbsStackUnwinder *, _DWORD))a1)(a1, 0);
      result = v11 == 0;
    }
    else
    {
      result = 0;
    }
  }
  else
  {
    result = error(0x57u);
  }
  return result;
}

为方便起见,下面的函数只写最简略形式,参数和返回类型后面一步步推导。这里构造了DbhStackServices类,并用传入的参数初始化之,之后用该类生成对应的DbhStackUnwinder类,最后分是否x86分别执行PickX86Walk和DbhUnwind获取回溯信息

class DbsStackServices
{
//虚表
public:
    virtual LONG ReadMemory()=0                //+00h  
    virtual LONG GetModuleBase()=0             //+04h  
    virtual LONG GetFunctionEntry()=0          //+08h  
    virtual LONG GetUnwindInfoFromSymbols      //+0Ch
    virtual LONG FreeUnwindInfoFromSymbols     //+10h
    virtual LONG TranslateToFlatAddress        //+14h
    virtual LONG GetSegmentDescriptor          //+18h
    virtual LONG Status                        //+1Ch
//成员
public:
    HANDLE hProcess;                                //+04h
    HANDLE hThread;                                //+08h
    FARPROC ReadMemoryRoutine;                        //+0Ch
    FARPROC FunctionTableAccessRoutine;                //+10h
    FARPROC GetModuleBaseRoutine;                //+14h
    FARPROC TranslateAddressRoutine;                //+18h
    DWORD mem1;                                        //+1Ch
    DWORD mem2;                                        //+20h
}

class DbhStackServices:DbsStackServices
{
public:
    DbhStackServices();
//虚表覆盖
public:
    virtual LONG ReadMemory();
    virtual LONG GetModuleBase();
    virtual LONG GetFunctionEntry();
//非虚函数
    LONG TranslateToFlatAddress();
}

而栈回溯对象DbsStackUnwinder为基类,其子类根据处理器不同有五类:(微软做的还是很全面的)

DbsIa64StackUnwinder        IA64指令集
DbsPpcBeStackUnwinder        PowerPC指令集
DbsX64StackUnwinder        X64指令集
DbsX86StackUnwinder        X86 32bit
DbsX8616StackUnwinder        X86 16bit
DbsArmStackUnwinder        ARM指令集

分别重写了基类的Start和UpdateAbstractPointers方法

class DbsStackUnwinder
{
//虚表
public:
    virtual ~DbsStackUnwinder();                                                //+00h
    virtual LONG Start(CONTEXT* ContextRecord,DWORD ContextSize)                //+04h
    virtual LONG Unwind()=0;                                                        //+08h
    virtual LONG GetContext(CONTEXT* ContextRecord,DWORD ContextSize)                //+0Ch
    virtual LONG GetUnwindInfo();                                                //+10h
    virtual LONG GetFullUnwindInfoSize();                                        //+14h
    virtual LONG DbhStart(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)        //+18h
    virtual LONG DbhContinue(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)        //+1Ch
    virtual LONG DbhUpdatePreUnwind(STACKFRAME64 * StackFrame);                        //+20h
    virtual LONG DbhUpdatePostUnwind(STACKFRAME64 * StackFrame,LONG status);        //+24h
    virtual LONG SetRestart();                                                        //+28h
    virtual LONG ClearUnwindDerived();                                                //+2Ch
    virtual LONG UpdateAbstractPointers()=0;                                        //+30h
//普通函数
    LONG AdjustForNoReturn();
    LONG DbhGetKdHelp();
    LONG DbgSetKdHelp();
    LONG DbgUnwind();
    LONG DbgStackUnwinder();
    LONG FillMemCache();
    LONG FreeUnwindInfo();
    LONG GetFuncitonEntryBytes();
    LONG GetServices();
    LONG InvalidateMemCache();
    LONG PopMemCache();
    LONG PushAndFillMem();
    LONG PushMemCache();
    LONG ReadMemCache();
    LONG SetImlFlags();
    LONG SetInvalidInstructionPointer();
    LONG StartAdjustForNoReturn();
    LONG UnwindNtKernelCallback();
    LONG UpdateCallPointer();
    void operator delete();
    void operator new(int);
    void operator new(int,void*,long);

    class DeclMemCache<T>
    {
    public:
       ~DeclMemCache<T>();
       void PushAndFill();
       void Pop();
    }
    static __stdcall LONG New();
//成员变量
    DWORD unkonw1;//+004h
    DbsStackServices* StackService;//+008h
    char* MachineName;//+00Ch
    DWORD MachineType;//+010h
    int ContextSize;//+014h
    int FunctionEntryBytes;//+018h  函数入口构成栈桢的字节数
    int u3;//+01Ch
    DWORD ??;//+020h
    DWORD RegSize;//+024h  机器字长
    int u6;//+028h
    BOOL IsVirtualFrame;//+040h
    int ImplFlags;//+044h
    CONTEXT* context;//+048h
    int u24;//+04Ch
    LONGLONG Xbp;//+050h
    LONGLONG RetAddr;//060h
    LONGLONG FrameOffset;//070h
    int u25;
    int u7;//+090h
    KDHELP64 KdHelp;//+098h
    LONGLONG StackUpLimit;//+0D0h
    LONGLONG StackDownLimit;//+0D8h
    int DbhVersion;//+108h
    LONGLONG RsBSP;//+110h
}

class DbsX86StackUnwinder:DbsStackUnwinder
{
public:
    DbsX86StackUnwinder(DbsStackServices* StackService):DbsStackUnwinder(StackService,"X86", 332, 204, 16, 0, 8, 4, 1){...}
//成员变量
public:
    DWORD Dr0;//+11Ch
    DWORD Dr1;//+120h
    DWORD Dr2;//+124h
    DWORD Dr3;//+128h
    DWORD Dr6;//+12Ch
    DWORD Dr7;//+130h
    DWORD SegGs;//+1A4h
    DWORD SegFs;//+1A8h
    DWORD SegEs;//+1ACh
    DWORD SegDs;//+1B0h
    DWORD _Edi;//+1B4h
    DWORD _Esi;//+1B8h
    DWORD _Ebx;//+1BCh
    DWORD _Edx;//+1C0h
    DWORD _Ecx;//+1C4h
    DWORD _Eax;//+1C8h
    DWORD _Ebp;//+1CCh
    DWORD _Eip;//+1D0h
    DWORD SegCs;//+1D4h
    DWORD EFlags;//+1D8h
    DWORD _Esp;//+1DCh
    DWORD SegSs;//+1E0h
    ;//+1E8h
    DWORD ARGS1;//+1ECh
    _FPO_DATA* Fpo;//+204h
    DWORD ARGS2;//+20Ch
    int u133;//+214h DbsX86StackUnwinder::ForceEbpRegion *
    DWORD u1;//+3C8h
}

部分实现:

LONG New(DbsStackServices* StackService,DWORD MachineType,ACCESS_MODE AccessMode,DbsStackUnwinder** OutPtr)
{
    switch(MachineType)
    {
    case 0x1F2:
        *OutPtr = new DbsPpcBeStackUnwinder(StackService);
        break;
    case IMAGE_FILE_MACHINE_IA64:
        *OutPtr = new DbsIa64StackUnwinder(StackService);
        break;
    case IMAGE_FILE_MACHINE_AMD64:
        *OutPtr = new DbsX64StackUnwinder(StackService);
        break;
    case IMAGE_FILE_MACHINE_ARM:
    case IMAGE_FILE_MACHINE_THUMB:
    case 0x1C4:
        *OutPtr = new DbsArmStackUnwinder(StackService);
        break;
    case IMAGE_FILE_MACHINE_I386:
        switch(AccessMode)
        {
        case AddrModeFlat:
            *OutPtr = new DbsX86StackUnwinder(StackService);
            break;
        case AddrMode1616:
            *OutPtr = new DbsX8616StackUnwinder(StackService);
            break;
        }
        *OutPtr = new DbsX86StackUnwinder(StackService);
        break;
    }
}
LONG DbhUnwind(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)
{
    LONG status;
    if(StackFrame->Virtual)
    {
        IsVirtualFrame = TRUE;
        status=DbhContinue(StackFrame,ContextRecord);
        if(status)
            return status;
        status=Unwind();
        if(status)
            return status;
        status=GetContext(ContextRecord,u6);
        if(status)
            return status;
    }
    else
    {
        status=DbhStart(StackFrame,ContextRecord);
        if(status)
            return status;
    }
    memset(StackFrame->Params,0,sizeof(StackFrame->Params));
    status=DbhUpdatePreUnwind(StackFrame);
    if(status)
        return status;
    status=Unwind();
    if(status)
    {
        u24=u25=0;
    }
    status=DbhUpdatePostUnwind(StackFrame,status);
    return status;
}

LONG DbhGetKdHelp(STACKFRAME64* StackFrame)
{
    memcpy(&KdHelp,&StackFrame->KdHelp,sizeof(KdHelp));
}
virtual LONG Start(CONTEXT* ContextRecord,DWORD ContextSize)//+04h
{
    if(context && ContextSize >= this->ContextSize)
    {
        memcpy(context,ContextRecord,this->ContextSize);

    }
}
virtual LONG GetContext(CONTEXT* ContextRecord,DWORD ContextSize)//+0Ch
{
    if(context && ContextSize >= this->ContextSize)
    {
        memcpy(ContextRecord,context,this->ContextSize);
        SetRestart();
        UpdateAbstractPointers();
        UpdateCallPointer();
    }
}
virtual LONG DbhStart(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)//+18h
{
    if(!DbhGetKdHelp(StackFrame))
    {
        memset(&StackFrame->AddrBStore,0,sizeof(StackFrame->AddrBStore));
        memset(&StackFrame->AddrReturn,0,sizeof(StackFrame->AddrReturn));
        StackFrame->FuncTableEntry=0;
        memset(StackFrame->Params,0,sizeof(StackFrame->Params));
        StackFrame->Virtual=TRUE;
        memset(StackFrame->Reserved,0,sizeof(StackFrame->Reserved));
    }
}
virtual LONG DbhContinue(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)//+1Ch
{
    if(!DbhGetKdHelp(StackFrame))
    {
        LONG status=Start(ContextRecord,ContextSize);
    }
}

DWORD gApiRevision = 5;
DWORD g_ForceLopWalk;
DWORD g_AllowLopSymInfo;
DWORD g_AllowLopRetSearch;
DWORD g_AllowLopWalk;
DWORD g_AllowVc7Fpo;

DWORD g_NumForceEbpRegions;
DWORD* g_ForceEbpRegions;

enum
{
    AllowVc7Fpo=0x1,
    AllowLopWalk=0x2,
    AllowLopSymInfo=0x4,
    AllowLopRetSearch=0x8,
    ForceLopWalk=0x10,
};

LRESULT WINAPI PickX86Walk(DbsStackUnwinder* pStackUnwinder,DbsStackServices* pStackServices,LPSTACKFRAME64 pInitStackFrame,LPCONTEXT ContextRecord)
{
    CONTEXT Context;
    if(!ContextRecord)
    {
        RtlZeroMemory(&Context,0,sizeof(CONTEXT));
        Context.Eip = pInitStackFrame->AddrPC.Offset;
        Context.Esp = pInitStackFrame->AddrStack.Offset;
        if(LODWORD(pInitStackFrame->Reserved[0]) != 0 && HIDWORD(pInitStackFrame->Reserved[0]) == 0xEB)
            Context.Ebp = pInitStackFrame->Reserved[0];
        ContextRecord = &Context;
    }
    LRESULT status;
    if(pInitStackFrame->AddrPC.Mode = AddrModeFlat)
    {
        pStackService->IsFlatMode = true;
        pStackUnwinder->SetImplFlags((g_ForceLopWalk?0x10:0)|(g_AllowLopRetSearch?8:0)|(g_AllowLopSymInfo?4:0)|
            (g_AllowLopWalk?2:0)|(g_AllowVc7Fpo?1:0));
        pStackUnwinder->SetForceEbpRegions(g_NumForceEbpRegions,g_ForceEbpRegions);
        status = pStackUnwinder->DbhUnwind(pInitStackFrame,gApiRevision,TlsData.info,sizeof(TlsData.info),ContextRecord);
        if(!status)
        {
            if(g_ForceLopWalk && !g_AllowLopSymInfo)
                pInitStackFrame->FuncTableEntry = 0;
            else
                pInitStackFrame->FuncTableEntry = pStackService->FunctionTableAccessRoutine(pStackService->hProcess,
                    pInitStackFrame->AddrPC.Offset,pInitStackFrame->AddrPC.Offset);
        }
    }
    else
    {
        status = pStackUnwinder->DbhUnwind(pInitStackFrame,gApiRevision,TlsData.info,sizeof(TlsData.info),ContextRecord);
    }
    return status;
}

PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutineLocal;
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutineLocal;
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutineLocal;
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddressRoutineLocal;


BOOL WINAPI StackWalk64(
    DWORD MachineType,
    HANDLE hProcess,
    HANDLE hThread,
    LPSTACKFRAME64 StackFrame,
    LPCONTEXT ContextRecord,
    PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
    PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
    PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
    PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
    )
{
    BOOL UseDefault = FALSE,NeedInnerFunc = FALSE;
    DbhStackServices StackServices;
    if(!StackFrame)
        return FALSE;
    StackServices.hProcess = hProcess;
    StackServices.hThread = hThread;
    if(FunctionTableAccessRoutine)
    {
        StackServices.FunctionTableAccessRoutine = FunctionTableAccessRoutine;
    }
    else
    {
        StackServices.FunctionTableAccessRoutine = FunctionTableAccessRoutineLocal;
        NeedInnerFunc = TRUE;
    }
    if(GetModuleBaseRoutine)
    {
        StackServices.GetModuleBaseRoutine = GetModuleBaseRoutine;
    }
    else
    {
        StackServices.GetModuleBaseRoutine = GetModuleBaseRoutineLocal;
        NeedInnerFunc = TRUE;
    }
    if(ReadMemoryRoutine)
    {
        StackServices.ReadMemoryRoutine = ReadMemoryRoutine;
    }
    else
    {
        StackServices.ReadMemoryRoutine = ReadMemoryRoutineLocal;
    }
    if(TranslateAddress)
    {
        StackServices.TranslateAddress = TranslateAddress;
    }
    else
    {
        StackServices.TranslateAddress = TranslateAddressRoutineLocal;
    }
    if(!NeedInnerFunc)
    {
        DbsStackUnwinder* StackUnwinder = NULL;
        LRESULT status;
        status = DbsStackUnwinder::New(&StackService,MachineType,StackFrame->AddrPC.Mode,&StackUnwinder);
        if(!status)
        {
            StackService.FpoDataSize = StackUnwinder->GetFunctionEntryBytes();
            if(MachineType == IMAGE_FILE_MACHINE_I386)
            {
                PickX86Walk(StackUnwinder,&StackService,StackFrame,ContextRecord);
            }
            else if(ContextRecord)
            {
                StackUnwinder->DbhUnwind(StackFrame,gApiRevision,TlsData.info,sizeof(TlsData.info),ContextRecord);
            }
        }
        if(StackUnwinder)
            StackUnwinder->~DbsStackUnwinder();
    }
    return 0;
}