元始天尊 发表于 2015-8-9 21:53:43

windbg k命令初探(一)

本帖最后由 元始天尊 于 2015-8-9 21:54 编辑

    栈回溯,一是用于调试,便于分析程序流程,另一是用于开发中,可以观察调用者是否自身进程,之前用过也简要分析过RtlpWalkFrameChain的原理http://www.0xaa55.com/forum.php?mod=viewthread&tid=1447&extra=,然而无论是用该函数,还是用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返回地址
+08paramN
.......
+??分配的栈变量空间
+??上上层ebp
+??上上层返回地址
..............

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


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


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

    所以根据该链表很容易得到调用栈,然而我们的程序中并不能遇到“理想”的情况,因为以上布局是假设函数存在创建和销毁栈桢的过程,假设该函数没用ebp做栈桢,或者压根没使用栈桢,那么这种方法肯定是行不通了。然而windbg却仍能正确找到,这是为什么呢?最直观的想法是解析了上述栈桢,计算出X,Y param1-N,然后把他们所占的从2个相邻ebp节点中除去,剩下的部分,探测是否返回地址,然后根据解析的返回地址位置重构每一层函数栈,当然返回地址处前一条指令必须是函数调用指令,而且调用地址应该是下一层函数起始位置。
    为了验证这个问题,需要研究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=0023ss=002bds=002bes=002bfs=0053gs=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::DbhUnwind+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;            // 推导函数参数
    BOOL      Far;                  // WOW far call
    BOOL      Virtual;            // 是否Virtual Frame
    DWORD64   Reserved;
    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);
                }
        }


从x86执行流程来看,重点还是在Unwind函数中,在其中对STACKFRAME64的迭代得到结果,其他的部分我会在下次叙述。

元始天尊 发表于 2015-8-23 22:20:08

windbg 命令初探(二)

这几个礼拜一直忙,所以请原谅一直没有时间研究~~~~

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 && HIDWORD(pInitStackFrame->Reserved) == 0xEB)
                        Context.Ebp = pInitStackFrame->Reserved;
                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;
}



还在编辑中~~~
页: [1]
查看完整版本: windbg k命令初探(一)