惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
Help Net Security
Help Net Security
P
Proofpoint News Feed
J
Java Code Geeks
爱范儿
爱范儿
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
Google DeepMind News
Google DeepMind News
H
Help Net Security
G
Google Developers Blog
Jina AI
Jina AI
Vercel News
Vercel News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
Lohrmann on Cybersecurity
S
Schneier on Security
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
Security Archives - TechRepublic
Security Archives - TechRepublic
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
GbyAI
GbyAI
B
Blog
O
OpenAI News
博客园_首页
Cisco Talos Blog
Cisco Talos Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News: Ask HN
Hacker News: Ask HN
TaoSecurity Blog
TaoSecurity Blog
腾讯CDC
MongoDB | Blog
MongoDB | Blog
M
MIT News - Artificial intelligence
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
Webroot Blog
Webroot Blog
Simon Willison's Weblog
Simon Willison's Weblog
Y
Y Combinator Blog
C
Cisco Blogs
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
AI
AI
W
WeLiveSecurity
aimingoo的专栏
aimingoo的专栏
The Register - Security
The Register - Security
Project Zero
Project Zero
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale

博客园 - 汇编工具视频笔记教程

如何让QT工程回到未编译前的样子?需要删除哪些文件夹? X64dbg中minidump文件夹的用途 x64dbg这个文件夹memdumps有啥用? cnpack卸载不干净,Delphi 11.1启动报错时的解决 Delphi 11.1 强行安装修改【一键中英文助手】版本号失败后的解决: 法王八强版x64dbg 存档 流程图 Delphi程序,已知机器码是:558BEC 要求反转为: EC8B55 写机器码改写EXE文件 delphi反转机器码的实现: delphi剪贴板类型 解决cnpack不正常使用的键值 x64dbg构建时正确的返回信息 Delphi 10.4.2 topics.chm帮助文件中文版 Ollydbg_x36dbg贴心伴侣 8.88版2021-5-5号发布 Ollydbg/x32dbg/x64dbg贴心伴侣 Version 6.48使用详解 视频教程x32dbg_x64dbg命令脚本从入门到精通 Red Gate .NET Reflector 10.2.1.1800汉化版使用心得
那你再查一下View==> Source这一功能的实现:是如何调用源码一起来调试的?
汇编工具视频笔记教程 · 2026-03-11 · via 博客园 - 汇编工具视频笔记教程

现在我已经收集了足够的信息来解释 "View -> Source" 功能的实现。让我总结一下整个流程。根据代码分析,我来详细解释 View → Source 功能的实现原理和源码调试流程:

整体架构

用户操作 → GUI 层 → Bridge 层 → 调试核心 (dbg) → PDB 符号系统

核心组件

1. GUI 层组件

  • SourceViewerManager (src/gui/Src/Gui/SourceViewerManager.h/cpp)

    • 管理多个源文件标签页
    • 接收 loadSourceFile 信号并加载源文件
  • SourceView (src/gui/Src/Gui/SourceView.h/cpp)

    • 单个源文件视图
    • 显示源代码、行号、对应的地址
    • 支持跳转到反汇编视图

2. Bridge 层

  • GuiLoadSourceFileEx (src/bridge/bridgemain.cpp)
    BRIDGE_IMPEXP void GuiLoadSourceFileEx(const char* path, duint addr)
    {
        _gui_sendmessage(GUI_LOAD_SOURCE_FILE, (void*)path, (void*)addr);
    }
    

3. 调试核心层

  • SymGetSourceLine (src/dbg/symbolinfo.cpp)

    • 从地址获取源文件路径和行号
    • 使用 PDB 符号信息
  • SymGetSourceAddr (src/dbg/symbolinfo.cpp)

    • 从源文件和行号获取地址
    • 支持源码到地址的双向映射

工作流程

触发方式 1:View → Source 菜单

// MainWindow.cpp
connect(ui->actionSource, SIGNAL(triggered()), this, SLOT(displaySourceViewWidget()));

void MainWindow::displaySourceViewWidget()
{
    showQWidgetTab(mSourceViewManager);
}

触发方式 2:反汇编视图中右键 → Open Source File

// CPUDisassembly.cpp
void CPUDisassembly::openSourceSlot()
{
    char szSourceFile[MAX_STRING_SIZE] = "";
    int line = 0;
    auto sel = rvaToVa(getInitialSelection());
    
    // 1. 从地址获取源文件信息
    if(!DbgFunctions()->GetSourceFromAddr(sel, szSourceFile, &line))
        return;
    
    // 2. 发送信号加载源文件
    emit Bridge::getBridge()->loadSourceFile(szSourceFile, sel);
    emit displaySourceManagerWidget();
}

源文件加载流程

// SourceViewerManager.cpp
void SourceViewerManager::loadSourceFile(QString path, duint addr)
{
    // 1. 检查文件是否已加载
    for(int i = 0; i < count(); i++)
    {
        SourceView* curView = (SourceView*)this->widget(i);
        if(curView->getSourcePath().compare(path, Qt::CaseInsensitive) == 0)
        {
            curView->setSelection(addr);  // 跳转到对应行
            setCurrentIndex(i);
            return;
        }
    }
    
    // 2. 创建新的源文件视图
    SourceView* newView = new SourceView(path, addr, this);
    addTab(newView, title);
    setCurrentIndex(count() - 1);
    
    // 3. 设置焦点并跳转到对应行
    QTimer::singleShot(50, [newView, addr]()
    {
        newView->setSelection(addr);
        newView->setFocus();
    });
}

源文件到地址的映射

// SourceView.cpp
duint SourceView::addrFromIndex(size_t index)
{
    // 调用调试核心获取行号对应的地址
    return DbgFunctions()->GetAddrFromLineEx(mModBase, 
        mSourcePath.toUtf8().constData(), int(index + 1));
}

// _dbgfunctions.cpp
_dbgfunctions.GetAddrFromLineEx = [](duint mod, const char* szSourceFile, int line)
{
    duint addr = 0;
    if(SymGetSourceAddr(mod, szSourceFile, line, &addr))
        return addr;
    return 0;
};

PDB 符号系统

// symbolinfo.cpp
bool SymGetSourceAddr(duint Module, const char* FileName, int Line, duint* Address)
{
    MODINFO* modInfo = ModInfoFromAddr(Module);
    SymbolSourceBase* sym = modInfo->symbols;
    
    LineInfo lineInfo;
    if(!sym->findSourceLineInfo(FileName, Line, lineInfo))
        return false;
    
    *Address = lineInfo.rva + modInfo->base;
    return true;
}

从 PDB 加载行号信息

// symbolsourcedia.cpp
bool SymbolSourceDIA::loadSourceLinesAsync()
{
    PDBDiaFile pdb;
    pdb.open(_path.c_str());
    
    // 1. 枚举所有行号信息
    std::vector<DiaLineInfo_t> lines;
    std::map<DWORD, String> files;
    pdb.enumerateLineNumbers(0, uint32_t(_imageSize), lines, files, _requiresShutdown);
    
    // 2. 构建地址→行号映射
    for(const auto & line : lines)
    {
        _linesData.emplace_back();
        lineInfo.rva = line.rva;
        lineInfo.lineNumber = line.lineNumber;
        lineInfo.sourceFileIndex = found->second.sourceFileIndex;
    }
    
    // 3. 构建行号→地址映射
    for(size_t i = 0; i < _linesData.size(); i++)
    {
        _sourceLines[line.sourceFileIndex].push_back(lineIndex);
    }
    
    _linesLoaded = true;
}

PDB 行号枚举

// pdbdiafile.cpp
bool PDBDiaFile::enumerateLineNumbers(uint32_t rva, uint32_t size, 
    std::vector<DiaLineInfo_t> & lines, 
    std::map<DWORD, std::string> & files, 
    const std::atomic<bool> & cancelled)
{
    // 1. 使用 DIA API 查找行号
    CComPtr<IDiaEnumLineNumbers> lineNumbersEnum;
    m_session->findLinesByRVA(rva, size, &lineNumbersEnum);
    
    // 2. 遍历行号信息
    while(lineNumbersEnum->Next(1, &lineNumberInfo, &fetched) == S_OK)
    {
        // 获取源文件
        lineNumberInfo->get_sourceFile(&sourceFile);
        sourceFile->get_fileName(&fileName);
        
        // 获取行号和地址
        lineNumberInfo->get_lineNumber(&lineInfo.lineNumber);
        lineNumberInfo->get_relativeVirtualAddress(&lineInfo.rva);
        
        lines.push_back(lineInfo);
        files.insert({ sourceFileId, fileName });
    }
}

双向映射机制

地址 → 源文件(用于显示源码)

反汇编地址 → SymGetSourceLine → 源文件路径 + 行号 → 显示源文件

源文件 → 地址(用于源码调试)

源文件行号 → SymGetSourceAddr → RVA + 模块基址 → 反汇编地址

关键特性

  1. 自动映射:从 PDB 符号文件中自动提取源文件行号信息
  2. 双向导航:可以在反汇编和源代码视图之间双向跳转
  3. 标签页管理:支持同时打开多个源文件
  4. 文件路径重映射:支持 PDB 中的相对路径到实际磁盘路径的映射
  5. 异步加载:大型 PDB 文件的行号信息异步加载,避免阻塞 UI

调试支持

源码调试的核心依赖:

  • PDB 符号文件:包含编译时的源文件路径和行号信息
  • DIA (Debug Interface Access):Microsoft 提供的 PDB 解析 API
  • 符号缓存:行号信息加载后缓存在内存中,提高查询性能

这就是 x64dbg 如何通过 PDB 符号系统实现源码级调试的完整流程!

采用EnigmaVirtualBox制作单文件便携版只是兴趣爱好,在WES7环境中制作,不保证全系统下正常,随缘随心随性。 温馨提醒建议在SandBoxie中测试https://www.lanzous.com/iatkifc