文章目录
UPack 头文件分析(特点总结)
概述
UPack是用来将pe文件压缩成很不规则形式的压缩器,书上说是国人编写的,牛。
压缩方法
在终端输入指令
upack notepad.exe
压缩后不会生成新文件,压缩的是其本身,所以做好备份
此时peview已经看不到很多东西了:
PE文件头部分的特征
表现特征
1.开头的MZ和PE签名离得太近了
1.没有dos存根
3.出现很多字符串和代码
4.等等等
具体改变
重叠文件头
将MZ文件头(IMAGE_DOS_HEADER)和PE文件头(IMAGE_NT_HEADER) 重叠在一起
{节约空间增加代码,提高复杂性}
具体
PE规定NT头的起始位置是可变的,由e_flanew决定,下面是MZ和e_flanew
一般情况下e_flanew有以下值:
UPack将其改为10
达到重叠的效果。
修改文件头(IMAGE_FILE_HEADER)中可选头(IMAGE_OPTIONAL_HEADER)的长度(E0)
原理(创造空间,插入代码)
UPack将其改为148(E0->148), 这样做可以向文件头插入解码代码
经过这样的改动 , (IMAGE_OPTIONAL_HEADER)和(IMAGE_SECTION_HEADER)之间就添加了一段额外的空间
原因
1.PE规定 IMAGE_OPTIONAL_HEADER的大小(sizeof…) 是要另外输入的
(为了可以插入不同形态的IMAGE_OPTIONAL_HEADER结构体,而不同形态的他们之间大小也不同)
2.IMAGE_SECTION_HEADER 并不是紧跟在IMAGE_OPTIONAL_HEADER 结构体后面的,而应该 在IMAGE_OPTIONAL_HEADER加上SizeOfOptionalHeader的地址后的位置
3.根据2便可以知道,将E0修改为148(>E0)会在 IMAGE_OPTIONAL_HEADER 和 IMAGE_SECTION_HEADER之间多出来一大块额外空间。
查看插入的代码
先看 IMAGE_OPTIONAL_HEADER 的结束位置
在D7附近
在stud_PE查看D7~170(节区起始位置)
再放入od中看一下这段地址的代码
之所以pe查看程序会出错,是因为将上面的解码代码错误的识别为PE文件头信息。
修改可选头中的NumberOfRvaAndSize
NumberOfRvaAndSize
是用来指出后面的IMAGE_DATA_DERICTOR结构体的元素数量
具体修改
NumberOfRvaAndSize 的改变也是为了在文件头中插入自身代码
原本的值是10
修改后为A
所以它的后6个元素就可以自由使用,添加代码了
88~ D7是data directory数组,剩下的蓝色部分是自由添加的代码(D8~107
在od中同样可以看到解码代码
IMAGE_SECTION_HEADER的空间利用
节区中有很多不会影响程序正常运行的区域
上图为IMAGE_SECTION_HEADER,方框内的区域便不会影响正常运行
重叠节区
看一下节区头,发现 第一节区和第三节区的大小和文件偏移地址是一样的 ,内存的起始RVA和内存大小是不一样的
正常情况下,PE装载器会把文件分别映射到3个不同的内存位置(文件头、第一节区、第三节区)。就是说用相同的文件可以分别创建出处于不同位置的、大小不同的内存映像。
因此,可以理解为,在文件中,第二个节区很大,文件就压缩存储在这里,在程序运行的时候,PE装载器会对文件进行解压缩并且进行内存的映射,将文件还原到第一个节区。(原来的文件有三个节区,都被解压到第一个节区)。
所以说,压缩的notepad在内存的第二节区,解压缩时被记录到第一节区。
并且原文件的 内存映像 会被整体解压,所以程序能正常运行。
RVA to RAW的特征
UPack的 FileAlignment 的值是200,所以PointerOfRawData 会被转换为200的整数倍,不足200的为0。
此文件的EP值是1018
根据rva to raw的转换
计算出压缩后的EP为:28
由于 PointerOfRawData 会被转换为200的整数倍 ,所以上面的计算是错误的,PointerOfRawData 的值应该是0
所以EP正确的Raw值是18.
在od中查看
IMAGE_IMPORT_DESCRIPTOR array(导入表)的特征
导入表是 由 一系列 IMAGE_IMPORT_DESCRIPTOR 结构体组成的数组
而且该数组(导入表)的 结尾必须是一个NULL结构体
原理
利用文件内容映射到内存时, 只映射文件结束地址前的内容 ,所以映射到内存中的节区结尾部分(如下图内存27200后的节区)永远被NULL填充,符合
结尾必须是一个NULL结构体
的要求,所以程序可以正常运行。
IAT(导入地址表,从dll额外导入了哪些API?)
导入表(经RVA to RAW转换后得到的地址1EE):
通过上面两图进行对应的映射后,得到结构体重要成员的信息:
因为header区域中RVA 和 RAW 值相等
所以在hxd看
它占用了原本不使用的DOS头区域(好节省)
所以知道了dll的名称,看看从中导入了哪些API函数
将IAT的RVA(11E8,一节区) 转化成RAW: 1E8 (一节区的RawOffset被强制换成0)
IAT(文件偏移):
其中记录着28 和 BE 两个地址值:
由于header区域rva和raw相同,所以看一下28 和 BE
可以看到导入的两个API:
LoadLibraryA
GetProcAddress