本帖最后由 BeneficialWeb 于 2019-7-7 09:23 编辑
1. 调试器是如何实现栈回溯的?
因为函数调用指令会将函数的返回地址记录在栈上,因此可以通过从栈顶向下遍历每个栈帧来追溯函数调用的过程。
知识背景
1.源代码级调试、栈回溯、按名称显示变量等功能的实现,都离不开调试符号。
2.调试符号是在编译器在将源文件编译为可执行程序的过程中,为支持调试而摘录的调试信息。调试信息包括变量,类型,函数名,源代码行等。
3.PDB,ProgramDataBase, 微软用于描述源程序的数据库。
4.可以通过DbgHelp函数库或者DIASDK两种方式来访问调试符号文件中的符号。
5.栈帧就是利用寄存器访问栈内局部变量、参数、函数返回地址等的手段。指向每个栈帧的指针被称为帧指针。遍历整个栈中的所有栈帧,便可以得到函数调用序列。
在通过DbgHelp函数库返回地址对应的符号,便可以得到栈回溯信息。
以下是我在文件夹中找到的dbghelp.dll的身影。
X64dbg
OllyDbg
接下来是我在其它地方学习来的的代码
[C++] 纯文本查看 复制代码 #include <windows.h>
#include <dbghelp.h>
#include <iostream>
#include<iomanip>
#include<vector>
#pragma comment(lib, "dbghelp.lib")
bool PrintCallStackBackTrace()
{
DWORD options = SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES;
SymSetOptions(options);
CONTEXT context = { 0 };
RtlCaptureContext(&context);
STACKFRAME64 stack = { 0 };
stack.AddrPC.Offset = context.Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Esp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
std::vector<DWORD_PTR> backtrace;
std::string path =
R"(SRV*D:\symbols*https://msdl.microsoft.com/download/symbols)";
BOOL result = SymInitialize(GetCurrentProcess(), path.c_str(), TRUE);
if (!result) {
DWORD error = GetLastError();
std::cout << "SymInitialize returned error : " << error << std::endl;
}
while (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(),
GetCurrentThread(), &stack, &context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL))
{
backtrace.push_back(stack.AddrPC.Offset);
}
for (DWORD index = 0; index < backtrace.size(); index++)
{
DWORD_PTR frame = backtrace[index];
const int kMaxNameLength = 256;
ULONG64 buffer[(sizeof(SYMBOL_INFO) + kMaxNameLength * sizeof(wchar_t) +
sizeof(ULONG64) - 1) /
sizeof(ULONG64)];
memset(buffer, 0, sizeof(buffer));
DWORD64 sym_displacement = 0;
PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = kMaxNameLength - 1;
BOOL has_symbol =
SymFromAddr(GetCurrentProcess(), frame, &sym_displacement, symbol);
DWORD line_displacement = 0;
IMAGEHLP_LINE64 line = {};
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
&line_displacement, &line);
std::cout <<"0x"<< std::left << std::hex << std::setw(12) << frame;
if (has_symbol) {
std::cout <<std::setw(5)<< symbol->Name << "\t";
}
std::cout << std::endl;
}
result = SymCleanup(GetCurrentProcess());
return true;
}
void f()
{
PrintCallStackBackTrace();
}
int main()
{
f();
system("pause");
return 0;
}
删除pdb之前的运行效果
删除pdb之后的运行效果
这是我的学习笔记,如有错误的地方,望大佬们指出
最后我有一个疑问,为什么我用OD调试OD过程中,对SymFromAddr下断点,没有断下来??? |