前言
对于脱DLL文件的壳时需要注意对重定位表的操作,在重建重定位表的时候需要注意壳代码是否对原程序中需要重定位的数据进行了加密。也就是在dump文件时不能单纯的nop过壳的重定位代码,因为有可能重定位数据被加密了。如果直接nop过此壳的重定位处理代码,那么dump的文件中的需要重定位的数据是错误的。
忽略壳对原程序的重定位数据加密
按照正常的思路在获取OEP后,我们需要找到壳的重定位代码处。
直接NOP过壳的重定位代码
到达壳的重定位代码处,将修正重定位数据的指令直接nop去。
然后我们运行程序来到OEP跳转处
这是我们查看对应函数真正入口处的代码,发现需要重定位的数据并没有被重定位。
但是我们发现其重定位数据的地址有点怪。因为程序默认的加载基地址为0x400000,正常的话如果没有重定位其需要重定位的数据的地址应该为0x400000+,而这里我们发现其地址并不是这样的(实际是被壳加密过的)。
接着重建输入表,重定位表。
做完这些之后我们获得了最终的DLL,用OD加载后我们来到OEP处,然而我们发现其重定位的地址并不是 “基地址+” 的形式。
是不是重定位表没用被windows加载器使用呢,我们计算一下。根据重定位数据的原理,在没有重定位的时候(也就是我们nop去壳的重定位代码)获得的oep处第一个需要重定位数据的地址为0x689D0000,而我们在重建了重定位表后OEP第一个需要重定位数据的地址为0x687F0000,而此时程序加载基地址为0x220000。 0x689D0000 - 0x400000 + 0x220000 正好等于 0x687f0000。说明重定位表发挥作用了,如果我们直接运行程序将出错因为重定位数据地址不正确会访问到无效的地址。
错误原因
这是因为我们忽略了壳代码会对重定位数据地址进行加密,直接nop去了修正重定位数据地址的代码导致的。
正确做法
找到OEP后,接着找到壳重定位代码处。
经过分析其在修正重定位地址时会把(实际的加载基地址 + 代码段RVA)通过esi给eax,我们为了恢复被加密的重定位数据地址只需将esi改为(默认的基地址0x400000 + 代码段RVA)即可。
接着运行程序到OEP处,发现此时需要重定位数据的形式变为 “0x400000+”的形式,解密成功。
接着dump程序,重建输入表和重定位表。
搞完这些之后我们重新加载dll,发现oep处需要重定位的数据的地址已经修正了。
总结
在进行dll文件脱壳时,dump程序的时候不能一味的直接跳过壳的重定位代码,需要考虑原程序的重定位数据地址是否被壳加密。