移动表的原因
一个PE文件中有很多节,每个节都存储不同的数据。而PE文件中的各种表也都分散存储在这些节当中。此时各种表的信息与程序的代码和数据相互混合在一起,如果我们直接对整个程序进行加密,那系统在初始化程序时就会出问题。比如:这些表的数据被加密时,系统就无法根据这些表将用到的.DLL中的函数地址存储到IAT表中,这时候程序就无法正常启动
所以对程序加密或破解之前,需要移动各种表到程序新增的节当中,再对剩下的数据进行加密
注意:DOS头、NT头等所有头和节表是操作系统判断该文件是否为Windows可执行程序的依据,因此这些数据不可以加密。
学会移动各种表,是对程序加密/破解的基础
移动导出表
步骤说明:
在FileBuffer中进行操作,现结合图示来理解移动的步骤
在PE文件FileBuffer中新增一个节,并获取该节的FOA。该表用来存储导出表,节大小按照表的的大小对齐以后计算,粗略估计0x1000字节大小,
新增节时需要修改的数据:
1.修改PE头中的字段:NumberOfSections、SizeOfImage
2.重新开辟一个FileBuffer,并新增节表
3.修改节表中的字段:Name、Misc.VirtualSize、VirtualAddress、SizeOfRawData、PointerToRawData、Characteristics。
新增节进行填充的数据:
1.复制导出表IMAGE_EXPORT_DIRECTORY到新节中,大小固定40字节
2.复制AddressOfFunctions指向的函数地址表到新节中(注意RVA转FOA),数据大小为4 * NumberOfFunctions字节
3.复制AddressOfNameOrdinals指向的函数序号表到新节中,数据大小为2 * NumberOfNames字节
4.复制AddressOfNames指向的函数名称表到新节中,数据大小为4 * NumberOfNames字节
5.依次复制函数名称表中元素所指向的函数名称字符串到新节中,注意以00结尾。遍历函数名称表,用strlen()函数依次求出每个字符串长度,再求和。每复制一个字符串到新节中,就修改对应的函数名称表中的地址值
注意:函数名称表中存的是RVA,所以把字符串复制到新节后还需要把FOA转成RVA,再存入
如果只移动函数名称表的话,对剩下的数据加密后,当需要根据函数名去调用导出函数时,由于字符串被加密,只能根据函数名称表查到名称字符串所在地址,但是无法匹配字符串。
6.修改导出表中的成员值,指向三个子表在新节中的位置,由于各个子表在导出表的地址数据是RVA,因此需要将FOA转成RVA
7.最后修复导出表数据目录中的VirtualAddress,指向导出表IMAGE_EXPORT_DIRECTORY在新节中的位置,该地址也要FOA转RVA
移动重定位表
步骤说明
结合图示来理解移动重定位表过程:
1.新增节,大小能够循环遍历重定位表的每个块,即把所有块的SizeOfBlock求和 + 结束标记8字节最后再对齐,粗略估算0x1000就满足大部分情况了
2.复制重定位表到新节中,大小为所有块的SizeOfBlock求和 + 结束标记8字节
3.修改重定位表数据目录中的VirtualAddress,指向重定位表在新节中的位置即可(FOA转RVA)
4.修复重定位表:根据重定位表中的各个具体项,去修改具体项指向的地方的值。这个值可能是DLL中全局变量的绝对地址,或者是DLL中函数的绝对地址等
一般情况下一个PE文件自身的.exe的ImageBase很少会和其子PE文件ImageBase发生冲突,但是.dll文件容易发生冲突。默认情况下.DLL的ImageBase为0x10000000,所以如果一个程序要用的DLL没有合理的修改分配装载起始地址,就可能出现多个DLL的ImageBase都是同一个地址,造成装载冲突
现在我们自己故意修改一个DLL文件的ImageBase,再根据其重定位表去修正,最后存盘,看此DLL文件是否可以正常使用,即手动模拟操作系统修复重定位表的过程
修正过程:比如DLL的ImageBase原来为0x400000,现在修改为0x500000;接着找到重定位表,遍历每个块中的具体项,根据具体项去找哪里的地址值需要修改重定位;找到后,将原来的地址值 + (0x500000 - 0x400000)即可
作业
1.在DLL新增一个节,并将导出表信息移动到这个新的节中,
2.使用工具打开修改后的DLL看能否正常解析.
3.在DLL中新增一个节,并将重定位表移动到这个新的节中,
4.修改DLL的ImageBase,根据重定位表修正,然后存盘.看叫号否可以使用.