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;
}