手动添加TLS回调函数
设计规划
首先要确定IMAGE_TLS_DIRECTORY
结构体与TLS回调函数放到文件的哪个位置。向某个PE文件添加代码或数据时,有如下3种方法查找合适位置:
- 添加到节区末尾的空白区域
- 添加到最后一个节区的大小
- 在最后添加新节区
这里呢,我们采用第二种方法,即增加最后一个节区(.rsrc)的节区头。
可以看到,最后一个节区(.rsrc)的Pointer to Raw Data=9200,Size of Raw Data=600。所以PE头中定义的文件整体大小为9800。考虑到要添加的代码与数据的大小,我们将最后一个节区的大小增加200(文件的大小增加到9A00)。使用HxD工具打开需要操作的程序,移动光标至最后位置,在菜单栏中选择Edit-Insert bytes 菜单,打开插入字节对话框,然后向Bytecount中输入200,单击OK按钮后,即从光标当前位置添加了200个字节(即512个字节)
另一种方法,直接复制最后很多的零字节内存单元格,然后从文件尾部直接粘贴就行,多粘贴几次,512字节就出来了
注意:
图中virtual size为43C,PE装载器会按照Section Alignment值对齐该值,即加载到内存中的大小为1000(一定要理解好这个关系)。所以将节区的文件大小增加200后,实际virtual size 变为63C,它比加载到内存中尺寸1000要小,所以不需要再单独增大virtual size 的值
这里加的时候,如果改了之后没法保存的话,记得用 管理员权限来打开编译exe的程序(即打开visual stido),我就是这种情况。。。
编辑PE文件头
.rsrc节区头
分别修改.rsrc节区头中的Size of raw data与Characteristics的值,即size of Raw data =800,characteristics=E0000060,如下所示
修改后:
Characteristics=E0000060的含义如下所示:
Characteristics | 属性 |
---|---|
00000020 | IMAGE_SCN_CNT_DODE |
00000040 | IMAGE_SCN_CNT_INITIALIZED_DATA |
20000020 | IMAGE_SCN_MEM_EXECUTE |
40000020 | IMAGE_SCN_CNT_READ |
80000020 | IMAGE_SCN_CNT_WRITE |
即在原有属性的基础上增加了IMAGE_SCN_CNT_DODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_CNT_WRITE
属性
注意:
由于要在扩展区域内创建IMAGE_TLS_DIRECTORY
结构体与TLS
回调函数,所以需要向节区添加IMAGE_SCN_CNT_DODE
| IMAGE_SCN_MEM_EXECUTE
属性,此外,还必须包括IMAGE_TLS_DIRECTORY
结构体的节区添加 IMAGE_SCN_CNT_WRITE
属性,才能保证正常运行
IMAGE_DATA_DIRECTORY[9]
接下来要设置TLS
表(IMAGE_NT_HEADERS-IMAGE_OPTIONAL_HEADER-IMAGE_DATA_DIRECTORY[9]
)。在PRVIEW中查看该地址为9800(RVA地址),我们将从改地址创建IMAGE_TLS_DIRECTORY结构体。因此要修改PE文件投中的IMAGE_DATA_DIRECTORY[9],即(RVA=9800,Size=18)
改完之后用PEview查看一下是否改好即可。
设置IMAGE_TLS_DIRECTORY结构体
接下来设置 IMAGE_TLS_DIRECTORY 结构体,只要把TLS回调函数注册到其中即可,编辑设置IMAGE_TLS_DIRECTORY结构体
我们在文件偏移9800地址处创建了IMAGE_TLS_DIRECTORY结构体。AddressOfCallbacks成员的值为 假设为0x40C224 ,它是array of TLS CallBack Function (TLS回调函数数组)的起始地址。只要把TLS回调函数的地址(40C230)放入该数组,即可成功注册TLS回调函数