x64dbg 文件菜单(File Menu)完全指南:从打开程序、附加进程到数据库导入导出与补丁管理
2026/9/20 11:30:03 网站建设 项目流程

x64dbg 文件菜单(File Menu)完全指南:从打开程序、附加进程到数据库导入导出与补丁管理

【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg

导读

x64dbg 的File(文件)菜单是逆向工程的起点——几乎所有调试会话都从这里开始:打开目标程序、附加到正在运行的进程、管理最近调试记录,以及维护与调试会话配套的用户数据库(注释、标签、断点、函数等)。本文基于 File.rst 官方文档,逐项剖析该菜单的全部条目,并结合仓库源码揭示其底层命令实现与配置存储机制,帮助你不仅会用界面,还能理解每个动作背后发生了什么,甚至可以直接用命令行完成同样操作。


菜单总览

File 菜单自上而下包含以下条目:

菜单项作用对应命令
Open打开可执行文件(EXE/DLL)开始调试InitDebug(init
Recent Files最近调试过的文件子菜单—(由 MRUList 管理)
Attach附加到运行中的进程AttachDebugger(attach
Detach分离调试器,让调试对象自由运行DetachDebugger(detach
Import database导入用户数据库dbload
Export database导出用户数据库dbsave
Patch file打开补丁对话框,查看并应用补丁
Restart as Admin以管理员权限重启 x64dbg 与当前调试目标restartadmin(内部命令)
Exit退出调试器并终止被调试进程

下面逐项展开。


Open:开始一个调试会话

Open动作用于打开一个可执行文件进行调试,文件类型可以是EXE,也可以是DLL。这是 x64dbg 最常用的入口动作,其 UI 实现位于 MainWindow.cpp:

void MainWindow::openFileSlot() { auto filename = QFileDialog::getOpenFileName(this, tr("Open file"), mMRUList->getEntry(0), tr("Executables (*.exe *.dll);;All files (*.*)")); if(!filename.length()) return; filename = QDir::toNativeSeparators(filename); //convert to native path format (with backlashes) openRecentFileSlot(filename); }

几个值得注意的实现细节:

  • 文件过滤器默认限定为*.exe*.dll,但允许切换到All files (*.*)手动选择任意文件(例如无扩展名的驱动或固件镜像)。
  • 初始目录取自最近文件列表(MRU)的第一项所在位置(mMRUList->getEntry(0)),方便连续调试同一目录下的多个样本。
  • 选定文件后,路径会通过QDir::toNativeSeparators转换为 Windows 原生反斜杠格式,再交给openRecentFileSlot,最终拼成命令init "路径"执行。

底层命令:init

Open 动作的界面背后执行的正是init(全名 InitDebug,别名initdbg)。该命令完成一次完整的初始化流程:

  1. 加载可执行文件并做基本检查;
  2. 若存在 TLS 回调(TLS callbacks),为其设置断点;
  3. 在进程入口点(entry point)设置断点;
  4. 在系统断点(system breakpoint)处停下,把控制权交还给用户。

命令语法:

init <arg1> [arg2] [arg3]
参数含义说明
arg1要调试的可执行文件路径如果未给出完整路径,会调用GetCurrentDirectoryAPI 补全为完整路径;路径含空格时必须使用引号包裹
arg2(可选)创建进程时附带的命令行参数直接传给CreateProcess
arg3(可选)当前工作目录即所谓的 working directory / current directory,也传给CreateProcess

命令返回后,会设置$pid(进程 ID)和$hp/$hProcess(进程句柄)变量,方便后续脚本直接引用。例如:

init "C:\malware\sample.exe" "--flag1 --flag2" "C:\malware"

在 GUI 层面,除了菜单 Open,你还可以把文件直接拖拽到主窗口上触发同样的init流程——MainWindow.cpp 的dropEvent会把拖入的文件路径拼成init "路径"命令执行,两者完全等价。


Recent Files:最近调试记录

Recent Files子菜单列出了你此前调试过的文件。文档特别说明:它不会包含任何程序无法调试的文件(例如已不存在的路径或非可执行文件)。

该子菜单的数据存放在配置 INI 文件的Recent Files小节中,你可以直接编辑该 INI 文件来增删条目。

源码级实现:MRUList

Recent Files 由MRUList类实现,见 MRUList.cpp。关键行为:

  • 存储格式:条目以两位数字序号作为键写入 INI,例如Recent Files\01Recent Files\02……每个键对应一个文件路径。BridgeSettingSet/BridgeSettingGet负责读写(见save()load())。
  • 默认容量MRUList构造函数的maxItems参数默认为16(见 MRUList.h),超出上限的旧条目会被裁剪(addEntrymMRUList.erase(...))。
  • 去重:加载与保存时都会removeDuplicates(),同一个文件只会出现一次;再次打开某文件时,它会被提升到列表最前(insert(mMRUList.begin(), entry))。
  • 有效性校验load()save()都会检查QFile(path).exists(),不存在的文件不会进入列表——这正是文档所说"不包含无法调试的文件"的机制来源。
  • 点击行为appendMenu为每个条目创建一个 QAction,触发后发出openFile信号,由主窗口openRecentFileSlot接收并执行init "路径"(见 MainWindow.cpp)。

主窗口在初始化时创建该列表(MainWindow.cpp):

mMRUList = new MRUList(this, "Recent Files"); connect(mMRUList, SIGNAL(openFile(QString)), this, SLOT(openRecentFileSlot(QString))); mMRUList->load();

值得注意的是,MRUList是一个通用组件,同一机制还被复用于Recent Scripts(ScriptView.cpp)和Recent Trace Files(TraceManager.cpp),只是 INI 小节名不同。另外,主窗口的restartDebugging()(对应actionRestart)也依赖 MRU 列表第一项来重新启动上次调试的目标(MainWindow.cpp)。


Attach:附加到运行中的进程

Attach用于附加到一个正在运行的进程。点击后会弹出一个对话框,列出当前系统正在运行的进程,你可以选择其一进行附加。

有两个必须牢记的限制(官方文档明确):

  1. 架构必须一致:只能附加与调试器同架构的可执行文件。例如用 x32dbg 无法附加 64 位进程,反之亦然。
  2. 附加会终止当前调试对象:如果你正在调试某个可执行文件,再附加另一个进程会终止之前的调试对象(debuggee)。

底层命令:attach

Attach 动作对应 AttachDebugger(别名attach):

attach <arg1> [arg2] [arg3]
参数含义说明
arg1目标进程的 PID必填
arg2(可选)事件对象句柄仅内部使用(internal use only)
arg3(可选)附加后要恢复的线程 TID仅内部使用(internal use only)

附加成功后,命令同样会在系统断点处把控制权交回用户,并设置$pid$hp/$hProcess变量。日常使用只需attach 1234这样的形式即可。


Detach:分离调试器

Detach将调试器与调试对象分离,让被调试进程脱离调试器的控制继续独立运行。

使用限制:未处于调试状态时无法执行此操作。对应命令 DetachDebugger(别名detach)非常简洁——它没有任何参数,也不会设置任何结果变量,直接输入detach即可。

典型场景:当逆向分析完成、不再需要单步跟踪,但又希望目标进程(比如一个被附加分析的服务器程序)继续对外提供服务时,用 Detach 比直接终止更加温和。


Import / Export database:用户数据库的导入与导出

Import database允许你导入一个数据库文件;Export database则允许你把当前数据库导出为未压缩(uncompressed)的数据库文件。

这里所说的"数据库"(database)是 x64dbg 的用户数据库——它集中存放与当前调试目标关联的一切分析成果:注释(comments)、标签(labels)、书签(bookmarks)、函数定义(functions)、参数(arguments)、断点(breakpoints)等。用户数据库的底层存储逻辑集中在 database.cpp,相关类型定义见 database.h。

对应的两个命令

dbload(别名loaddb),见 dbload:

dbload [arg1]
  • 若给出arg1(数据库文件路径):执行的是导入(import)语义,当前数据不会被自动清空
  • 若不给出参数:会清空所有数据,并从磁盘重新加载当前程序的数据库。

其命令处理函数位于 cmd-user-database.cpp:无参数时先DebugRemoveBreakpoints()DbClear(),随后DbLoad(...)DebugSetBreakpoints()并刷新所有视图——也就是说加载数据库的同时会同步恢复其中的断点设置。

dbsave(别名savedb),见 dbsave:

dbsave [arg1]
  • 若给出arg1:将数据库保存到指定路径;
  • 若不给出参数:保存到当前程序的默认数据库。

实现上直接调用DbSave(DbLoadSaveType::All, ...)(cmd-user-database.cpp),按"全部类型"导出。

这两个命令在命令系统中注册于 x64dbg.cpp:

dbgcmdnew("dbsave,savedb", cbInstrDbsave, true); //save program database dbgcmdnew("dbload,loaddb", cbInstrDbload, true); //load program database

实战建议:在分析一个大型样本前,先用dbsave备份干净的初始数据库;导入他人分享的分析成果时用dbload <path>,这样不会覆盖你当前已有的数据。


Patch file:补丁对话框

Patch file打开补丁对话框(Patch Dialog),你可以在此查看已记录的补丁(patches),并将补丁直接应用到文件上

补丁功能允许你在内存中修改指令后,把修改固化到磁盘上的原始文件里——例如 patch 掉反调试的jz跳转、改写条件分支等。GUI 侧由 PatchDialog 实现,主窗口的patchWindow()槽负责将其显示出来(MainWindow.cpp),并通过actionPatches连接到菜单项(MainWindow.cpp)。此外,当你在反汇编视图中通过右键"show patches"时也会触发同一个对话框(MainWindow.cpp)。

补丁的底层记录与读写逻辑位于 patches.cpp / patches.h。对话框内会列出所有待定补丁,你可以逐个审查后选择"应用"来把修改写回文件。


Restart as Admin:以管理员权限重启

Restart as Admin会用管理员权限重启 x64dbg,并同时以管理员权限重启当前正在调试的目标进程。

该菜单项在 MainWindow.cpp 中被绑定到内部命令restartadmin

makeCommandAction(ui->actionRestartAdmin, "restartadmin");

命令在 x64dbg.cpp 中注册:

dbgcmdnew("restartadmin,runas,adminrestart", cbInstrRestartadmin, false);

核心实现是dbgrestartadmin(),见 debugger.cpp:

bool dbgrestartadmin() { wchar_t wszProgramPath[MAX_PATH] = L""; if(GetModuleFileNameW(GetModuleHandleW(nullptr), wszProgramPath, _countof(wszProgramPath))) { std::wstring file = wszProgramPath; auto last = wcsrchr(wszProgramPath, L'\\'); if(last) *last = L'\0'; std::wstring params = L"\"" + gInitExe + L"\""; if(!gInitCmd.empty()) params += L" -- " + gInitCmd; if(!gInitDir.empty()) params = L"-workingDir \"" + gInitDir + L"\" " + params; auto result = ShellExecuteW(NULL, L"runas", file.c_str(), params.c_str(), wszProgramPath, SW_SHOWDEFAULT); return INT_PTR(result) > 32 && GetLastError() == ERROR_SUCCESS; } return false; }

机制要点:

  • 通过ShellExecuteWrunas动词触发 Windows UAC 提权,重新启动调试器;
  • 重启时会保留初始调试目标gInitExe(当前调试的可执行文件)、gInitCmd(启动命令行参数,通过--分隔传递)、gInitDir(工作目录,通过-workingDir参数传递)都会被透传给新进程;
  • 如果调试器在调试过程中检测到需要管理员权限(例如附加到高权限进程失败),也会走同样的提权重启路径(debugger.cpp)。

典型应用:许多恶意样本、加壳程序或受保护进程运行在高权限下,普通权限的调试器无法附加或读写其内存,此时用此功能一次性提升整个调试环境(包括被调试进程)的权限。


Exit:退出调试器

Exit终止调试器。特别注意官方文档的警告:如果当前有进程正被本程序调试,退出时这些进程也会被一并终止(terminated)

因此,在退出前请确认:

  • 是否已经保存好数据库(dbsave/ Export database);
  • 是否已经应用或导出补丁(Patch file);
  • 如果只想让目标进程继续运行而不再调试,应优先使用Detach而非 Exit。

小结与实战速查

File 菜单虽然只是 x64dbg 的入口,却串联起了调试生命周期中最核心的几个动作。一张表速查:

你的需求操作路径等价命令
打开 EXE/DLL 开始调试File → Openinit "path" [cmdline] [workdir]
重新调试上次的目标File → Recent Files 或 Restartinit(由 MRU 首项驱动)
附加同架构运行进程File → Attachattach <pid>
让目标脱离调试器继续运行File → Detachdetach
备份/分享分析成果File → Export databasedbsave [path]
载入他人/旧的分析成果File → Import databasedbload [path]
把内存修改写回文件File → Patch file—(GUI 对话框)
提权后继续调试File → Restart as Adminrestartadmin
结束调试并终止目标File → Exit

如需更深入地理解每一项背后的命令行为,可继续阅读 debug-control 与 user-database 两个命令手册目录,或直接查看 MainWindow.cpp、MRUList.cpp、cmd-user-database.cpp 等源码文件。

【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询