找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5208|回复: 1

windbg k命令初探(一)

[复制链接]

307

主题

228

回帖

7349

积分

用户组: 真·技术宅

UID
2
精华
76
威望
291 点
宅币
5599 个
贡献
253 次
宅之契约
0 份
在线时间
949 小时
注册时间
2014-1-25
发表于 2015-8-9 21:53:43 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

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

    栈回溯,一是用于调试,便于分析程序流程,另一是用于开发中,可以观察调用者是否自身进程,之前用过也简要分析过RtlpWalkFrameChain的原理http://www.0xaa55.com/forum.php? ... 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  返回地址
+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节点中除去,剩下的部分,探测是否返回地址,然后根据解析的返回地址位置重构每一层函数栈,当然返回地址处前一条指令必须是函数调用指令,而且调用地址应该是下一层函数起始位置。
    为了验证这个问题,需要研究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:
。。。。。。。。。。。
  1. for ( i = 0; i < *(_DWORD *)(a1 + 24); ++i )
  2.   {
  3.     v36 = 0;
  4.     v35 = 0;
  5.     v33 = 1;
  6.     if ( g_DebugClrStack )
  7.       dprintf(L"Frame %d\n", i);
  8.     if ( *(_DWORD *)(a1 + 16) )
  9.     {
  10.       FrameInfo::SetToDefault((FrameInfo *)(*(_DWORD *)(a1 + 16) + 152 * i));
  11.       *(_DWORD *)(*(_DWORD *)(a1 + 16) + 152 * i + 132) = i + *(_DWORD *)(a1 + 44);
  12.     }
  13.     if ( *(_DWORD *)(a1 + 20) )
  14.       qmemcpy((void *)(*(_DWORD *)(a1 + 20) + 0xA70 * i), &v104, 0xA70u);
  15.     if ( v39 && v40 )
  16.     {
  17.       if ( v38 && !ProcessInfo::IsClrMethod(**(ProcessInfo ***)(a1 + 8), v53) )
  18.       {
  19.         if ( !StackWalk64(
  20.                 **(_DWORD **)(v105 + 44),
  21.                 *(HANDLE *)(**(_DWORD **)(a1 + 8) + 88),
  22.                 *(HANDLE *)(*(_DWORD *)(a1 + 8) + 40),
  23.                 (LPSTACKFRAME64)&v49,
  24.                 &v104,
  25.                 SwReadMemory,
  26.                 SwFunctionTableAccess,
  27.                 SwGetModuleBase,
  28.                 SwTranslateAddress) )
  29.           break;
  30.         v35 = 1;
  31.       }
  32.       if ( *(_DWORD *)(a1 + 16) )
  33.         v20 = ProcessClrFrame(
  34.                 v39,
  35.                 i,
  36.                 (struct _CROSS_PLATFORM_CONTEXT *)&v104,
  37.                 v40,
  38.                 (struct FrameInfo *)(*(_DWORD *)(a1 + 16) + 152 * i),
  39.                 (struct _tagSTACKFRAME64 *)&v49);
  40.       else
  41.         v20 = ProcessClrFrame(v39, i, (struct _CROSS_PLATFORM_CONTEXT *)&v104, v40, 0, (struct _tagSTACKFRAME64 *)&v49);
  42.       v33 = v20;
  43.       if ( v20 < 0 )
  44.       {
  45.         v21 = FormatStatusCode(v20);
  46.         ErrOut(L"Managed frame processing failed, %s\n", v21);
  47.         v33 = 1;
  48.       }
  49.       v36 = v33 == 0;
  50.     }
  51.     v38 = 0;
  52.     if ( v33 == 1 || !v40 )
  53.     {
  54.       if ( !v35
  55.         && !StackWalk64(
  56.               **(_DWORD **)(v105 + 44),
  57.               *(HANDLE *)(**(_DWORD **)(a1 + 8) + 88),
  58.               *(HANDLE *)(*(_DWORD *)(a1 + 8) + 40),
  59.               (LPSTACKFRAME64)&v49,
  60.               &v104,
  61.               SwReadMemory,
  62.               SwFunctionTableAccess,
  63.               SwGetModuleBase,
  64.               SwTranslateAddress) )
  65.         break;
  66.       v38 = 1;
  67.       if ( i && *(_DWORD *)(a1 + 20) )
  68.         qmemcpy((void *)(*(_DWORD *)(a1 + 20) + 2672 * i), &v104, 0xA70u);
  69.       if ( v39 && !v40 )
  70.       {
  71.         if ( *(_DWORD *)(a1 + 16) )
  72.           v22 = ProcessClrFrame(
  73.                   v39,
  74.                   i,
  75.                   (struct _CROSS_PLATFORM_CONTEXT *)&v104,
  76.                   0,
  77.                   (struct FrameInfo *)(*(_DWORD *)(a1 + 16) + 152 * i),
  78.                   (struct _tagSTACKFRAME64 *)&v49);
  79.         else
  80.           v22 = ProcessClrFrame(v39, i, (struct _CROSS_PLATFORM_CONTEXT *)&v104, 0, 0, (struct _tagSTACKFRAME64 *)&v49);
  81.         v34 = v22;
  82.         if ( v22 < 0 )
  83.         {
  84.           v23 = FormatStatusCode(v22);
  85.           ErrOut(L"Managed frame processing failed, %s\n", v23);
  86.         }
  87.         v36 = v34 == 0;
  88.       }
  89.       if ( *(_DWORD *)(a1 + 16) )
  90.       {
  91.         if ( !v36 )
  92.         {
  93.           v32 = (UnmanagedFrameInfo *)TypedData::operator new(0x98u, (void *)(*(_DWORD *)(a1 + 16) + 152 * i));
  94.           v112 = 0;
  95.           if ( v32 )
  96.             UnmanagedFrameInfo::UnmanagedFrameInfo(v32);
  97.           v112 = -1;
  98.         }
  99.         if ( **(_DWORD **)(v105 + 44) == 332 )
  100.         {
  101.           v24 = 152 * i;
  102.           v25 = *(_DWORD *)(a1 + 16);
  103.           *(_DWORD *)(v25 + v24 + 144) = v62;
  104.           *(_DWORD *)(v25 + v24 + 148) = v63;
  105.         }
  106.         v26 = *(_DWORD *)(a1 + 16) + 152 * i + 8;
  107.         *(_DWORD *)v26 = v49;
  108.         *(_DWORD *)(v26 + 4) = v50;
  109.         *(_QWORD *)(v26 + 8) = v53;
  110.         *(_DWORD *)(v26 + 16) = v54;
  111.         *(_DWORD *)(v26 + 20) = v55;
  112.         *(_DWORD *)(v26 + 24) = v58;
  113.         *(_DWORD *)(v26 + 28) = v59;
  114.         *(_QWORD *)(v26 + 32) = v66;
  115.         *(_DWORD *)(v26 + 120) = v68;
  116.         v27 = v26 + 72;
  117.         *(_DWORD *)v27 = v69;
  118.         *(_DWORD *)(v27 + 4) = v70;
  119.         *(_DWORD *)(v27 + 8) = v71;
  120.         *(_DWORD *)(v27 + 12) = v72;
  121.         *(_DWORD *)(v27 + 16) = v73;
  122.         *(_DWORD *)(v27 + 20) = v74;
  123.         v28 = v26 + 96;
  124.         *(_DWORD *)v28 = 0;
  125.         *(_DWORD *)(v28 + 4) = 0;
  126.         *(_DWORD *)(v28 + 8) = 0;
  127.         *(_DWORD *)(v28 + 12) = 0;
  128.         *(_DWORD *)(v28 + 16) = 0;
  129.         *(_DWORD *)(v28 + 20) = 0;
  130.         qmemcpy((void *)(v26 + 40), &v67, 0x20u);
  131.       }
  132.       if ( **(_DWORD **)(v105 + 44) == 512 && v107 && *(_DWORD *)(v107 + 8) == 1 )
  133.       {
  134.         if ( *(_QWORD *)&v49 >= 0xE0000000FFA00000ui64 && *(_QWORD *)&v49 < 0xE0000000FFA02000ui64 )
  135.         {
  136.           v29 = *(_QWORD *)&v49
  137.               - __PAIR__(
  138.                   -536870912 - ((unsigned int)(*(_DWORD *)(v107 + 1408) > 0xFFA00000) + *(_DWORD *)(v107 + 1412)),
  139.                   -6291456 - *(_DWORD *)(v107 + 1408));
  140.           v49 -= -6291456 - *(_DWORD *)(v107 + 1408);
  141.           v50 = HIDWORD(v29);
  142.         }
  143.         if ( i
  144.           && *(_DWORD *)(a1 + 16)
  145.           && *(_QWORD *)(*(_DWORD *)(a1 + 16) + 152 * (i - 1) + 8) >= 0xE0000000FFA00000ui64
  146.           && *(_QWORD *)&v49 < 0xE0000000FFA02000ui64 )
  147.         {
  148.           v30 = 152 * (i - 1);
  149.           v31 = *(_DWORD *)(a1 + 16);
  150.           *(_DWORD *)(v31 + v30 + 16) = v49;
  151.           *(_DWORD *)(v31 + v30 + 20) = v50;
  152.         }
  153.       }
  154.     }
  155.     if ( *(_DWORD *)(a1 + 40) || *(_DWORD *)(a1 + 36) & 0x10 )
  156.     {
  157.       if ( *(_DWORD *)(a1 + 16) )
  158.         FrameInfo::OutputFrameOfTrace(
  159.           i,
  160.           *(_DWORD *)(a1 + 24),
  161.           *(struct FrameInfo **)(a1 + 16),
  162.           *(struct _CROSS_PLATFORM_CONTEXT **)(a1 + 20),
  163.           (struct _CROSS_PLATFORM_CONTEXT *)&v104,
  164.           *(_DWORD *)(a1 + 40),
  165.           &v106);
  166.     }
  167.   }
复制代码
。。。。。。。。。。。。。。。。。

*(_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;


  1. 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)
  2. {
  3.   v22 = 0;
  4.   DbhStackServices::DbhStackServices(&a2);
  5.   if ( StackFrame )
  6.   {
  7.     v13 = hProcess;
  8.     v14 = hThread;
  9.     dword_31142D0 = MachineType;
  10.     if ( FunctionTableAccessRoutine )
  11.     {
  12.       v16 = FunctionTableAccessRoutine;
  13.     }
  14.     else
  15.     {
  16.       v16 = FunctionTableAccessRoutineLocal;
  17.       v22 = 1;
  18.     }
  19.     if ( GetModuleBaseRoutine )
  20.     {
  21.       v17 = GetModuleBaseRoutine;
  22.     }
  23.     else
  24.     {
  25.       v17 = GetModuleBaseRoutineLocal;
  26.       v22 = 1;
  27.     }
  28.     if ( ReadMemoryRoutine )
  29.       v15 = ReadMemoryRoutine;
  30.     else
  31.       v15 = (PREAD_PROCESS_MEMORY_ROUTINE64)ReadMemoryRoutineLocal;
  32.     if ( TranslateAddress )
  33.       v18 = TranslateAddress;
  34.     else
  35.       v18 = TranslateAddressRoutineLocal;
  36.     if ( !v22 || TrySymInit(hProcess) )
  37.     {
  38.       a1 = 0;
  39.       v11 = DbsStackUnwinder::New(
  40.               (struct DbsStackServices *)&a2,
  41.               MachineType,
  42.               (ACCESS_MODE)StackFrame->AddrPC.Mode,
  43.               &v20,
  44.               3200u,
  45.               &a1);
  46.       if ( !v11 )
  47.       {
  48.         v19 = DbsStackUnwinder::GetFunctionEntryBytes(a1);
  49.         if ( MachineType == 332 )
  50.         {
  51.           v11 = PickX86Walk(a1, (DbhStackServices *)&a2, StackFrame, ContextRecord);
  52.         }
  53.         else if ( ContextRecord )
  54.         {
  55.           v10 = GetTlsPtr();
  56.           v11 = DbsStackUnwinder::DbhUnwind(
  57.                   a1,
  58.                   StackFrame,
  59.                   (unsigned __int16)gApiRevision,
  60.                   (char *)v10 + 96,
  61.                   800u,
  62.                   ContextRecord);
  63.         }
  64.         else
  65.         {
  66.           v11 = 0x80070057;
  67.         }
  68.       }
  69.       if ( a1 )
  70.         (**(void (__thiscall ***)(DbsStackUnwinder *, _DWORD))a1)(a1, 0);
  71.       result = v11 == 0;
  72.     }
  73.     else
  74.     {
  75.       result = 0;
  76.     }
  77.   }
  78.   else
  79.   {
  80.     result = error(0x57u);
  81.   }
  82.   return result;
  83. }
复制代码

为方便起见,下面的函数只写最简略形式,参数和返回类型后面一步步推导
这里构造了DbhStackServices类,并用传入的参数初始化之,之后用该类生成对应的DbhStackUnwinder类,最后分是否x86分别执行PickX86Walk和DbhUnwind获取回溯信息
  1. class DbsStackServices
  2. {
  3. //虚表
  4. public:
  5.     virtual LONG ReadMemory()=0                //+00h  
  6.     virtual LONG GetModuleBase()=0             //+04h  
  7.     virtual LONG GetFunctionEntry()=0          //+08h  
  8.     virtual LONG GetUnwindInfoFromSymbols      //+0Ch
  9.     virtual LONG FreeUnwindInfoFromSymbols     //+10h
  10.     virtual LONG TranslateToFlatAddress        //+14h
  11.     virtual LONG GetSegmentDescriptor          //+18h
  12.     virtual LONG Status                        //+1Ch
  13. //成员
  14. public:
  15.     HANDLE hProcess;                                //+04h
  16.     HANDLE hThread;                                //+08h
  17.     FARPROC ReadMemoryRoutine;                        //+0Ch
  18.     FARPROC FunctionTableAccessRoutine;                //+10h
  19.     FARPROC GetModuleBaseRoutine;                //+14h
  20.     FARPROC TranslateAddressRoutine;                //+18h
  21.     DWORD mem1;                                        //+1Ch
  22.     DWORD mem2;                                        //+20h
  23. }

  24. class DbhStackServices:DbsStackServices
  25. {
  26. public:
  27.     DbhStackServices();
  28. //虚表覆盖
  29. public:
  30.     virtual LONG ReadMemory();
  31.     virtual LONG GetModuleBase();
  32.     virtual LONG GetFunctionEntry();
  33. //非虚函数
  34.     LONG TranslateToFlatAddress();
  35. }
复制代码


而栈回溯对象DbsStackUnwinder为基类,其子类根据处理器不同有五类:(微软做的还是很全面的)
DbsIa64StackUnwinder        IA64指令集
DbsPpcBeStackUnwinder        PowerPC指令集
DbsX64StackUnwinder        X64指令集
DbsX86StackUnwinder        X86 32bit
DbsX8616StackUnwinder        X86 16bit
DbsArmStackUnwinder        ARM指令集
分别重写了基类的Start 和UpdateAbstractPointers方法

  1. class DbsStackUnwinder
  2. {
  3. //虚表
  4. public:
  5.     virtual ~DbsStackUnwinder();                                                //+00h
  6.     virtual LONG Start(CONTEXT* ContextRecord,DWORD ContextSize)                //+04h
  7.     virtual LONG Unwind()=0;                                                        //+08h
  8.     virtual LONG GetContext(CONTEXT* ContextRecord,DWORD ContextSize)                //+0Ch
  9.     virtual LONG GetUnwindInfo();                                                //+10h
  10.     virtual LONG GetFullUnwindInfoSize();                                        //+14h
  11.     virtual LONG DbhStart(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)        //+18h
  12.     virtual LONG DbhContinue(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)        //+1Ch
  13.     virtual LONG DbhUpdatePreUnwind(STACKFRAME64 * StackFrame);                        //+20h
  14.     virtual LONG DbhUpdatePostUnwind(STACKFRAME64 * StackFrame,LONG status);        //+24h
  15.     virtual LONG SetRestart();                                                        //+28h
  16.     virtual LONG ClearUnwindDerived();                                                //+2Ch
  17.     virtual LONG UpdateAbstractPointers()=0;                                        //+30h
  18. //普通函数
  19.     LONG AdjustForNoReturn();
  20.     LONG DbhGetKdHelp();
  21.     LONG DbgSetKdHelp();
  22.     LONG DbgUnwind();
  23.     LONG DbgStackUnwinder();
  24.     LONG FillMemCache();
  25.     LONG FreeUnwindInfo();
  26.     LONG GetFuncitonEntryBytes();
  27.     LONG GetServices();
  28.     LONG InvalidateMemCache();
  29.     LONG PopMemCache();
  30.     LONG PushAndFillMem();
  31.     LONG PushMemCache();
  32.     LONG ReadMemCache();
  33.     LONG SetImlFlags();
  34.     LONG SetInvalidInstructionPointer();
  35.     LONG StartAdjustForNoReturn();
  36.     LONG UnwindNtKernelCallback();
  37.     LONG UpdateCallPointer();
  38.     void operator delete();
  39.     void operator new(int);
  40.     void operator new(int,void*,long);

  41.     class DeclMemCache<T>
  42.     {
  43.     public:
  44.        ~DeclMemCache<T>();
  45.        void PushAndFill();
  46.        void Pop();
  47.     }
  48.     static __stdcall LONG New();
  49. //成员变量
  50.         DWORD unkonw1;//+004h
  51.         DbsStackServices* StackService;//+008h
  52.         char* MachineName;//+00Ch
  53.         DWORD MachineType;//+010h
  54.         int ContextSize;//+014h
  55.         int FunctionEntryBytes;//+018h  函数入口构成栈桢的字节数
  56.         int u3;//+01Ch
  57.         DWORD ??;//+020h
  58.         DWORD RegSize;//+024h  机器字长
  59.         int u6;//+028h
  60.         BOOL IsVirtualFrame;//+040h
  61.         int ImplFlags;//+044h
  62.         CONTEXT* context;//+048h
  63.         int u24;//+04Ch
  64.         LONGLONG Xbp;//+050h
  65.         LONGLONG RetAddr;//060h
  66.         LONGLONG FrameOffset;//070h
  67.         int u25;
  68.         int u7;//+090h
  69.         KDHELP64 KdHelp;//+098h
  70.         LONGLONG StackUpLimit;//+0D0h
  71.         LONGLONG StackDownLimit;//+0D8h
  72.         int DbhVersion;//+108h
  73.         LONGLONG RsBSP;//+110h
  74. }

  75. class DbsX86StackUnwinder:DbsStackUnwinder
  76. {
  77. public:
  78.     DbsX86StackUnwinder(DbsStackServices* StackService):DbsStackUnwinder(StackService,"X86", 332, 204, 16, 0, 8, 4, 1){...}
  79. //成员变量
  80. public:
  81.         DWORD Dr0;//+11Ch
  82.         DWORD Dr1;//+120h
  83.         DWORD Dr2;//+124h
  84.         DWORD Dr3;//+128h
  85.         DWORD Dr6;//+12Ch
  86.         DWORD Dr7;//+130h
  87.         DWORD SegGs;//+1A4h
  88.         DWORD SegFs;//+1A8h
  89.         DWORD SegEs;//+1ACh
  90.         DWORD SegDs;//+1B0h
  91.         DWORD _Edi;//+1B4h
  92.         DWORD _Esi;//+1B8h
  93.         DWORD _Ebx;//+1BCh
  94.         DWORD _Edx;//+1C0h
  95.         DWORD _Ecx;//+1C4h
  96.         DWORD _Eax;//+1C8h
  97.         DWORD _Ebp;//+1CCh
  98.         DWORD _Eip;//+1D0h
  99.         DWORD SegCs;//+1D4h
  100.         DWORD EFlags;//+1D8h
  101.         DWORD _Esp;//+1DCh
  102.         DWORD SegSs;//+1E0h
  103.         ;//+1E8h
  104.         DWORD ARGS1;//+1ECh
  105.         _FPO_DATA* Fpo;//+204h
  106.         DWORD ARGS2;//+20Ch
  107.         int u133;//+214h DbsX86StackUnwinder::ForceEbpRegion *
  108.         DWORD u1;//+3C8h
  109. }
复制代码

部分实现:

  1.         LONG New(DbsStackServices* StackService,DWORD MachineType,ACCESS_MODE AccessMode,DbsStackUnwinder** OutPtr)
  2.         {
  3.                 switch(MachineType)
  4.                 {
  5.                 case 0x1F2:
  6.                         *OutPtr = new DbsPpcBeStackUnwinder(StackService);
  7.                         break;
  8.                 case IMAGE_FILE_MACHINE_IA64:
  9.                         *OutPtr = new DbsIa64StackUnwinder(StackService);
  10.                         break;
  11.                 case IMAGE_FILE_MACHINE_AMD64:
  12.                         *OutPtr = new DbsX64StackUnwinder(StackService);
  13.                         break;
  14.                 case IMAGE_FILE_MACHINE_ARM:
  15.                 case IMAGE_FILE_MACHINE_THUMB:
  16.                 case 0x1C4:
  17.                         *OutPtr = new DbsArmStackUnwinder(StackService);
  18.                         break;
  19.                 case IMAGE_FILE_MACHINE_I386:
  20.                         switch(AccessMode)
  21.                         {
  22.                         case AddrModeFlat:
  23.                                 *OutPtr = new DbsX86StackUnwinder(StackService);
  24.                                 break;
  25.                         case AddrMode1616:
  26.                                 *OutPtr = new DbsX8616StackUnwinder(StackService);
  27.                                 break;
  28.                         }
  29.                         *OutPtr = new DbsX86StackUnwinder(StackService);
  30.                         break;
  31.                 }
  32.         }
  33.         LONG DbhUnwind(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)
  34.         {
  35.                 LONG status;
  36.                 if(StackFrame->Virtual)
  37.                 {
  38.                         IsVirtualFrame = TRUE;
  39.                         status=DbhContinue(StackFrame,ContextRecord);
  40.                         if(status)
  41.                                 return status;
  42.                         status=Unwind();
  43.                         if(status)
  44.                                 return status;
  45.                         status=GetContext(ContextRecord,u6);
  46.                         if(status)
  47.                                 return status;
  48.                 }
  49.                 else
  50.                 {
  51.                         status=DbhStart(StackFrame,ContextRecord);
  52.                         if(status)
  53.                                 return status;
  54.                 }
  55.                 memset(StackFrame->Params,0,sizeof(StackFrame->Params));
  56.                 status=DbhUpdatePreUnwind(StackFrame);
  57.                 if(status)
  58.                         return status;
  59.                 status=Unwind();
  60.                 if(status)
  61.                 {
  62.                         u24=u25=0;
  63.                 }
  64.                 status=DbhUpdatePostUnwind(StackFrame,status);
  65.                 return status;
  66.         }

  67.         LONG DbhGetKdHelp(STACKFRAME64* StackFrame)
  68.         {
  69.                 memcpy(&KdHelp,&StackFrame->KdHelp,sizeof(KdHelp));
  70.         }
  71.         virtual LONG Start(CONTEXT* ContextRecord,DWORD ContextSize)//+04h
  72.         {
  73.                 if(context && ContextSize >= this->ContextSize)
  74.                 {
  75.                         memcpy(context,ContextRecord,this->ContextSize);

  76.                 }
  77.         }
  78.         virtual LONG GetContext(CONTEXT* ContextRecord,DWORD ContextSize)//+0Ch
  79.         {
  80.                 if(context && ContextSize >= this->ContextSize)
  81.                 {
  82.                         memcpy(ContextRecord,context,this->ContextSize);
  83.                         SetRestart();
  84.                         UpdateAbstractPointers();
  85.                         UpdateCallPointer();
  86.                 }
  87.         }
  88.         virtual LONG DbhStart(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)//+18h
  89.         {
  90.                 if(!DbhGetKdHelp(StackFrame))
  91.                 {
  92.                         memset(&StackFrame->AddrBStore,0,sizeof(StackFrame->AddrBStore));
  93.                         memset(&StackFrame->AddrReturn,0,sizeof(StackFrame->AddrReturn));
  94.                         StackFrame->FuncTableEntry=0;
  95.                         memset(StackFrame->Params,0,sizeof(StackFrame->Params));
  96.                         StackFrame->Virtual=TRUE;
  97.                         memset(StackFrame->Reserved,0,sizeof(StackFrame->Reserved));
  98.                 }
  99.         }
  100.         virtual LONG DbhContinue(STACKFRAME64 * StackFrame,CONTEXT* ContextRecord)//+1Ch
  101.         {
  102.                 if(!DbhGetKdHelp(StackFrame))
  103.                 {
  104.                         LONG status=Start(ContextRecord,ContextSize);
  105.                 }
  106.         }
复制代码


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

使用道具 举报

307

主题

228

回帖

7349

积分

用户组: 真·技术宅

UID
2
精华
76
威望
291 点
宅币
5599 个
贡献
253 次
宅之契约
0 份
在线时间
949 小时
注册时间
2014-1-25
 楼主| 发表于 2015-8-23 22:20:08 | 显示全部楼层
windbg 命令初探(二)

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

  1. DWORD gApiRevision = 5;
  2. DWORD g_ForceLopWalk;
  3. DWORD g_AllowLopSymInfo;
  4. DWORD g_AllowLopRetSearch;
  5. DWORD g_AllowLopWalk;
  6. DWORD g_AllowVc7Fpo;

  7. DWORD g_NumForceEbpRegions;
  8. DWORD* g_ForceEbpRegions;

  9. enum
  10. {
  11.         AllowVc7Fpo=0x1,
  12.         AllowLopWalk=0x2,
  13.         AllowLopSymInfo=0x4,
  14.         AllowLopRetSearch=0x8,
  15.         ForceLopWalk=0x10,
  16. };

  17. LRESULT WINAPI PickX86Walk(DbsStackUnwinder* pStackUnwinder,DbsStackServices* pStackServices,LPSTACKFRAME64 pInitStackFrame,LPCONTEXT ContextRecord)
  18. {
  19.         CONTEXT Context;
  20.         if(!ContextRecord)
  21.         {
  22.                 RtlZeroMemory(&Context,0,sizeof(CONTEXT));
  23.                 Context.Eip = pInitStackFrame->AddrPC.Offset;
  24.                 Context.Esp = pInitStackFrame->AddrStack.Offset;
  25.                 if(LODWORD(pInitStackFrame->Reserved[0]) != 0 && HIDWORD(pInitStackFrame->Reserved[0]) == 0xEB)
  26.                         Context.Ebp = pInitStackFrame->Reserved[0];
  27.                 ContextRecord = &Context;
  28.         }
  29.         LRESULT status;
  30.         if(pInitStackFrame->AddrPC.Mode = AddrModeFlat)
  31.         {
  32.                 pStackService->IsFlatMode = true;
  33.                 pStackUnwinder->SetImplFlags((g_ForceLopWalk?0x10:0)|(g_AllowLopRetSearch?8:0)|(g_AllowLopSymInfo?4:0)|
  34.                         (g_AllowLopWalk?2:0)|(g_AllowVc7Fpo?1:0));
  35.                 pStackUnwinder->SetForceEbpRegions(g_NumForceEbpRegions,g_ForceEbpRegions);
  36.                 status = pStackUnwinder->DbhUnwind(pInitStackFrame,gApiRevision,TlsData.info,sizeof(TlsData.info),ContextRecord);
  37.                 if(!status)
  38.                 {
  39.                         if(g_ForceLopWalk && !g_AllowLopSymInfo)
  40.                                 pInitStackFrame->FuncTableEntry = 0;
  41.                         else
  42.                                 pInitStackFrame->FuncTableEntry = pStackService->FunctionTableAccessRoutine(pStackService->hProcess,
  43.                                         pInitStackFrame->AddrPC.Offset,pInitStackFrame->AddrPC.Offset);
  44.                 }
  45.         }
  46.         else
  47.         {
  48.                 status = pStackUnwinder->DbhUnwind(pInitStackFrame,gApiRevision,TlsData.info,sizeof(TlsData.info),ContextRecord);
  49.         }
  50.         return status;
  51. }

  52. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutineLocal;
  53. PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutineLocal;
  54. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutineLocal;
  55. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddressRoutineLocal;


  56. BOOL WINAPI StackWalk64(
  57.         DWORD MachineType,
  58.         HANDLE hProcess,
  59.         HANDLE hThread,
  60.         LPSTACKFRAME64 StackFrame,
  61.         LPCONTEXT ContextRecord,
  62.         PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  63.         PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  64.         PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
  65.         PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
  66.         )
  67. {
  68.         BOOL UseDefault = FALSE,NeedInnerFunc = FALSE;
  69.         DbhStackServices StackServices;
  70.         if(!StackFrame)
  71.                 return FALSE;
  72.         StackServices.hProcess = hProcess;
  73.         StackServices.hThread = hThread;
  74.         if(FunctionTableAccessRoutine)
  75.         {
  76.                 StackServices.FunctionTableAccessRoutine = FunctionTableAccessRoutine;
  77.         }
  78.         else
  79.         {
  80.                 StackServices.FunctionTableAccessRoutine = FunctionTableAccessRoutineLocal;
  81.                 NeedInnerFunc = TRUE;
  82.         }
  83.         if(GetModuleBaseRoutine)
  84.         {
  85.                 StackServices.GetModuleBaseRoutine = GetModuleBaseRoutine;
  86.         }
  87.         else
  88.         {
  89.                 StackServices.GetModuleBaseRoutine = GetModuleBaseRoutineLocal;
  90.                 NeedInnerFunc = TRUE;
  91.         }
  92.         if(ReadMemoryRoutine)
  93.         {
  94.                 StackServices.ReadMemoryRoutine = ReadMemoryRoutine;
  95.         }
  96.         else
  97.         {
  98.                 StackServices.ReadMemoryRoutine = ReadMemoryRoutineLocal;
  99.         }
  100.         if(TranslateAddress)
  101.         {
  102.                 StackServices.TranslateAddress = TranslateAddress;
  103.         }
  104.         else
  105.         {
  106.                 StackServices.TranslateAddress = TranslateAddressRoutineLocal;
  107.         }
  108.         if(!NeedInnerFunc)
  109.         {
  110.                 DbsStackUnwinder* StackUnwinder = NULL;
  111.                 LRESULT status;
  112.                 status = DbsStackUnwinder::New(&StackService,MachineType,StackFrame->AddrPC.Mode,&StackUnwinder);
  113.                 if(!status)
  114.                 {
  115.                         StackService.FpoDataSize = StackUnwinder->GetFunctionEntryBytes();
  116.                         if(MachineType == IMAGE_FILE_MACHINE_I386)
  117.                         {
  118.                                 PickX86Walk(StackUnwinder,&StackService,StackFrame,ContextRecord);
  119.                         }
  120.                         else if(ContextRecord)
  121.                         {
  122.                                 StackUnwinder->DbhUnwind(StackFrame,gApiRevision,TlsData.info,sizeof(TlsData.info),ContextRecord);
  123.                         }
  124.                 }
  125.                 if(StackUnwinder)
  126.                         StackUnwinder->~DbsStackUnwinder();
  127.         }
  128.         return 0;
  129. }
复制代码



还在编辑中~~~
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-5-7 11:15 , Processed in 0.035609 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表