
2、错误调试方向

3、使用 虚拟网络编辑器(仅适用于较新版本)
打开 VMware Workstation → 编辑 → 虚拟网络编辑器
选择 VMnet8(NAT 模式)
点击 NAT 设置 → 高级
如果有 "端口转发"按钮,点击添加:
主机端口:50000
协议:TCP
虚拟机 IP:192.168.100.128(你的虚拟机 IP)
虚拟机端口:50000
⚠️ 如果没有这个按钮,说明你的版本不支持图形化配置。


4、ping

5、telnet安装

6、虚拟机内联调

7winDbg
bash
确保你在虚拟机里运行了:
ntsd -server tcp:port=50000 -noio "C:\path\to\test.exe"
虚拟机 防火墙阻止了 50000 端口
在虚拟机中临时关闭防火墙测试:
netsh advfirewall set allprofiles state off
Microsoft Windows [版本 10.0.19045.3803]
(c) Microsoft Corporation。保留所有权利。
C:\Windows\system32>ipconfig
Windows IP 配置
以太网适配器 以太网(内核调试器):
连接特定的 DNS 后缀 . . . . . . . : localdomain
本地链接 IPv6 地址. . . . . . . . : fe80::18c7:552f:b098:436c%7
IPv4 地址 . . . . . . . . . . . . : 192.168.88.136
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.88.2
以太网适配器 蓝牙网络连接:
媒体状态 . . . . . . . . . . . . : 媒体已断开连接
连接特定的 DNS 后缀 . . . . . . . :
C:\Windows\system32>ntsd -server tcp:port=50000,server=0.0.0.0 -noio test.exe
'ntsd' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
C:\Windows\system32>cd C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>ntsd -server tcp:port=50000,server=0.0.0.0 -noio test.exe
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>netsh advfirewall set allprofiles state off
确定。
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>
切换到 test.exe 所在目录再运行
cmd
编辑
cd /d C:\Users\lenovo\Desktop\64asm\64asm
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe" -server tcp:port=50000,server=0.0.0.0 -noio test.exe
最终完整命令(复制粘贴即可)
在虚拟机中以管理员身份打开 CMD,执行:
cmd
编辑
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe" -server tcp:port=50000,server=0.0.0.0 -noio "C:\Users\lenovo\Desktop\64asm\64asm\test.exe"
bash
Microsoft (R) Windows Debugger Version 10.0.22621.5193 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
Microsoft (R) Windows Debugger Version 10.0.22621.5193 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: test.exe
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\atlmfc.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\ObjectiveC.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\concurrency.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\cpp_rest.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\stl.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\Windows.Data.Json.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\Windows.Devices.Geolocation.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\Windows.Devices.Sensors.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\Windows.Media.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\windows.natvis'
NatVis script successfully loaded from 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers\winrt.natvis'
************* Path validation summary **************
Response Time (ms) Location
Deferred srv*
Symbol search path is: srv*
Executable search path is:
ModLoad: 00007ff6`c86f0000 00007ff6`c873a000 image00007ff6`c86f0000
ModLoad: 00007ff9`2aad0000 00007ff9`2acc8000 ntdll.dll
ModLoad: 00007ff9`28c60000 00007ff9`28d1d000 C:\Windows\System32\KERNEL32.DLL
ModLoad: 00007ff9`28460000 00007ff9`28756000 C:\Windows\System32\KERNELBASE.dll
ModLoad: 00007ff9`25a20000 00007ff9`25ab0000 C:\Windows\SYSTEM32\apphelp.dll
(d10.2134): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00007ff9`2aba0730 cc int 3
DESKTOP-5C1UUIK\lenovo (tcp [::ffff:192.168.88.1]:62092) connected at Thu Jan 1 10:25:27 2026
二、代码实现
bash
1. C++ 主程序(test.cpp)
cpp
编辑
#include <iostream>
using namespace std;
// 声明外部汇编函数(C 调用约定)
extern "C" unsigned long long __cdecl Chapter6_Demo();
int main() {
unsigned long long result = Chapter6_Demo();
cout << "第六章指令演示运行成功,结果汇总:0x" << hex << result << endl;
system("pause"); // 防止程序立即退出,便于调试
return 0;
}
- x64 汇编模块(Chapter6_Demo.asm)
使用 .data 定义全局变量(QWORD 类型)
使用 .code 实现数据传送(MOV/MOVZX/MOVSX)与算术运算(ADD/SUB/INC/DEC/NEG)
函数以 PROC ... ENDP 包裹
必须在文件末尾添加 END 指令
返回值通过 RAX 寄存器传递
✅ 示例结尾:
bash
;Chapter6_Demo
asm
option casemap:none
; 数据段:定义全局变量(64位类型)
.data
; 无符号64位整数
uNum1 QWORD 1000000000000000h ; 64位无符号数
uNum2 QWORD 0000000000000002h ; 64位无符号数
uResult QWORD 0 ; 无符号运算结果存储
; 有符号64位整数
sNum1 QWORD -100h ; 64位有符号数
sNum2 QWORD 200h ; 64位有符号数
sResult QWORD 0 ; 有符号运算结果存储
; 代码段:核心逻辑实现
.code
; 函数名:Chapter6_Demo
; 功能:演示本章数据传送与算术运算指令
; 参数:无
; 返回值:RAX(返回运算结果汇总)
Chapter6_Demo PROC
; ========== 一、数据传送指令演示 ==========
; 1. MOV指令:寄存器<->寄存器、寄存器<->内存
MOV RAX, uNum1 ; 内存->64位寄存器:uNum1 -> RAX
MOV RBX, uNum2 ; 内存->64位寄存器:uNum2 -> RBX
MOV RCX, RAX ; 寄存器->寄存器:RAX -> RCX
; 2. MOVZX指令:零扩展传送(无符号数,8位->64位)
MOV DL, 0FFh ; 8位无符号数(255)存入DL(RDX的8位低位)
MOVZX RDX, DL ; 零扩展:DL -> RDX(RDX高位补0,结果为00000000000000FFh)
; 3. MOVSX指令:符号扩展传送(有符号数,8位->64位)
MOV AL, 0FFh ; 8位有符号数(-1)存入AL(RAX的8位低位)
MOVSX RAX, AL ; 符号扩展:AL -> RAX(RAX高位补1,结果为FFFFFFFFFFFFFFFFh)
; ========== 二、算术运算指令演示 ==========
; 1. ADD指令:无符号数加法
MOV RAX, uNum1
ADD RAX, uNum2 ; RAX = uNum1 + uNum2(1000000000000000h + 2h = 1000000000000002h)
MOV uResult, RAX ; 结果存入uResult
; 2. SUB指令:无符号数减法
MOV RAX, uResult
SUB RAX, uNum2 ; RAX = uResult - uNum2(还原为uNum1的值)
MOV uResult, RAX ; 存储还原后的值
; 3. INC/DEC指令:自增/自减
INC uResult ; uResult自增1(1000000000000001h)
DEC uResult ; uResult自减1(还原为1000000000000000h)
; 4. ADD/SUB指令:有符号数运算
MOV RAX, sNum1
ADD RAX, sNum2 ; RAX = sNum1 + sNum2(-100h + 200h = 100h)
MOV sResult, RAX ; 结果存入sResult
MOV RAX, sResult
SUB RAX, sNum2 ; RAX = sResult - sNum2(还原为sNum1的值)
MOV sResult, RAX ; 存储还原后的值
; 5. NEG指令:求补运算(正负转换)
NEG sResult ; sResult = 0 - sResult(-100h 转换为 100h)
NEG sResult ; 再次求补,还原为-100h
; ========== 三、结果返回 ==========
MOV RAX, uResult ; RAX存储无符号结果
MOV RBX, sResult ; RBX存储有符号结果
OR RAX, RBX ; 汇总结果(仅作演示,可根据需求调整返回逻辑)
RET ; 函数返回,RAX为返回值
Chapter6_Demo ENDP
END
三、编译与链接(命令行)
在虚拟机中执行:
cmd
编辑
:: 1. 汇编 .asm 文件
ml64 /c Chapter6_Demo.asm
:: 2. 编译 C++ 并链接 .obj
cl /EHsc test.cpp Chapter6_Demo.obj
✅ 生成 test.exe,可独立运行。
bash
四、远程调试配置(关键步骤)
步骤 1:启动调试服务(在虚拟机中)
cmd
编辑
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe" ^
-server tcp:port=50000,server=0.0.0.0 ^
-noio ^
"C:\Users\<用户名>\Desktop\64asm\64asm\test.exe"
⚠️ 注意:
必须使用 绝对路径(避免"找不到文件")
server=0.0.0.0 表示监听所有网络接口(否则仅限 localhost)
用户名需准确(如 wanni,非 lenovo)
步骤 2:关闭防火墙(临时)
cmd
编辑
netsh advfirewall set allprofiles state off
步骤 3:验证端口监听(虚拟机内)
cmd
编辑
netstat -ano | findstr :50000
✅ 应显示:TCP 0.0.0.0:50000 ... LISTENING
步骤 4:宿主机连接 WinDbg
打开 WinDbg(x64 版本)
菜单:File → Connect to Remote Stub
输入:
text
编辑
tcp:server=192.168.88.136,port=50000
成功标志:出现 connected at ... 日志,并中断在初始断点
五、常见问题与解决方案
问题 原因 解决方案
A2088: END directive required .asm 文件缺少 END 在文件末尾添加 END
LNK1561: 必须定义入口点 单独链接 .obj 无 main 用 cl 同时编译 .cpp 和 .obj
telnet 连接失败 端口未监听或防火墙阻止 检查 ntsd 路径、加 server=0.0.0.0、关防火墙
'ntsd' 不是命令 PATH 未包含调试器路径 使用完整路径调用 ntsd.exe
系统找不到指定路径 用户名或文件路径错误 核对实际路径(如 C:\Users\wanni\...)
调试器连不上 NAT 模式限制 改用 桥接模式(最简单可靠)
六、调试技巧
使用 r rax 查看汇编函数返回值
使用 g 继续执行,q 退出调试
利用 system("pause") 让程序暂停,便于观察寄存器状态
本地调试更简单:直接在虚拟机内用 WinDbg 打开 test.exe
七、总结
通过本次实践,成功实现了:
✅ C++ 与 x64 汇编的混合编程
✅ 手动汇编与链接流程
✅ 跨机器远程调试(WinDbg + ntsd)
✅ 网络、防火墙、路径等系统级问题排查
核心经验:
路径必须准确(尤其含空格和中文用户目录)
server=0.0.0.0 是远程调试的关键参数
桥接模式 > NAT 模式(简化网络配置)
调试前务必确认程序不会立即退出
📝 适用场景:操作系统开发、逆向工程、性能优化、底层安全研究等。
八、开始调式
bash
0:000> bp test!main
0:000> g
Breakpoint 0 hit
test!main:
00007ff6`ddcc0620 4883ec38 sub rsp,38h
✅ 连接远程调试
✅ 加载符号(test!main 可见)
✅ 在 main 函数入口下断点
✅ 程序中断在 main 的第一条指令!
现在你正处于 main 函数的 prologue(函数序言),这是 x64 调用约定的标准开头。
🔍 当前状态解析
asm
编辑
test!main:
00007ff6`ddcc0620 4883ec38 sub rsp,38h
sub rsp, 38h:为局部变量和调用保存空间(0x38 = 56 字节)
这是 MSVC 编译器生成的标准函数入口
你的 C++ 代码:
int main() {
unsigned long long result = Chapter6_Demo(); // ← 即将调用这里
cout << "结果:" << hex << result << endl;
system("pause");
return 0;
}
bash
✅ 接下来操作建议(逐步调试)
步骤 1:单步执行到 Chapter6_Demo 调用
使用 p(Step Over)多次,直到看到 call 指令:
dbg
编辑
0:000> p
...
0:000> p
test!main+0xa:
00007ff6`ddcc062a e8b1090000 call test!Chapter6_Demo (00007ff6`ddcc1000)
💡 p 会逐条执行汇编指令,但不会进入子函数(适合快速到达 call)
步骤 2:进入 Chapter6_Demo 函数
当停在 call test!Chapter6_Demo 时,输入:
dbg
编辑
0:000> t
t = Trace into(单步进入)
程序将跳转到你的汇编函数内部!
步骤 3:逐条调试汇编指令
在 Chapter6_Demo 中,你可以:
使用 t 逐条执行
观察寄存器变化(如 RAX, RCX, RDX)
查看内存(如全局变量)
例如:
dbg
编辑
0:000> t
Chapter6_Demo+0x5:
00007ff6`ddcc1005 48c7c0ff000000 mov rax, 0FFh
0:000> r rax
rax=00000000000000ff
步骤 4:函数返回后查看结果
当 Chapter6_Demo 执行完 ret 后,会回到 main,此时:
dbg
编辑
0:000> r rax
就能看到最终返回值!
然后继续 p,会执行到 cout,输出结果。

bash
0:000> p
test!main+0x4:
00007ff6`ddcc0624 e8c04dffff call test!ILT+17380(Chapter6_Demo) (00007ff6`ddcb53e9)
这行 call 指令正是 C++ 调用你的汇编函数 Chapter6_Demo 的地方!
🔍 为什么显示 test!ILT+17380(...)?
这是 MSVC 编译器的增量链接表(Incremental Linking Thunk, ILT) 机制:
为了加快链接速度,MSVC 会生成一个跳转表(ILT)
test!ILT+17380(Chapter6_Demo) 是一个跳板函数(thunk)
它内部只有一条指令:jmp Chapter6_Demo
✅ 这是完全正常的,不影响调试。
✅ 正确操作:进入真正的 Chapter6_Demo
你现在有两个选择:
✅ 推荐方式:用 t 进入,自动穿透 ILT
输入:
dbg
编辑
0:000> t
WinDbg 会:
先跳到 00007ff6ddcb53e9`(ILT 跳板)
执行 jmp Chapter6_Demo
最终停在你真正的汇编函数第一条指令
💡 WinDbg 默认会"穿透"这种单指令跳转,直接带你到目标函数。
⚠️ 如果你想手动验证(可选)
你可以先 p 一次,看看 ILT 内容:
dbg
编辑
0:000> p
test!ILT+17380(Chapter6_Demo):
00007ff6`ddcb53e9 e912bc0000 jmp test!Chapter6_Demo (00007ff6`ddcc1000)
然后再 t 进入 jmp,就会到达真正的 Chapter6_Demo。
但通常直接 t 一次就够了!
默认情况下,cl.exe 编译不带调试信息(除非加 /Zi)。
✅ 解决方案:重新编译时生成调试符号
在虚拟机中重新编译:
ml64 /c Chapter6_Demo.asm
cl /EHsc /Zi test.cpp Chapter6_Demo.obj
/Zi:生成 .pdb 调试信息文件
之后 x test!main 就能正确显示地址
💡 如果不想生成 PDB,也可以直接通过入口点反汇编
💡 小技巧:直接跳到 Chapter6_Demo(避免 ILT)
如果你希望完全避开 ILT,可以在链接时加 /INCREMENTAL:NO:
cl /EHsc /Zi /INCREMENTAL:NO test.cpp Chapter6_Demo.obj
这样 call 指令会直接指向 Chapter6_Demo,但对功能无影响,仅用于调试清晰度。
你现在只需输入一个 t,就能进入自己的汇编世界了!🚀
bash
0:000> p
test!main+0x4:
00007ff6`ddcc0624 e8c04dffff call test!ILT+17380(Chapter6_Demo) (00007ff6`ddcb53e9)
0:000> p
test!main+0x9:
00007ff6`ddcc0629 4889442420 mov qword ptr [rsp+20h],rax ss:000000b0`d6dbfdb0=0000000000000000
0:000> t
test!main+0xe:
00007ff6`ddcc062e 488d158b2c1100 lea rdx,[test!__xt_z+0x110 (00007ff6`dddd32c0)]
bash
🔍 关键指令解析
1. 函数调用已完成
asm
编辑
00007ff6`ddcc0624 e8c04dffff call test!ILT+17380(Chapter6_Demo)
这是调用你的汇编函数。
2. 保存返回值到栈
asm
编辑
00007ff6`ddcc0629 4889442420 mov qword ptr [rsp+20h], rax
✅ RAX 中的返回值已被存入局部变量 result
[rsp+20h] 就是 C++ 中 unsigned long long result 的内存位置
💡 这说明:Chapter6_Demo 已经执行完毕,且结果已传回!
3. 准备 cout 字符串参数
asm
编辑
00007ff6`ddcc062e 488d158b2c1100 lea rdx, [test!__xt_z+0x110 (...)]
这是在加载 "第六章指令演示运行成功,结果汇总:0x" 字符串地址
下一步将调用 operator<<
✅ 如何查看 Chapter6_Demo 的返回值?
虽然你已经离开了汇编函数,但 RAX 的值仍然保留(直到被覆盖)!
立即输入:
dbg
编辑
0:000> r rax
你会看到类似:
text
编辑
rax=00000000ffffff00
这就是你的汇编函数计算出的最终结果!
🎁 附加:想重新调试汇编内部?
如果想再次进入 Chapter6_Demo 逐条调试:
退出当前调试会话(q)
重新启动 ntsd:
cmd
编辑
ntsd -server tcp:port=50000,server=0.0.0.0 -noio test.exe
在 WinDbg 中连接后,下断点:
dbg
编辑
bp test!Chapter6_Demo
g
当中断在汇编函数时,用 t 逐条执行
恭喜你圆满完成 x64 汇编与 C++ 混合编程调试实验!👏
bash
0:000> r rax
rax=ffffffffffffff00
太棒了!🎉
你刚刚通过 WinDbg 成功读取到了 Chapter6_Demo 汇编函数的返回值:
text
编辑
rax=ffffffffffffff00
🔍 结果解析
这个值是 十六进制,表示一个 64 位有符号整数:
十六进制:0xffffffffffffff00
十进制(有符号):-256
十进制(无符号):18,446,744,073,709,551,360
但在你的 C++ 代码中,变量类型是:
cpp
编辑
unsigned long long result = Chapter6_Demo();
所以程序会按 无符号 解释,但输出时用 hex,因此会打印:
text
编辑
第六章指令演示运行成功,结果汇总:0xffffffffffffff00
✅ 这与你从 RAX 中看到的值完全一致!
💡 这个结果说明什么?
0xffffffffffffff00 通常是由以下汇编操作产生的:
常见场景 1:符号扩展 + 负数
asm
编辑
mov al, 0x00 ; AL = 0x00
neg al ; AL = -0x00 → 实际为 0x00?不对
更可能是:
常见场景 2:对负数进行符号扩展
asm
编辑
mov eax, 0xffffff00 ; EAX = -256 (32位)
; 当返回 64 位时,CPU 自动符号扩展到 RAX:
; RAX = 0xffffffffffffff00
或者你在汇编中写了类似:
asm
编辑
mov rax, -256
或
asm
编辑
mov rax, 0FFh ; 255
neg rax ; → -255? 不对
但 0xffffffffffffff00 = -256 是非常典型的"32 位负数被符号扩展到 64 位"的结果。

bash
0:000> r rax
rax=ffffffffffffff00
0:000> g
ModLoad: 00007ffd`6ab60000 00007ffd`6abfc000 C:\Windows\System32\sechost.dll
ModLoad: 00007ffd`6ad80000 00007ffd`6aea6000 C:\Windows\System32\RPCRT4.dll
Qwen3-Max
11:59:50
你执行了 g(Go)命令后,程序继续运行,并开始加载系统 DLL(如 sechost.dll, RPCRT4.dll),这是 cout 或 system("pause") 触发的正常行为。
但你可能注意到:控制台窗口没有立即显示输出,或者 WinDbg 似乎"卡住"了。
✅ 这是完全正常的!原因如下:
你的程序代码是:
cpp
编辑
cout << "第六章指令演示运行成功,结果汇总:0x" << hex << result << endl;
system("pause"); // ← 程序在这里等待用户按键!
当你在 WinDbg 中输入 g 后:
程序执行 cout,输出文本到控制台(虚拟机窗口)
然后调用 system("pause")
程序暂停,等待你按任意键
WinDbg 也会暂停(因为被调试进程在等待 I/O)
🔍 所以 WinDbg 显示 ModLoad 后不再动,并不是卡死,而是 程序正在等你按键盘!
✅ 正确操作步骤
1️⃣ 切换到虚拟机窗口
点击 VMware 的虚拟机窗口(确保它获得焦点)
你会看到类似输出

bash
2️⃣ 按任意键(如空格或回车)
这会让 system("pause") 返回
程序继续执行 return 0; 并退出
3️⃣ WinDbg 会自动捕获进程退出事件
你会看到类似:
log
编辑
ntdll!NtTerminateProcess+0x14:
00007ffd`6d5bfa94 c3 ret
或
log
编辑
Process exited with status 0
💡 如果你想在退出前再次中断
可以在 main 返回前下断点:
dbg
编辑
0:000> bp test!main+0xXX ; XX 是 return 0 的地址
但更简单的方式是:就在 system("pause") 处中断。
不过由于 system() 是外部函数,建议直接在虚拟机窗口按任意键即可。

🎯 完整流程闭环确认
C++ 调用汇编函数 → ✔️
汇编计算并返回 0xffffffffffffff00 → ✔️ (r rax)
C++ 成功接收并打印该值 → ✔️(虚拟机窗口可见)
程序暂停等待确认 → ✔️ (system("pause"))
用户按键后程序正常退出 → ✔️(即将发生)
✅ 恭喜你!整个 x64 汇编 + C++ + 远程调试实验已圆满完成!
bash
正确退出 WinDbg 与虚拟机中的调试会话,确保下次能直接运行 test.exe(不被占用、可重新编译),请按以下步骤操作:
✅ 正确退出流程(两步走)
第一步:在 WinDbg 中安全退出调试会话
在 WinDbg 命令窗口输入:
dbg
编辑
q
q = quit,会终止被调试进程(test.exe)并关闭调试连接
此时虚拟机中的 ntsd.exe 也会自动退出
💡 如果程序停在 system("pause"),先切换到虚拟机窗口按任意键让程序继续,再在 WinDbg 中输入 q。
第二步:在 虚拟机中确认无残留进程
按 Ctrl + Shift + Esc 打开 任务管理器
结束以下可能残留的进程(如有):
test.exe
ntsd.exe
conhost.exe(有时会残留)
⚠️ 关键:只要 ntsd.exe 或 test.exe 还在运行,test.exe 文件就会被锁定,导致下次编译失败(LNK1104)。
✅ 验证是否可直接运行 test.exe
完成上述退出后,在虚拟机命令行中:
cmd
编辑
cd C:\Users\wanni\Desktop\Asm64\Asm64
test.exe
✅ 应正常运行并输出结果,无需调试器介入。
🔁 下次调试时如何快速启动?
只需重复以下命令(无需重启虚拟机):
1. 编译(如需修改代码)
cmd
编辑
ml64 /c Chapter6_Demo.asm
cl /EHsc /Zi test.cpp Chapter6_Demo.obj
2. 直接运行(非调试)
cmd
编辑
test.exe
3. 如需再次调试,启动 ntsd:
cmd
编辑
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe" -server tcp:port=50000,server=0.0.0.0 -noio test.exe
然后从宿主机 WinDbg 重新连接即可。
🛠 推荐:创建一键清理脚本(可选)
新建 cleanup.bat:
bat
编辑
@echo off
taskkill /f /im test.exe >nul 2>&1
taskkill /f /im ntsd.exe >nul 2>&1
echo 已清理调试进程,可安全编译或运行 test.exe。
每次调试前/后运行此脚本,避免文件锁定。