从Windows出现开始,汇编语言似乎在慢慢地销声匿迹,但本书可以让人放弃这个观点,其实在Win32环境下,汇编语言依然强大。
Why——为什么选择Win32汇编
选择Win32汇编的理由是什么呢?
在DOS时代,学习汇编就是学习系统底层编程的代名词,仅要成为一名入门级的汇编程序员,就需要学习从CPU结构、CPU工作方式、各种硬件的编程方法到DOS工作方式等范围很广的知识。随着Windows时代的到来,Windows像一堵巨大的墙,把我们和计算机的硬件隔离开。对于DOS的汇编程序员来说,就像在一夜之间,我们发现自己曾经学过的几乎所有的东西都被Windows封装到内核中去了,由于保护模式的存在,我们又无法像在DOS下那样闯入系统内核为所欲为。在Windows下用任何语言编程都必须遵循Windows的规范,汇编也不例外,也就是说,汇编不再是一种“有特权”的语言。面对汹涌而来的Visual C++,Visual Basic,PowerBuilder和Java等各个领域的猛将,从DOS时代“为所欲为”的“系统警察”岗位下岗,在其他领域又没有一技之长,汇编语言似乎失去了生存的意义,有很多人在DOS转向Windows的时候放弃了汇编语言。
但是经过短暂的失落,摆正了自己在系统中的位置,我们发现从“系统警察”转换到遵循Windows规范的“好市民”后,汇编语言又慢慢地在这个世界流行起来了。毕竟,不能为所欲为也可以有好的一面,我们可以不必再考虑一些老大难的问题,如程序运行时会面对什么样的显示卡,如何驱动不同的打印机,内存不够了如何用磁盘交换,等等。我们也可以在了解更少硬件知识的情况下就可以掌握Win32的汇编编程。而且,我们惊喜地发现,做了“好市民”以后,我们反而拥有了和其他语言同样的权利——为了做图形和界面等方面的功能,汇编程序员在DOS时代连做梦都在羡慕C语言庞大的函数库,而现在,Windows为我们提供了比这还要多得多的函数,以至于其他大部分语言可以做出来的功能,汇编都可以做,而其他语言做不到的功能,汇编照样可以做!所以这就是理由之一:Win32汇编可以当做一种功能强大的开发语言使用,使用它完全可以开发出大型的软件来。
正因为Win32汇编看上去不再那样低级,于是有读者曾经提出:Win32汇编讲的都是用API来写程序,和高级语言差不多,以前在DOS下使用的中断什么的都不能用,所以没有什么新奇的了。还有读者认为本书只不过是MSDN的汇编版本而已。言下之意就是:学汇编就是为了了解高级语言底下一层的功能,但现在Win32汇编却使用和C++等语言相同的API接口,既然和高级语言处于同一个级别,我们为什么还要去和机器指令打交道呢,还不如去学Visual C++方便。
但是我们可以这样问一问自己:
问:在DOS汇编中我们为什么用中断功能?
答:为了使用DOS内核提供的功能。
问:在DOS中我们常常自己用操作I/O端口的方法读写硬盘或操作显卡吗?
答:不,我们用系统提供的int 13h和int 10h。
……
同样,在Win32汇编里使用API也是为了使用Windows内核提供的功能。只不过使用的方式不再是中断方式而已,这不是Win32汇编语言“高级化”了,而是高级语言因为使用Windows的API接口而“低级化”了,其代价就是无法移植到其他系统,用Visual C++写的程序是无法移植到其他操作系统平台上的,只有和平台无关的ANSI C++等才能算是真正意义上的高级语言。
其实,任何汇编语言都是和操作系统密切相关的,不管是DOS汇编、Win32汇编,还是Linux汇编,都是基于特定的操作系统的,如果一定要绕过操作系统,那么就不会有DOS汇编和Win32汇编的区别了,但是这样的话我们不是在学汇编,而是在自己开发操作系统。高级语言在不同的操作系统上看起来都差不多,但作为一种低级语言,不同操作系统上的汇编就是不同的世界。所以,既然Windows和DOS是两个完全不同的操作系统,我们就必须抛弃DOS汇编中的大部分概念从头开始学习Win32汇编。这就是理由之二:Win32汇编是Windows环境下一种全新的编程语言。
Win32环境下的很多高级语言,如Visual C++和Visual Basic等,一如既往地对实现的细节进行了或深或浅的封装,就连最能表现Windows特征的部分,如消息循环和多线程的处理等内容也都被隐藏封装,使我们在使用它们进行可视化编程的同时,无法全面了解Win32程序运行的具体方式。在学习Win32汇编以后,这些隐藏在高级语言后面的细节就暴露出来了。
由于封装的关系,各种高级语言或多或少存在某种“缺陷”,比如VB不支持指针,结果很多需要使用指针的API用起来就很不方便,像多线程一类的特征在VB中就无法实现,PowerBuilder也是如此;C语言已经是最灵活的高级语言了,但还是无法在代码级别处理某些需求;而汇编语言见到的是一个最真实的操作系统,它可以用最灵活的方式使用各种系统功能,第13章中有关进程隐藏的内容就是最好的写照。所以理由之三就是:使用Win32汇编语言是了解操作系统运行细节的最佳方式。
最后的理由根本不是理由,而是必然的选择,当我们在Windows环境下进行加密解密、逆向工程,还有病毒、木马等有害代码的分析和防治工作时,Win32汇编是唯一的选择。在任何讨论这方面内容的书籍中,汇编代码的篇幅总是很大的。因此,要想深入了解这些内容的前提就是深入汇编编程。
How——如何学习Win32汇编
以往的汇编书籍往往把重点放在硬件结构和指令上,讲述了一大堆电路框图和指令列表,把大家搞得晕晕乎乎后,再举出一些重量级的例子,不是一些像数组、矩阵计算一类的复杂运算,就是开始图形模式画图,以至于大家看完以后就再也找不到北了!实际上,这些例子不是太难了,而是太枯燥了。有人说,学汇编就像考大学,千军万马过独木桥,太多的人中途放弃了,只有少数人坚持到最后。
笔者认为:学习汇编应该在轻松的环境下进行,在学习中使用的例子不一定太复杂,但一定要有吸引力。用汇编写复杂的运算程序固然会比C更有效率,但同样的事在C中用一个表达式就全部搞定了,从这里开始学汇编,给人的感觉就像从复杂的公式开始学算术,要知道,加法还没有学会呢!而对于高级语言封装起来的系统功能,用汇编解释起来就非常直接,非常自然,也更容易懂。以笔者自己学汇编的过程来说,那时候是1990年,刚好是中国第一次病毒大流行,大家的计算机上都是那个病毒的开山鼻祖——乒乓病毒,在流行DOS的时期,看着在屏幕上蹦的小球,心中就有一个问题:如何编出这样一个玩意来呢?要知道DOS是单任务的,而那个球在别的程序运行的时候照样蹦!这用当时流行的FORTRAN、C等课程中学到的任何知识都无法解释,因为这些课程中不可能有TSR、中断、引导区等内容。带着这样一个疑问学习汇编,在分析乒乓病毒的过程中啃一条条不懂的指令,病毒分析完了,汇编课也学完了,而且反过来看那些复杂的计算程序都是那么顺理成章,不攻自破了。实际上,从一些实用的系统功能开始学习汇编远比学矩阵计算容易理解。
正如最经典的C程序就是那个“Hello,World!”一样,这个程序的有名并不是因为它用高深复杂的语句放倒了一大批人,而是它以最简单易懂的方式让人们走入C语言的大门。对于Win32汇编也是如此,从最简单的例子开始总是没错的,笔者建议读者跟随本书中从简到繁的例子,努力做到理解并灵活引用这些例子中的各种功能,正如“熟读唐诗三百首,不会写诗也会吟”,最后能够熟练地使用Win32汇编来解决各种编程需求就是最大的胜利。
另外,正如前面讲到的,汇编语言的学习必须和操作系统紧密结合。经过简单的调查,笔者发现很多高校使用的汇编教程还是停留在清华91版《IBM-PC汇编语言程序设计》之类的教材上,虽然这些教材中基础知识部分永远不会过时,但涉及操作系统的部分还是停留在DOS阶段。随着DOS操作系统的悄然引退,继续把精力花在上面是一种浪费,因为任何语言都必须有应用的平台,否则课程学完之后会尴尬地发现没有地方可以应用。笔者认为,在《IBM-PC汇编语言程序设计》之类传统教材中的基础部分学习完毕以后,重点就应该转向Win32汇编,以及保护模式方面的知识。
关于本书的内容
本书尝试从编写应用程序的角度,从“Hello,World”这个简单的例子开始到编写多线程、注册表和网络通信等复杂的程序,通过70多个从简单到复杂的例子,逐步深入Win32汇编编程的方方面面。笔者从事汇编编程已经有十几年的历史了,从8086时代的DOS汇编编程开始到当前的Win32汇编编程,从一个初学者到现在能利用Win32汇编来解决大部分编程需求,中间也经过了很长时间的摸索和大量的挫折,所以笔者很清楚初学者在哪些地方会遇到问题,但是涉及Win32汇编的书籍却实在太少了。正是因为如此,笔者决心把本书的目标定为:能让读者入门并在最后能熟练掌握Win32汇编编程,而不是那种深入系统奥秘一类的书籍。
从这个目标出发,本书的选材中尽量去掉已经有其他书籍详细讨论的部分,因为要一本书涉及全部方面是不现实的。内容全面就必然不精,内容深刻就必须围绕一个中心点,所以本书的内容并不详细讨论一般汇编教材的基础部分,如处理器结构和保护模式等,也不准备涉及Windows驱动程序、COM编程或者其他能够冠以“密技”头衔的内容。本书主要的内容将放在32位宏汇编对比DOS汇编所不同的部分,以及Win32应用程序的汇编实现上。不求全面,只求精也!(说句老实话,也不敢对自己不精通的地方妄加评论,以免破坏自己的良好形象。 )
在一些汇编编程论坛上,经常有初学者问到MASM和TASM有什么不同,用哪个比较好,@@标号是什么意思,为什么用下载的汇编编译器无法编译程序等问题,虽然这些都属于最基本的问题,但是以前的确没有一个地方或者有一本书能系统全面地讲解这些问题。本书的基础篇就是因此而设,它们是:
● 第1章 背景知识
● 第2章 准备编程环境
● 第3章 使用MASM
当搭建编译环境和对编译器的使用不再成为绊脚石的时候,初学者的问题往往集中在对Windows程序结构的迷惑上,消息驱动体系、窗口过程、与硬件隔绝的图形接口及资源文件等相对于DOS程序来说都是全新的内容。接下来的4章将深入讨论这些内容,通过这几章,读者应该开始习惯以Windows的方式考虑问题了(脑海中的DOS逐渐远去……),这就是本书的初级篇:
● 第4章 第一个窗口程序
● 第5章 使用资源
● 第6章 定时器和Windows时间
● 第7章 图形操作
Windows系统不像DOS系统,它的应用程序界面是规范化的,统一的界面来自大量统一的界面控件,学习这些控件就等于学习如何编写Windows界面。下面的界面篇中的两章将探讨这方面的内容:
● 第8章 通用对话框
● 第9章 通用控件
学到这里为止,读者应该可以写出界面规范的标准的Win32程序了。但还是无法用这些程序来解决一些具体问题,因为有关Windows系统的高级特征的介绍还没有开始,如内存管理、文件操作和多线程等。这些就是本书系统篇中将要介绍的内容,通过这些内容,读者将比较深入地了解Windows的工作方式:
● 第10章 内存管理和文件操作
● 第11章 动态链接库和钩子
● 第12章 多线程
● 第13章 进程控制
● 第14章 异常处理
相信到这里为止,读者对Windows的了解已经比较系统了。虽然Windows中还存在其他很多方面的内容,如管道,邮件槽,如何写控制面板程序、屏幕保护程序和驱动程序等。但是有了前面的基础以后,读者自己去了解这些内容就不成问题了,因为掌握了“渔”,得到“鱼”又有什么困难呢?在最后的几章中,本书将从应用的角度再补充介绍一些常用的网络编程、注册表、PE文件和数据库操作方面的内容,这就是应用篇:
● 第15章 注册表和INI文件
● 第16章 WinSock接口和网络编程
● 第17章 PE文件
● 第18章 ODBC数据库编程
在本书中,笔者特别以显著的方式标出了一些经验之谈,这些是笔者在长期的汇编编程中得到的体会,可能是任何一本教科书或者手册里都没有的。希望这些能给读者带来帮助!
用“灯泡”标出的部分表示一些小技巧,可以对编程的理解有促进作用。
用“惊叹号”标出的部分表示容易出错的部分,可以帮助读者避免一些难以理解的错误。
对读者的假设
有了内容的定位,读者的定位也就比较清楚了,本书适合于以下读者:
● 想用Win32汇编写Windows应用程序的读者。
● 想从DOS下的16位汇编转向Windows下32位汇编的读者。
● 欲了解Win32汇编,以便为Windows下的加密解密、系统安全、逆向工程等方面打基础的读者。
● 欲了解Win32汇编,以便为用汇编写Windows驱动程序打基础的读者。
● 正在学习汇编课程,需要补充汇编课程中Win32部分的学生。
在开始本书之前,读者应该有以下的基础知识:
● 计算机的基础知识,如进制转换、逻辑运算、变量类型和指针的概念等。
● 数据结构的基础知识,因为Win32编程涉及大量的数据结构。
● C语言的基础知识,因为Win32编程的绝大部分参考资料都是以C的格式出现的。
● Intel 80x86处理器的基础知识,如寻址方式和指令的使用等。
本书并不是为以下读者准备的:
● 欲详细了解保护模式的读者——因为Windows并不是一个开放的平台,Windows的开放只限于应用程序接口,所以要用Windows做背景研究保护模式只能是自讨苦吃,如果读者需要深入了解这方面的内容,最好的方法就是去研究Linux的核心代码并在Linux上实验。
● 欲了解Windows核心“机密”的读者——汇编并不等同于深入操作系统的内部,所以本书不是《Windows内核分析》。而真正意义上的《Windows内核分析》除了Microsoft,恐怕谁也写不出来。
● 欲了解Windows驱动程序编写的读者——要介绍清楚Windows驱动程序,需要的篇幅绝不会亚于本书的篇幅,本书不打算涉及这方面的内容,读者有兴趣的话,可以阅读《Programming WDM》和《System Programming for Windows 95》等书,前者讲述的是Windows 2000/Windows NT下的WDM驱动程序,后者讲述的是Windows 9x下的VxD驱动程序。
第3版有什么新的内容
本书第1版出版至今已经6年多了,第2版出版至今也已经3年了,期间笔者收到了大量的读者来信,对本书提出了各种意见和建议,综合各种方面的考虑,本书的第3版做了以下改进。
● 对第2版中已知的错误进行了修正,包括一些排版错误、错别字和例子中的Bug。
● 对一些过时的内容进行了更新或者删除。
● 根据读者的反馈,对部分章节进行了重写。
关于附书代码和读者反馈
为了更好地说明Win32汇编的编程方法,本书附带了70多个例子,这些例子的源代码全部可以在附书光盘中找到,代码全部采用MASM格式编写,推荐使用的编译软件为MASM32 SDK软件包。
本书中的例子代码已经经过了严格的防病毒测试,绝对不含任何病毒,但第11章的例子涉及钩子技术,第17章的例子涉及对PE文件进行操作,其中的小段代码与一些木马和病毒的特征码类似,以至于被一些杀毒软件误认为有未知病毒,请读者放心使用,不必顾虑。
虽然本书中所有的例子代码都已经在Windows 98、Windows 2000、Windows XP和Windows Vista下测试通过,但也有存在Bug的可能,如果发现代码存在错误或者发现书中有其他问题,请告知作者,以便在下一个版本中改进。如果读者有任何的反馈意 见——不管是批评还是鼓励,都请和作者联系,请访问作者网站获取最新有效的E-mail地址。
罗云彬
致谢
首先感谢我的父母亲,如果没有你们从小到大对我的培养,就没有这一切。也感谢我的妹妹,在很多关键的时候,你总是给予我很多的帮助。
感谢我的妻子小猪猪,在本书创作的时候,没有你的理解和支持,我不可能完成这样一部作品;在本书发行后的日子里,要不是你将逛街、买衣服、旅游的时间慷慨地贡献出来,并盯紧四处乱跑的小宝宝,本书就不会有多次再版的机会。
感谢我的母校浙江大学,浙大“求是创新”的校训,“实事求是、严谨踏实、奋发进取、开拓创新”的校风让我能够有一个好的学习习惯,让我在毕业以后的这么多年里能够始终有一种动力去学习最新的知识。
感谢电子工业出版社博文视点资讯有限公司的郭立老师和李冰编辑,你们的支持、鼓励和专业的指点使本书能够按照进度按时完成。
非常高兴看到本书的再版,本书的前2个版本取得了累计销量达到40000册的好成绩,从本书的第1版发行到现在,我收到了很多读者和网友的反馈,使本书更加完善。在第3版发行之际,再次感谢你们对我的关心和爱护,也感谢你们为我提了很多宝贵的意见和建议。
罗云彬