一:背景
1. 简介
.NET 高级调试要想玩的好,看懂汇编是基本功,但看懂汇编和能写点汇编又完全是两回事,所以有时候看的多,总手痒痒想写一点,在 Windows 平台上搭建汇编环境不是那么容易,大多还是用微软的 MASM + DosBox
搭一个 8086 的环境,这玩意距今快 50 年了。
在以前想快捷的写一点汇编,借助的是 VC 编译器的 __asm
在 C/C++ 代码中内嵌一点,比如下面这样。
int main()
{int num = 10;__asm {mov[num], 20}printf("num=%d", num);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XPpDzTnO-1670470379736)(https://huangxincheng.oss-cn-hangzhou.aliyuncs.com/img/20221208095947.png)]
便捷是便捷,但只能玩个局部,还是不够爽,所以本篇我们借助 nasm
来搭建一个 32bit 的汇编环境,当然 64bit 也是可以的, nasm
在 Linux 社区中非常有名。
二:搭建 x86 汇编环境
1. 前置基础构件
- nasm 下载
nasm 是一个非常有名的汇编器,官方网址:https://nasm.us/
目前稳定版是 2.15.05
。
- gcc
大家都知道,源代码要变成可执行程序,步骤一般是: asm -> obj -> exe
,前半部分由 nasm 负责,后半部分由 gcc 负责, gcc 是 Linux 上的刚需产品,在 Windows 上可以用 MinGW
。
下载网址:https://sourceforge.net/projects/mingw/files/MinGW
下载完之后,将下图中的 五项
全部勾选上进行安装。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lKxjozu-1670470379738)(https://huangxincheng.oss-cn-hangzhou.aliyuncs.com/img/20221208102251.png)]
把 bin, include,lib
全部配到环境变量的 PATH 中,然后打开控制台键入 gcc -v
看一下有没有配好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2iFOqQjH-1670470379738)(https://huangxincheng.oss-cn-hangzhou.aliyuncs.com/img/20221208102500.png)]
PS C:\Users\Administrator\Desktop> gcc -v
Using built-in specs.
COLLECT_GCC=C:\MinGW\bin\gcc.exe
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nls
Thread model: win32
gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)
PS C:\Users\Administrator\Desktop>
- vscode 插件
这里我准备用 vscode
来写汇编代码,主要安装两个插件。
- The Netwide Assembler (NASM)
这个 nasm 官方提供的 语法高亮 插件。
- GDB Debug
gdb 已经内嵌到了 gcc 中,方便于 code 调试。
2. vscode 自动化构建
玩过 vscode 的朋友应该知道,自动化构建需要自己写 tasks.json
,这里我简单写了一个。
{"version": "2.0.0","tasks": [{"label": "win86","type": "shell","command": "nasm.exe -f win32 -g -F cv8 -l app.lst app.asm; gcc app.obj -o app.exe","problemMatcher": {"pattern": {"regexp": "error"}},"group": "build","presentation": {"focus": true,"panel": "dedicated","reveal": "silent","clear": true}}]
}
然后就是配置启动 launch.json
,代码如下:
{"version": "0.2.0","configurations": [{"type": "gdb","request": "launch","name": "GDB32","program": "${workspaceFolder}/app.exe","stopOnEntry": true,"preLaunchTask": "win86"},{"type": "gdb","request": "launch","name": "GDB64","program": "${workspaceFolder}/app.exe","stopOnEntry": true,"preLaunchTask": "win64"}]
}
到这里基础设施就全部搭建完成了,然后就是写一个简单的汇编程序,实现三个 printf
的打印,代码如下:
extern _printf
SECTION .datamsg db 'Hello World!', 0Ah , 0h;num1 dd 100;num1_int_fmt db 'num1=%d', 0Ah, 0h;num2 dq 3.14;num2_flt_fmt db 'num2=%lf', 0Ah, 0h;SECTION .textglobal _main_main:push ebpmov ebp , esp ; printf("Hello World\n");mov eax , msgpush eax call _printfadd esp, 4; printf("num1=%d",num1)mov eax , [num1]push eax mov ebx , num1_int_fmtpush ebx , call _printfadd esp , 4; printf("num2=%lf",num2)movq xmm0 , [num2]sub esp , 0x8movsd [esp] , xmm0mov ebx , num2_flt_fmtpush ebx call _printfadd esp , 0xcmov esp , ebppop ebp ret
输出结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fIp7D9cm-1670470379739)(https://huangxincheng.oss-cn-hangzhou.aliyuncs.com/img/20221208110551.png)]
从上面的代码看,我需要自己协调栈平衡,自己去管理寄存器和内存的使用,真的是太爽了。
二:总结
汇编看多了,总想自己动手试试,如果你也有这种想法,可以搭建一下玩玩,有一点遗憾的是,在 windows 中用 gdb 单步调试汇编目前还没搞定,在 linux 上很轻松,不过也不影响自己学习研究,毕竟可以用强大的 windbg 和 ollydbg 来实现单步调试,对吧!