gpt4 book ai didi

c++ - 如何使 StackWalk64() 在 x64 上成功运行?

转载 作者:可可西里 更新时间:2023-11-01 10:10:38 45 4
gpt4 key购买 nike

我有一个 C++ 工具可以一次遍历调用堆栈。在代码中,它首先获取实时 CPU 寄存器的拷贝(通过 RtlCaptureContext()),然后使用一些“#ifdef ...” block 将特定于 CPU 的寄存器名称保存到 stackframe.AddrPC.Offset, ...AddrStack..., and ...AddrFrame...;此外,对于上面的 3 个 Addr... 成员中的每一个,它都设置了 stackframe.Addr....Mode = AddrModeFlat。 (这是从我前一段时间遇到的一些示例代码中借用的。)

使用 x86 二进制文件,效果很好。但是,对于 x64 二进制文件,StackWalk64() 会传回虚假地址。 (第一次调用 API 时,唯一公然伪造的地址值出现在 AddrReturn 中(== 0xFFFFFFFF'FFFFFFFE -- 又名 StackWalk64() 的第 3 个arg,GetCurrentThread() 返回的伪句柄)。但是,如果第二次调用 API,所有 Addr... 变量都会收到伪地址。) 不管AddrFrame 是如何设置的:

  • 使用推荐的 x64“基址/帧指针”CPU 寄存器之一:rbp (= 0xf),或 rdi (= 0x0)
  • 使用rsp (没想到它会起作用,但还是试过了)
  • 正常设置 AddrPCAddrStack,但将 AddrFrame 置零 (见其他示例代码)
  • 将所有 Addr... 值清零,让 StackWalk64() 从传入的 CPU 寄存器上下文中填充它们 (见其他示例代码)

FWIW,物理堆栈缓冲区的内容在 x64 和 x86 上也不同(当然,在考虑了不同的指针宽度和堆栈缓冲区位置之后)。不管是什么原因,StackWalk64() 应该仍然能够正确地遍历调用堆栈——哎呀,调试器仍然能够遍历调用堆栈,而且它似乎在幕后使用 StackWalk64() 本身。奇怪的是,调试器报告的(正确的)调用堆栈包含基址和返回地址指针值,其构成字节实际上并不存在于堆栈缓冲区中(当前堆栈指针下方或上方)。

(FWIW #2:鉴于上面的堆栈缓冲区异常,我确实尝试禁用 ASLR(/dynamicbase:no)以查看它是否有所作为,但二进制文件仍然显示相同的行为。)

所以。为什么这在 x86 上可以正常工作,但在 x64 上有问题?关于如何修复它有什么建议吗?

最佳答案

鉴于fs.sf是一个STACKFRAME64结构,在传递给StackWalk64之前需要像这样初始化它:(c是一个CONTEXT结构)

  DWORD machine = IMAGE_FILE_MACHINE_AMD64;
RtlCaptureContext (&c);
fs.sf.AddrPC.Offset = c.Rip;
fs.sf.AddrFrame.Offset = c.Rsp;
fs.sf.AddrStack.Offset = c.Rsp;
fs.sf.AddrPC.Mode = AddrModeFlat;
fs.sf.AddrFrame.Mode = AddrModeFlat;
fs.sf.AddrStack.Mode = AddrModeFlat;

此代码取自 ACE(自适应通信环境),改编自 CodeProject 上的 StackWalker 项目。

关于c++ - 如何使 StackWalk64() 在 x64 上成功运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/136752/

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com