板凳----------(枯藤 )vs2026+win10(第六章-2)

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;
}
  1. 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。
每次调试前/后运行此脚本,避免文件锁定。
相关推荐
2501_9181269112 小时前
用Python开发一个三进制程序开发工具
开发语言·汇编·python·个人开发
黎雁·泠崖1 天前
Java底层探秘进阶:JIT汇编逐行拆解!Java方法栈帧与C语言深度对标
java·c语言·汇编
小初生ZLD1 天前
CSDN年度技术趋势预
汇编
切糕师学AI2 天前
ARM 汇编指令:STM
汇编·arm开发·stm
黎雁·泠崖2 天前
Java 方法栈帧深度解析:从 JIT 汇编视角,打通 C 与 Java 底层逻辑
java·c语言·汇编
切糕师学AI2 天前
ARM 汇编指令:LDM
汇编·arm开发
山峰哥4 天前
SQL调优核心战法——索引失效场景与Explain深度解析
大数据·汇编·数据库·sql·编辑器·深度优先
切糕师学AI7 天前
ARM 汇编指令:UBFX
汇编·arm开发
切糕师学AI7 天前
ARM 汇编指令:STP\LDP
汇编·arm开发