现在的位置: 首页 > 综合 > 正文

Win32汇编和PE的一些基础知识

2013年03月16日 ⁄ 综合 ⁄ 共 2760字 ⁄ 字号 评论关闭

Win32汇编和PE的一些基础知识
本文来源于Eddy's Blog http://www.rrgod.com/ , 原文地址:http://www.rrgod.com/post/240.html

 

摘自laomms的一篇文章:从IDA中提取代码做汇编注册机之Delphi篇。
.386
这是一个汇编语言伪指令,他告诉编译器我们的程序是使用80386指令集编写的。您还可以使用 .486、.586, 但最安全的还是使用.386。对于每一种CPU有两套几乎功能相同伪指 令: .386/.386P、 486/.486P、 586/.586P。 带P的指令标明您的程序中可以用特权级指令。特权级指令是保留给操作系统的,如虚拟设备驱动程序。在大多数时间,您的程序都 无须运行在RING0层,故用不带后缀P的伪指令已足够了。
.MODEL FLAT,STDCALL
.MODEL 是用来指定内存模式的伪指令,在Win32下,只有一种内存模型,那就是FLAT。 STDCALL 告诉编译器参数的传递约定。参数的传递约定是指参数传达时的顺序(从左到右或 从右到左)和由谁恢复堆栈指针(调用者或被调用者)。在Win16下有两种约定:C 和 PASCAL。C 约定规定参数传递顺序是从右到左,即最右边的参数最先压栈,由调用者恢复堆栈指 针。
.DATA 其中包括已初始化的数据。
.DATA? 其中包括未初始化的数据。比如有时您仅想预先分配一些内存但并不想指定初始值。使用未初始化的数据的优点是它不占据可执行文件的大小,如:若您要在 .DATA? 段中 分配10,000字节的空间,您的可执行文件的大小无须增加10,000字节,而仅仅是要告诉编译器在装载可执行文件时分配所需字节。
.CONST 其中包括常量定义。这些常量在程序运行过程中是不能更改的。 应用程序并不需要以上所有的三个"分段", 可以根据需要进行定义。
.CODE 这是代码"分段"。
<label>
end <label>
是用来唯一标识您的代码范围的标签, 两个标签必须相同,应用程序的所有可执行代码必修在两个标签之间。

预定义段

   一个Windows NT的应用程序典型地拥有9个预定义段,它们是.text、.bss、.rdata、.data、.rsrc、.edata、.idata、.pdata和.debug。一些应用程序不需要所有的这些段, 同样还有一些应用程序为了自己特殊的需要而定义了更多的段。这种做法与MS-DOS和Windows 3.1中的代码段和数据段相似。事实上,应用程序定义一个独特的段的方法是使用标准 编译器来指示对代码段和数据段的命名,或者使用名称段编译器选项-NT——就和Windows 3.1中应用程序定义独特的代码段和数据段一样。
   以下是一个关于Windows NT PE文件之中一些有趣的公共段的讨论。

.text   可执行代码段
  Windows 3.1和Windows NT之间的一个区别就是Windows NT默认的做法是将所有的代码段(正如它们在Windows 3.1中所提到的那样)组成了一个单独的段,名为“.text”。既 然Windows NT使用了基于页面的虚拟内存管理系统,那么将分开的代码放入不同的段之中的做法就不太明智了。因此,拥有一个大的代码段对于操作系统和应用程序开发者来说, 都是十分方便的。
  .text段也包含了早先提到过的入口点。IAT亦存在于.text段之中的模块入口点之前。(IAT在.text段之中的存在非常有意义,因为这个表事实上是一系列的跳转指令,并且它 们的跳转目标位置是已固定的地址。)当Windows NT的可执行映像装载入进程的地址空间时,IAT就和每一个导入函数的物理地址一同确定了。要在.text段之中查找IAT,装载器只 用将模块的入口点定位,而IAT恰恰出现于入口点之前。既然每个入口拥有相同的尺寸,那么向后退查找这个表的起始位置就很容易了。

.bss、.rdata、.data  数据段
  .bss段表示应用程序的未初始化数据,包括所有函数或源模块中声明为static的变量。
  .rdata段表示只读的数据,比如字符串文字量、常量和调试目录信息。
   所有其它变量(除了出现在栈上的自动变量)存储在.data段之中。基本上,这些是应用程序或模块的全局变量。

.rsrc  资源段
  .rsrc段包含了模块的资源信息。它起始于一个资源目录结构,这个结构就像其它大多数结构一样,但是它的数据被更进一步地组织在了一棵资源树之中。

.edata 导出数据段
   .edata段包含了应用程序或DLL的导出数据。在这个段出现的时候,它会包含一个到达导出信息的导出目录。

.idata 导入数据段
   .idata段是导入数据,包括导入库和导入地址名称表。

.debug 调试信息段
   调试信息位于.debug段之中,同时PE文件格式也支持单独的调试文件(通常由.DBG扩展名标识)作为一种将调试信息集中的方法。调试段包含了调试信息,但是调试目录却位 于早先提到的.rdata段之中。

    另外我们需要了解下IDA反汇编PE文件后所加的那些伪指令分别代表些什么:
byte_XXXXXX         单字节型常量或变量
word_XXXXXX         2字符型常量或变量
dword_XXXXXX        4字节型常量或变量 
QWORD_XXXXXX        8字节型常量或变量
TWORD_XXXXXX        10字节型常量或变量
NEAR                标号作段内转移指令的目标地址,NEAR必须借助PTR才能指示无条件转移指令目标地址的属性
FAR                 标号作段间转移或调用指令的目标地址
SHORT可以不必借助PTR直接指示无条件转移指令目标地址属性为段内短转移
off_XXXXXX          是数据标号的偏移地址
unk_XXXXXX          变量地址
s_XXXXXX            字符串
sub_XXXXXX          子程序
loc_XXXXXX          子程序内部标号

    对于fs:,MASM在.model flat模式自动做了下面的定义:
    ASSUME CS:flat,       DS:flat,       ES:flat,       SS:flat,       FS:ERROR,GS:ERROR
    flat是内存平坦模式,意思是段寻址4G空间。因此,CS,DS,ES,SS可以在程序中平坦使用。使用FS和GS则会报错。所以需要做如下定义:
    assume  fs:nothing
本文来源于Eddy's Blog http://www.rrgod.com/ , 原文地址:http://www.rrgod.com/post/240.html

抱歉!评论已关闭.