2. PE结构2
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //说明性
union {
DWORD PhysicalAddress;
DWORD VirtualSize; //内存中节的大小,但不一定准
} Misc;
DWORD VirtualAddress; //节的RVA
DWORD SizeOfRawData; //文件中数据对齐后的大小,必须是FileAlignment的整数倍
DWORD PointerToRawData; //文件地址
DWORD PointerToRelocations; //说明性
DWORD PointerToLinenumbers; //说明性
WORD NumberOfRelocations; //说明性
WORD NumberOfLinenumbers; //说明性
DWORD Characteristics; //wres等信息
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
SizeOfRawData不为0时,把PointerToRawData开始的SizeOfRawData个字节,映射到RVA为VirtualAddress的地方(若Misc.VirtualSize大于SizeOfRawData,用0填充大于的部分,若Misc.VirtualSize小于SizeOfRawData,则不考虑Misc.VirtualSize)。
SizeOfRawData为0时,从RVA为VirtualAddress的地方开始,Misc.VirtualSize个字节都设为0。
数据或代码从PE文件加载到内存时,由于文件对齐值和节对齐值未必相等,所以文件偏移和内存偏移也未必相等。如果文件对齐值和节对齐值一致,则变量在文件和内存中的偏移一般相等,但也有例外,例如文件中节大小是1000h,但是加载到内存中节大小是2000h,前1000h和文件中一致,后1000h未初始化,相当于汇编中的.data?段。
增加一个节:
- 文件最后插入需要的数据
- 新增节,配好数据
- 修改IMAGE_OPTIONAL_HEADER中的SizeOfImage
- 修改IMAGE_FILE_HEADER中的NumberOfSections
- 检查SizeOfHeaders是否需要改,一般修改量少,不会越界,不用修改
在上例的基础上,将AddressOfEntryPoint改为自己添加节的RVA,执行完需要的功能后跳回原入口,可实现注入。如果把SizeOfRawData改为0,插入到文件中的字节不会映射到内存,节大小依然有效。
未初始化节可以用这种思路设计,并把最后插入的数据删除,这样未初始化数据就不占磁盘空间,模拟了汇编的.data?段。
也有的情况是文件中数据较小,例如只有200h,但Misc.VirtualSize较大,例如有8000h,多出来的部分模拟了.data?段。

另一种注入思路是不增加新节,只在末尾插入数据,并更最后一个节的大小,再按需调整IMAGE_OPTIONAL_HEADER中的SizeOfImage。
VA和FA的转换:
假设hInstance = 00400000,已知VA为0040312C,求FA。
RVA = 0040312C - 00400000
= 312C
接着查询312C是文件中哪个节映射而来,假设文件中800h开始的200h字节映射到RVA是3000h的位置,则FA = 12C,12C小于映射的200h字节,计算有效,故FA = 12C。
若只映射了100h字节,且没有其他映射,12C大于100,计算无效,此VA不存在对应的有效FA。如果在此VA处打补丁,由于无法对应到文件位置,结果是无法保存。

浙公网安备 33010602011771号