计算机鼻祖——图灵机
所谓的图灵机就是指一个抽象的机器,它有一条无限长的纸带,纸带分成了一个一个的小方格,每个方格有不同的颜色。
有一个机器头在纸带上移来移去。机器头有一组内部状态,还有一些固定的程序。
在每个时刻,机器头都要从当前纸带上读入一个方格信息,然后结合自己的内部状态查找程序表,根据程序输出信息到纸带方格上,并转换自己的内部状态,然后进行移动。
——摘自 百度百科
编程语言是一组描述计算机,更准确的说是描述CPU如何执行指令的语法规则。
对于确定的处理器,它能执行的指令是确定的,这就是CPU的指令集。CPU的指令集是机器码,于是人们为了容易编程,发明了使用助记符的汇编语言。后来,又出现 了高级语言。高级语言只是用人更容易理解的语法来描述了 这些指令的组织规则,而最终翻译成机器指令则是由编译器来完成的。
不同的编程语言使用了不同的描述规则,这就如同各个不同 国家用不同的语言说“你好”,虽然表达各异,但最终说的 是同一个意思。
程序的两大组件
指令
数据
PE文件完成的任务就是:
用一套数据结构来组织编程语言编译后的指令和数据。因此,PE文件最重要的就是指令和数据的组织方法了。当然,除了指令和数据,还涉及操作系统的相关内容,比如资源等。
什么是PE文件?
全称Portable Execute —— 可移植的执行体,是 windows平台组织程序代码的一种文件格式。常⻅的exe、dll、sys、 ocx、com都属于PE文件。
学习PE文件,是深入windows机制的重 要一步,也是逆向工程基础课程。
PE文件分为以下四大块,依次是:
DOS实模式残留数据
NT文件头
节表
节内容
一、DOS实模式残留数据
在Windows NT之前的Windows系统是基于dos操作系统内核,为了兼容dos系统上可执行文件,Windows NT在设计可执行文件格式时保留兼容了之前的格式。
PE文件中的DOS实模式残留数据包括两部分: DOS头 + DOS Stub,如下图所示:
DOS头的数据结构是这样的:
typedef struct _IMAGE_DOS_HEADER { WORD e_magic; //”MZ” WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; ...... LONG e_lfanew;} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
重点关注的是最后一个字段, 有时称为3C字段,它指示了windows NT PE文件头的偏移位置。
Dos Stub是一段16位的程序,反汇编如下:
这一段16位汇编程序:调用21号中断的9号功能:向屏幕输出 一个字符串“this ...”,然后调用4C号功能退出程序。
二、NT文件头
前面提到: DOS头的最后一个字段指示了NT头的位置。
NT头分为三个部分:
typedef struct _IMAGE_NT_HEADERS{ DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader;}IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
第一部分是一个PE标识符,长度4个字节:
第二部分数据包含了PE文件的一些最基本的信息,其结构如下:
typedef struct _IMAGE_FILE_HEADER { WORD Machine; //运行平台 WORD NumberOfSections; //节数目 DWORD TimeDateStamp; //文件创建时间 DWORD PointerToSymbolTable; //指向符号表指针 DWORD NumberOfSymbols; //符号数目 WORD SizeOfOptionalHeader; //可选头长度 WORD Characteristics; //文件属性}IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
第三部分,叫可选头,虽然名为可选头,但这个结构是整个PE文件中占重要地位,记录的PE文件的代码执行入口、运行平台、堆栈属性等等信息,绝对不能没有(以下为节选部分字段)
typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; DWORD AddressOfEntryPoint; // 代码执行入口 DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; // 加载基地址 DWORD SectionAlignment; DWORD FileAlignment; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];}IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
可选头的最后一个字段是一个数组,名叫数据目录。数组大小是一个宏定义,其值为16:
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; //RVA DWORD Size; //大小} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
这16个数据目录项的内容分别是:
三、节表
在NT文件头之后,就是节表信息了:
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //节名字 union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics;}IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
每个节表项占据40个字节,该结构体的数量在PE文件头的NumberOfSections指定。每一个 结构体描述了PE文件中的一个节的信息。
四、节内容
前面各种头部信息之后,我们迎来了PE文件的主体: 节区
节区没有特定的格式,不同的节承载的内容不一样,也就有不同的数 据结构。
常⻅的节如下:
.text :代码节(VC)
.code : 代码节(VB/Delphi)
.data : 数据节(一般存放已初始化的全局变量,静态变量)
.rdata : 只读数据节(一般存放只读数据,如常量字符串,C++虚表) .idata : 输入数据表(一般用来存放IAT和导入表)
.bss : 通常是指用来存放程序中未初始化的全局变量、静态变量 .textbss : 节中同时包含代码和未初始化全局变量、静态变量
.rsrc : 资源节
.reloc : 重定位表
进程
进程是操作系统结构的基础;
是一个正在执行的程序;
计算机中正在运行的程序实例;
可以分配给处理器并由处理器执行的一个实体;
由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描 述的活动单元。
——百度百科
通俗的理解,一个可执行文件运行起来的实体称之为进程。在没有线程概念的时候,进程代表了多任务系统上的一个任务实体。
进程包含哪些内容?
在Intel 80386处理器诞生之前,程序运行时使用的地址是真实的物理地址。学过微机原理和单片机的知道,8051单片机有64KB的内存寻址空间,在8051上编写程序时我们的地址都是内存区域上的真实地址。
为应对软件技术的快速发展和对内存的需求增大,Intel 80386处理器应运而生,它提出了一种新的工作模式——保护模式。而之前的工作方式称之为——实模式。80386处理器的诞生直接加速了PC的发展。
在32位的操作系统中,在保护模式下,每个进程都拥有4GB的地址空间,不必再考虑和别的程序共享一个地址空间的问题。
每个进程4GB地址空间是虚拟的,通过⻚式存储机制,进程可以安全的享用这些内存。
正是因为是4GB地址空间,也就解释了为什么指针需要4B了。
看一下进程的地址空间分布:
我们经常说程序运行后在内存中,需要强调的是进程的4GB内存空间不是位于真正的内存条上。
事实上,进程的可执行文件和dll所占的“内存”⻚面实际上是映射到硬盘中的文件的。这就是内存映射文件机制。另外,4GB大小的空间中大部分都是空头支票,只有真正需要用到的时候才会予以分配。而在内存紧张时,不常用的页面还会被操作系统通过页交换文件的方式换到硬盘上去。
PE文件到进程地址空间的映射
PE文件按照⻚面大小映射到内存中,在硬盘上,文件对⻬粒度是512B(一个扇区大小),在内存中,⻚面粒度是4KB (32位的Windows系统上)。如下图所示:
关于PE文件到进程空间的对照关系,你弄懂了吗?
往期推荐
打钱!我的数据库被黑客勒索了!
黑客爱用的HOOK技术大揭秘!
安全软件群雄混战史