《逆核》05-Upack和PE结构
upack是一个压缩器,用于压缩PE文件,跟随逆核一起深入学习PE文件结构
特征
PE文件经过upack之后有以下特点:
重叠文件头
把MZ文件头(dos头)和PE头重合在一起
原理是dos头中的e_lfanew指向NT头但是并没有说NT头不能和DOS头重合,一般情况下:
e_fanew = MZ文件大小(40h)+DOS存根=E0
1
2
3
4
5
6
7
8
9
10
- 但是Upack后e_fanew值是10h,所以hex方式打开后,第一排是4D5A下一排就是5045
## 在可选头中插入解码代码
- 修改SizeOfOpionalHeader的值增加至148h,这样在节区头和可选头中间就可以插入解码代码,此时节区头的起始偏移是
- ```
170h=28h(可选头起始偏移)+148h(SizeOfOpionalHeader的作用是想要根据PE文件形态更换和插入其它可选头形态的结构体)
在文件头插入解码代码
- 可选头中的NumberOfRvaAndSizes由10h变为Ah,使得DataDirectory只有前10个元素,,并把后面6个元素的位置改为自己的解码代码
在节区头中记录自身数据和重叠节区
- 节区头中类似重定位节区是不需要的,所以这种节区可以用于记录自身数据
- 整个PE文件分为4个部分:PE头,第一节区,第二节区,第三节区.有以下几个特性:
- 内存中,PE头,第一节区,第三节区均由同一区域映射而来,即SizeOfRawData和RawOffset相同,但是VirtulSize不同
- 源文件压缩于第二节区
- 第一节区的SizeOfImage与原PE文件相同,即原PE文件会解压到第一节区
RVA to RAW
标准操作是:
RAW=RVA-VA+PointerToRawData
但是经过upack后,第一节区的PointerToRawData值为10,然而不为FileAlignment(200h)的倍数,因此PE装载器强制识别为其整倍数(确保指向一页),令其等于0
所以正确值是:
RAW=RVA-VA
导入表
- 通过存在在节区的末尾,省略最后的null结构体,映射到内存时,后面自然有null填充,这样可以节约空间
导入地址表
- 在DOS存根中存放导入DLL的名称,查看FirstThunk可以找到对应加载的函数.
调试过程
- 先是解码循环,再是设置IAT(和UPX差不多?),但是设置IAT的方法是用导入的函数LoadLibraryA和GetProcAddress一边循环一遍构建(先获取导入函数实际地址,再写入原函数)IAT
评论