论文部分内容阅读
个人电脑上,Windows系统依然一家独大,而在Windows系统下,我们双击过无数次的EXE程序文件(或者链接到EXE的程序快捷图标)以运行各种软件。今天我们就来揭秘EXE程序的前世今生,以及它的内部运行机制,它的指令是如何传递到CPU中并带回结果。只有知己知彼,在各种软件出现状况时就能明了问题之所在,遇到病毒侵扰时也能很快找到头绪了。
EXE是个什么东西
电脑中的文件类型数以千计,令人眼花缭乱,但归纳一下会发现它们实际也就分三大类:一是如文本、图像、音乐、视频等以数据为主的数据文件;一是Windows、Linux等系统的可执行文件(即程序)或脚本;一是可以将不同类型文件打包在一起的压缩包文件。
Windows系统中的可执行文件,最主要的就是EXE文件(发音e-x-e),当我们双击一个EXE文件时,文件内置的自动执行代码便会被启动,接下来便可进行各种操作。
EXE的前身是DOS下的COM命令文件。COM文件结构比较简单,它的大小不能超过64KB,局限性太大,渐渐被更灵活的多段结构的EXE所取代。曾经有一段时间,一些电脑病毒编写者利用某些网民电脑知识的缺乏,将COM病毒伪装成一个网址(如www.example.com)作为附件发给用户,如果不小心点击就会中毒,因为它不是网址,而是一个文件名为www.example的com病毒程序。
虽然文件扩展名同为EXE,但DOS下的EXE可执行文件主要为MZ格式,它的一个比较明显的标志就是文件头中包含一个ASCII字符串“MZ”(16进制中表示为4D5A,也称为“幻数”,它实际是DOS开发者之一的名字缩写)。Windows下的EXE主要为Portable Executable格式(简称PE),它是从Unix中的COFF格式修改而来,意为可移植的可执行文件。
解剖EXE文件的结构
不管什么类型的可执行文件,一般都由两大部分组成:头部+代码主体。以DOS-MZ可执行文件格式为例,文件头部描述出文件的总体结构,包括各种说明数据,比如第一句可执行代码执行指令时所需要的文件入口点、堆栈的位置、重定位表等。操作系统根据文件头的信息把代码部分装入内存,然后再根据重定位表修正代码,最后在设置好堆栈后从文件头中指定的入口开始执行。
不过现在我们很少能接触到DOS-MZ,更常打交道的是Windows标准的PE格式可执行文件(除了EXE外,DLL、CPL、SCR、SYS、OCX等等也是PE格式),本文将主要介绍这方面的内容。
PE文件使用的是一个平面地址空间,所有代码和数据都合并在一起,组成一个很大的结构。
Windows下所有PE文件都以一个简单的DOS-MZ头开始,在偏移0处(也就是文件最开始的位置)设置有“MZ”标志,一旦错误地在DOS下运行这一EXE程序,将会直接运行紧随DOS-MZ后面的DOS stub部分。DOS stub实际就是一个有效的微型EXE,它负责在不支持PE文件格式的操作系统中(如DOS),给出一个简单的错误提示。
许多人有过这样的体验,在DOS环境下运行一个Windows程序,会显示出类似This program cannot run in DOS mode(此程序不能在DOS模式下运行)的提示,这一提示就包含在DOS stub中。
紧接DOS stub之后就是PE自己的文件头了,在一个支持PE格式的系统上(Windows),PE装载器会跳过DOS-MZ和DOS stub部分,直接定位到真正的文件头PE header。PE header由三部分组成:字串“PE\0\0”(标志)、映像文件头、可选映像头。这几部分包含了PE装载器需要的许多信息,以便正确地将程序装载到内存中。
紧接着PE头部信息后面的是Section table(节表)。PE文件的内容是以Sections(节)来划分的,每节是一块拥有共同属性的数据,比如代码节(一般名为.text或CODE,每个PE文件必然都有此节)、数据节(一般名为.data或DATA)、引入函数节(一般名为.rdata)、引出函数节(一般名为.edata)、资源节等等。节表就是对本程序中节的属性、位置、大小等的记录。如果PE文件里有5个节,那么这个结构数组内就有5个成员。
EXE怎么被装到内存中
EXE文件是不能直接运行的,它执行各种命令需要经过操作系统,它与各种硬件打交道也要经过操作系统。操作系统提供了一套接口供EXE调用。这套接口,就是所谓的操作系统的Shell,俗称为壳。Shell分命令行式和图形界面两种,Windows资源管理器(Windows Explorer)就是应用非常广泛的一套图形界面Shell。
当我们在Windows的资源管理器(以下称之为Shell)中双击一个EXE文件时,Shell调用CreateProcess激活此EXE,系统产生一个“进程核心对象”,并在内存中为此进程建立一个4GB的地址空间。
PE装载器检查DOS-MZ头信息,查询PE文件头的位置,找到后跳转到那里执行下一步操作,在检查PE头有效的情况下即跳转到PE头的尾部。接着将紧随其后的节信息映射到内存中,再处理引入表部分,如果此EXE调用了外部的动态链接库(DLL),还需要把涉及到的DLL也加载到进程空间中。至于EXE调用了哪些DLL,加载器根据idata节中的记录即可获取相关信息。如果没有找到相应的DLL文件,此时程序就会显示错误信息,即著名的“没有找到某DLL文件”。
代码、数据、相应资源加载完毕,这时系统将为这个进程建立一个主线程。注意,这个线程才是真正的程序,是CPU执行的单位。接下来即调用启动代码,调用EXE中的主函数WinMain,程序开始运行,此时便可看到我们熟悉的程序窗口了(如果此EXE有窗口界面的话)。
当我们关闭程序窗口时,WinMain被结束掉,回到启动代码(Startup code),再返回系统,系统调用ExitProcess结束进程。
PE病毒程序是怎么回事
病毒实际也是程序,只不过它的目的是搞破坏或盗窃隐私而已。不过病毒是“老鼠过街人人喊打”,所以它要想方设法隐藏自己(比如没有前台界面,完全在后台运行),还要想办法运行自己,这就造成了病毒程序的独特性。
传统病毒由引导、触发、感染、破坏四大模块组成。病毒程序不能指望用户主动去启动它,只能依靠一些欺骗手段。比较典型的做法有两种:一种是通过修改注册表,将自己加到随机启动中,开机自动运行;一种是把自己寄生在正常的EXE文件中(即所谓感染),通过修改EXE文件的PE头信息,当用户运行被感染的EXE时,将被跳转到病毒引导模块中,偷偷加载完病毒代码后,再转向EXE的正常执行指令,从而在你毫不知情的情况下完成病毒的加载。
EXE是个什么东西
电脑中的文件类型数以千计,令人眼花缭乱,但归纳一下会发现它们实际也就分三大类:一是如文本、图像、音乐、视频等以数据为主的数据文件;一是Windows、Linux等系统的可执行文件(即程序)或脚本;一是可以将不同类型文件打包在一起的压缩包文件。
Windows系统中的可执行文件,最主要的就是EXE文件(发音e-x-e),当我们双击一个EXE文件时,文件内置的自动执行代码便会被启动,接下来便可进行各种操作。
EXE的前身是DOS下的COM命令文件。COM文件结构比较简单,它的大小不能超过64KB,局限性太大,渐渐被更灵活的多段结构的EXE所取代。曾经有一段时间,一些电脑病毒编写者利用某些网民电脑知识的缺乏,将COM病毒伪装成一个网址(如www.example.com)作为附件发给用户,如果不小心点击就会中毒,因为它不是网址,而是一个文件名为www.example的com病毒程序。
虽然文件扩展名同为EXE,但DOS下的EXE可执行文件主要为MZ格式,它的一个比较明显的标志就是文件头中包含一个ASCII字符串“MZ”(16进制中表示为4D5A,也称为“幻数”,它实际是DOS开发者之一的名字缩写)。Windows下的EXE主要为Portable Executable格式(简称PE),它是从Unix中的COFF格式修改而来,意为可移植的可执行文件。
解剖EXE文件的结构
不管什么类型的可执行文件,一般都由两大部分组成:头部+代码主体。以DOS-MZ可执行文件格式为例,文件头部描述出文件的总体结构,包括各种说明数据,比如第一句可执行代码执行指令时所需要的文件入口点、堆栈的位置、重定位表等。操作系统根据文件头的信息把代码部分装入内存,然后再根据重定位表修正代码,最后在设置好堆栈后从文件头中指定的入口开始执行。
不过现在我们很少能接触到DOS-MZ,更常打交道的是Windows标准的PE格式可执行文件(除了EXE外,DLL、CPL、SCR、SYS、OCX等等也是PE格式),本文将主要介绍这方面的内容。
PE文件使用的是一个平面地址空间,所有代码和数据都合并在一起,组成一个很大的结构。
Windows下所有PE文件都以一个简单的DOS-MZ头开始,在偏移0处(也就是文件最开始的位置)设置有“MZ”标志,一旦错误地在DOS下运行这一EXE程序,将会直接运行紧随DOS-MZ后面的DOS stub部分。DOS stub实际就是一个有效的微型EXE,它负责在不支持PE文件格式的操作系统中(如DOS),给出一个简单的错误提示。
许多人有过这样的体验,在DOS环境下运行一个Windows程序,会显示出类似This program cannot run in DOS mode(此程序不能在DOS模式下运行)的提示,这一提示就包含在DOS stub中。
紧接DOS stub之后就是PE自己的文件头了,在一个支持PE格式的系统上(Windows),PE装载器会跳过DOS-MZ和DOS stub部分,直接定位到真正的文件头PE header。PE header由三部分组成:字串“PE\0\0”(标志)、映像文件头、可选映像头。这几部分包含了PE装载器需要的许多信息,以便正确地将程序装载到内存中。
紧接着PE头部信息后面的是Section table(节表)。PE文件的内容是以Sections(节)来划分的,每节是一块拥有共同属性的数据,比如代码节(一般名为.text或CODE,每个PE文件必然都有此节)、数据节(一般名为.data或DATA)、引入函数节(一般名为.rdata)、引出函数节(一般名为.edata)、资源节等等。节表就是对本程序中节的属性、位置、大小等的记录。如果PE文件里有5个节,那么这个结构数组内就有5个成员。
EXE怎么被装到内存中
EXE文件是不能直接运行的,它执行各种命令需要经过操作系统,它与各种硬件打交道也要经过操作系统。操作系统提供了一套接口供EXE调用。这套接口,就是所谓的操作系统的Shell,俗称为壳。Shell分命令行式和图形界面两种,Windows资源管理器(Windows Explorer)就是应用非常广泛的一套图形界面Shell。
当我们在Windows的资源管理器(以下称之为Shell)中双击一个EXE文件时,Shell调用CreateProcess激活此EXE,系统产生一个“进程核心对象”,并在内存中为此进程建立一个4GB的地址空间。
PE装载器检查DOS-MZ头信息,查询PE文件头的位置,找到后跳转到那里执行下一步操作,在检查PE头有效的情况下即跳转到PE头的尾部。接着将紧随其后的节信息映射到内存中,再处理引入表部分,如果此EXE调用了外部的动态链接库(DLL),还需要把涉及到的DLL也加载到进程空间中。至于EXE调用了哪些DLL,加载器根据idata节中的记录即可获取相关信息。如果没有找到相应的DLL文件,此时程序就会显示错误信息,即著名的“没有找到某DLL文件”。
代码、数据、相应资源加载完毕,这时系统将为这个进程建立一个主线程。注意,这个线程才是真正的程序,是CPU执行的单位。接下来即调用启动代码,调用EXE中的主函数WinMain,程序开始运行,此时便可看到我们熟悉的程序窗口了(如果此EXE有窗口界面的话)。
当我们关闭程序窗口时,WinMain被结束掉,回到启动代码(Startup code),再返回系统,系统调用ExitProcess结束进程。
PE病毒程序是怎么回事
病毒实际也是程序,只不过它的目的是搞破坏或盗窃隐私而已。不过病毒是“老鼠过街人人喊打”,所以它要想方设法隐藏自己(比如没有前台界面,完全在后台运行),还要想办法运行自己,这就造成了病毒程序的独特性。
传统病毒由引导、触发、感染、破坏四大模块组成。病毒程序不能指望用户主动去启动它,只能依靠一些欺骗手段。比较典型的做法有两种:一种是通过修改注册表,将自己加到随机启动中,开机自动运行;一种是把自己寄生在正常的EXE文件中(即所谓感染),通过修改EXE文件的PE头信息,当用户运行被感染的EXE时,将被跳转到病毒引导模块中,偷偷加载完病毒代码后,再转向EXE的正常执行指令,从而在你毫不知情的情况下完成病毒的加载。