加壳的DLL处理重定位表有n中方法,常见的有下面4种情况:
1、完整的保留了原重定位表,RVA也没有变化(即在加壳的程序中
后看到的重定位表就原来真正的重定位表,我原来发给您的我
写的加壳例子就是这样);
2、原重定位表的RVA进行了加密,但重定位数据没有加密(即将原
重定位数据做了搬移);
3、对原重定位表的RVA和重定位数据都进行了加密处理;
4、对原重定位表的RVA和重定位数据、以及原程序中被重定位项所
指向的数据同时进行了加密。
以上几种情况中,都有可能在原重定位表中增加了外壳的重定位数据,所以脱壳后还要将外壳的重定位项去掉。当然,如果不是真正脱掉外壳(保留脱壳后的外壳尸体)去不去掉也无所谓,若真正脱了壳,一定要去掉,否则PE装载时可能会报告:Windows错误,xxxxxxxx的地址不能为Write。
另外,DLL加载时候,基地址一般跟编译器生成的基地址是不同的,所以脱壳后的程序中被原重定位项所指向的地方是已经重定位了的数据。所以,还要将这些地方还原为编译器生成的数据。方法可以写一个程序,扫描获得的“真正的原重定位表”取得这些地方数据并减去脱壳时候的基地址,再加上编译器生成时候的基地址(重定位项的属性一共有7种情况,但在PE中只能看到0和3这两种情况,0---没有什么意义;3---对32位都要修正,即PE文件在重定位表中每项所指向的地方肯定是个32位的地址)。
第一种情况,是最简单的,因为完全保留了原来的重定位表,所以重定位的过程让PE装载器给完成了。脱壳后只要将获得得原来的重定位数据复制到脱壳后的程序的重定位表中,再按照上面的方法修正重定位项所指的地方的数据就可以了。
第二种情况,跟第一种情况不同之处是:对原程序重定位项所指向的地方,由外壳程序完成重定位。那么关键的就是找到真正的原来的重定位表。可以通过追踪外壳程序,找到外壳解密后的重定位表的地址,然后将这些数据复制下来放入脱壳后的重定位表中,再按照上面的方法修正重定位项所指的地方的数据就可以了。对于这种情况,也可以通过经验直接查看加壳后的程序的16进制数据,直接找到重定位表(这个好像要靠运气)。
第三种情况,跟第二种区别不大,也可以通过追踪外壳得到解密后的重定位数据。再按照上面的方法修正重定位项所指的地方的数据,再将我们获得的真的重定位表数据放入脱壳后的程序的重定位表中就可以了。
第四种情况稍微复杂些,也是通过追踪外壳得到解密后的重定位数据。然后还要看看外壳怎样将重定位项所指向的数据还原的,并将这个还原方法同上面的“修正重定位项所指的地方的数据”结合起来修复这些数据。再将我们获得的真的重定位表数据放入脱壳后的程序的重定位表中。
错误疏漏指出,恳请高手们指正!
附上我原来自己分析得重定位表的说明:
;- ------------------------------------------------------------ 以下部分是由 Relocation表分析得出的结果:(以前没有找到资料啊,只有自己瞎琢磨。。,现在看了看罗云彬大侠的书,总算分析得差不多,结构名字我就不改了,可能关键字跟专业文档不太一致,各位见笑了。。)
-- 重定位表格式:
重定位表以1000h大小为分隔段,因为ItemOffset最长为12位,即刚好为1000h。
IMAGE_RELOC STRUCT
RVirtualAddress dd 0
SizeOfBlock dd 0
Type1 dw 0
;其中:Bit15-Bit12 为类型type
;Bit11--Bit0 为ItemOffset
IMAGE_RELOC ENDS
-- 举例:
-- 如果某文件重定位表如下:
00 10 00 00
0E 00 00 00
01 30 08 30
00 00
以上说明:00001000h为本段RVirtualAddress;0000000Eh为本段重定位表的字节长度。
3001h为第一个重定位项,类型是3;
3008h为第二个重定位项,类型是3;
0000h为第三个重定位项,类型是0,对于这种全0的项,很多PE中都有,好像没用。???
如果还有更多索引,将重复上面数据结构,直到RVirtualAddress为NULL。
RVA的计算:
RVA = RVirtualAddress + ItemOffset = RVirtualAddress + (Type1 & 0FFFh)
对于第一项:RVA = 00001000h + (3001h & 0FFFh) = 00001001h,即要对(ImageBase+1001)的4字节(一个32位的地址)进行重定位。
0
顶一下0
埋一下引用地址:



