总目录
1. WinDbg概述
2. WinDbg主要功能
3. WinDbg程序调试示例
4. CPU寄存器及指令系统
5. CPU保护模式概述
6. 汇编语言不等于CPU指令
7. 用WinDbg观察托管程序架构
8. Windows PE/COFF文件格式简述
9. 让WinDbg自动打开DotNet Runtime源程序
10. WinDbg综合实战
前言
前面两篇文章,通过对Intel CPU的介绍,让我们对计算机底层架构有了基础了解。
本文比较短,主要是想进一步通过示例说清楚一个问题:
汇编助记符 ≠ CPU指令
或者说,汇编助记符并不能永远看成是CPU机器指令的精确表达。
抛开汇编语言有自己的语法体系,有自己的directive指令而机器语言没有不提,单从CPU instruction和汇编助记符的角度考量,很多同学都认为,汇编语言就是机器语言,常将两者等同看待。虽然在很多时候,这种认识不会引发什么问题。不过,在某些特殊场景下,则务必区分清楚汇编与机器指令的区别,两者并非一一对应。
示例程序
这次,我们用一个C++程序来进行说明。本来可以不展示原程序,直接上汇编代码,但为了让同学们知道本次试验的来龙去脉,还是将C++源程序及完整汇编都展示出来,但请读者一定要明白:是否能看懂这个源程序或汇编,与能否理解本文要讲的核心要点之间,无必然联系,也就是说,看不懂这段程序就直接略过,不会影响后面的分析。
C++源程序如下:
int main(int argc, char* argv[])
{
_asm INT 3;
_asm
{
__asm _emit 0xcd __asm _emit 0x03
}
return 0;
}
以x86调试模式调试,在Visual Studio中通过汇编代码窗口拷贝出该程序的完整汇编如下:
--- E:\test\a\TestingCpp\Source.cpp --------------------------------------------
TestingCpp.exe!main(int, char * *):
009C1770 55 push ebp
009C1771 8B EC mov ebp,esp
009C1773 81 EC C0 00 00 00 sub esp,0C0h
009C1779 53 push ebx
009C177A 56 push esi
009C177B 57 push edi
009C177C 8B FD mov edi,ebp
009C177E 33 C9 xor ecx,ecx
009C1780 B8 CC CC CC CC mov eax,0CCCCCCCCh
009C1785 F3 AB rep stos dword ptr es:[edi]
009C1787 CC int 3
009C1788 CD 03 int 3
009C178A 33 C0 xor eax,eax
009C178C 5F pop edi
009C178D 5E pop esi
009C178E 5B pop ebx
009C178F 81 C4 C0 00 00 00 add esp,0C0h
009C1795 3B EC cmp ebp,esp
009C1797 E8 A3 FA FF FF call __RTC_CheckEsp (09C123Fh)
009C179C 8B E5 mov esp,ebp
009C179E 5D pop ebp
009C179F C3 ret
--- No source file -------------------------------------------------------------
本文要点其实只有上面汇编代码中的两条语句:
009C1787 CC int 3
009C1788 CD 03 int 3
先说本文要点:
- 009C1787 和 009C1788是内存地址,意思是说:数据CC保存在内存地址为009C1787的单元,数据CD保存在内存地址为009C1788的单元,数据03保存在内存地址为009C1789的单元;
- CC,CD和03都是十六进制数据,也就是计算机程序运行时要传到CPU中的指令,其中CC是第一条指令,CD和03合起来是第二条指令;
- 两个int 3都是对应着前面的CPU指令的汇编语言程序。汇编语言是对CPU指令的翻译,并不是计算机真正执行的指令。在这个示例中,CC指令被Visual Studio翻译成 int 3,CD 03也被Visual Studio翻译成 int 3,但如同老外说awesome,有人翻译成“真了不起”,也有人翻译成“漂亮!”,但最真实的意思是永远翻译不过来的,最真实的意思只有awesome才能代表。
下面,我们介绍一下两个int 3之间的差异。
INT 3 指令
我们首先必须清楚,在CPU看来,CC和CD 03绝对是两条不同的指令。从下面截图的 Description部分,我们知道,CC的作用是产生断点陷阱,而CD 03产生的是03号软中断。
本文也不想详细说明两个 int 3 的差别,我的目的只有一个,不要完全相信汇编语句,真出现模糊时,还是必须要查手册,要定位到CPU指令级别。
当然,既然抛出了问题,我就简单说一下差别。
相似点
在CPU层面,无论是CC还是CD 03,其作用都是产生断点,让程序执行过程暂停,所以功能上差异是不大的。
差异
如果必须了解这两条指令在CPU层面的差异,可以看Intel CPU架构手册第二册,其主要差别只在于是否做IOPL权限检查。不过,因为Windows操作系统对断点指令的处理包括了将当前指令指针EIP减1的动作,所以对于单字节指令CC来说,断点断下后EIP执行CC之后的第一个字节,EIP - 1之后,又指回了CC,还是int 3的首地址,所以后续继续运行不会出现任何问题。但对于CD 03来说,断点断下以后,EIP指向了03之后的字节,此时EIP - 1 以后,则指向了03,而不是CD,这最终导致了后续指令错乱。