玩好.NET高级调试,你也要会写点汇编

打印 上一主题 下一主题

主题 906|帖子 906|积分 2718

一:背景

1. 简介

.NET 高级调试要想玩的好,看懂汇编是基本功,但看懂汇编和能写点汇编又完全是两回事,所以有时候看的多,总手痒痒想写一点,在 Windows 平台上搭建汇编环境不是那么容易,大多还是用微软的 MASM + DosBox 搭一个 8086 的环境,这玩意距今快 50 年了。
在以前想快捷的写一点汇编,借助的是 VC 编译器的 __asm 在 C/C++ 代码中内嵌一点,比如下面这样。
  1. int main()
  2. {
  3.         int num = 10;
  4.         __asm {
  5.                 mov[num], 20
  6.         }
  7.         printf("num=%d", num);
  8. }
复制代码

便捷是便捷,但只能玩个局部,还是不够爽,所以本篇我们借助 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

下载完之后,将下图中的 五项 全部勾选上进行安装。

把 bin, include,lib 全部配到环境变量的 PATH 中,然后打开控制台键入 gcc -v 看一下有没有配好。
  1. PS C:\Users\Administrator\Desktop> gcc -v
  2. Using built-in specs.
  3. COLLECT_GCC=C:\MinGW\bin\gcc.exe
  4. COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe
  5. Target: mingw32
  6. 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
  7. Thread model: win32
  8. gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)
  9. PS C:\Users\Administrator\Desktop>
复制代码

  • vscode 插件
这里我准备用 vscode 来写汇编代码,主要安装两个插件。

  • The Netwide Assembler (NASM)
这个 nasm 官方提供的 语法高亮 插件。

  • GDB Debug
gdb 已经内嵌到了 gcc 中,方便于 code 调试。

2. vscode 自动化构建

玩过 vscode 的朋友应该知道,自动化构建需要自己写 tasks.json,这里我简单写了一个。
  1. {
  2.     "version": "2.0.0",
  3.     "tasks": [
  4.         {
  5.             "label": "win86",
  6.             "type": "shell",
  7.             "command": "nasm.exe -f win32 -g -F cv8 -l app.lst app.asm; gcc app.obj -o app.exe",
  8.             "problemMatcher": {
  9.                 "pattern": {
  10.                     "regexp": "error"
  11.                 }
  12.             },
  13.             "group": "build",
  14.             "presentation": {
  15.                 "focus": true,
  16.                 "panel": "dedicated",
  17.                 "reveal": "silent",
  18.                 "clear": true
  19.             }
  20.         }
  21.     ]
  22. }
复制代码
然后就是配置启动 launch.json,代码如下:
  1. {
  2.     "version": "0.2.0",
  3.     "configurations": [
  4.         {
  5.             "type": "gdb",
  6.             "request": "launch",
  7.             "name": "GDB32",
  8.             "program": "${workspaceFolder}/app.exe",
  9.             "stopOnEntry": true,
  10.             "preLaunchTask": "win86"
  11.         },
  12.         {
  13.             "type": "gdb",
  14.             "request": "launch",
  15.             "name": "GDB64",
  16.             "program": "${workspaceFolder}/app.exe",
  17.             "stopOnEntry": true,
  18.             "preLaunchTask": "win64"
  19.         }
  20.     ]
  21. }
复制代码
到这里基础设施就全部搭建完成了,然后就是写一个简单的汇编程序,实现三个 printf 的打印,代码如下:
  1. extern _printf
  2. SECTION .data
  3.     msg             db      'Hello World!', 0Ah , 0h;
  4.    
  5.     num1            dd       100;
  6.     num1_int_fmt    db      'num1=%d', 0Ah, 0h;
  7.     num2            dq       3.14;
  8.     num2_flt_fmt    db       'num2=%lf', 0Ah, 0h;
  9. SECTION .text
  10. global _main
  11. _main:
  12.     push ebp
  13.     mov  ebp , esp
  14.     ; printf("Hello World\n");
  15.     mov  eax , msg
  16.     push eax
  17.     call _printf
  18.     add  esp, 4
  19.     ; printf("num1=%d",num1)
  20.     mov  eax , [num1]
  21.     push eax
  22.     mov  ebx , num1_int_fmt
  23.     push ebx ,
  24.     call _printf
  25.     add  esp , 4
  26.     ; printf("num2=%lf",num2)
  27.     movq    xmm0  , [num2]
  28.     sub     esp   , 0x8
  29.     movsd   [esp] , xmm0
  30.     mov     ebx   , num2_flt_fmt
  31.     push    ebx
  32.     call    _printf
  33.     add     esp   , 0xc
  34.     mov esp , ebp
  35.     pop ebp
  36.     ret
复制代码
输出结果如下:

从上面的代码看,我需要自己协调栈平衡,自己去管理寄存器和内存的使用,真的是太爽了。
二:总结

汇编看多了,总想自己动手试试,如果你也有这种想法,可以搭建一下玩玩,有一点遗憾的是,在 windows 中用 gdb 单步调试汇编目前还没搞定,在 linux 上很轻松,不过也不影响自己学习研究,毕竟可以用强大的 windbg 和 ollydbg 来实现单步调试,对吧!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大号在练葵花宝典

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表