解决什么问题:
解决功能性shellcode开发中的某些限制:不能使用静态变量,不能使用全局变量,不能使用字符串,不能使用虚类。
PE2Shellcode解决方案可以缓解shellcode开发中的这些限制,让shellcode开发能够更为快速方便。
不能解决什么问题:
PE文件中导入表未被处理,使用者要么进行二次开发,在shellcode前处理导入函数,要么在开发前消除PE文件的导入表。
CRT(C runtime)函数系列.大量的C语言标准库函数都会在其内部分配和释放内存,这会破坏shellcode的内存环境,所有的CRT函数要么自行重写,要么不再使用。
原理:
shellcode开发中不能使用静态变量,全局变量和字符串等等限制的原因,是这些代码在生成机器码的过程中,没有值写入,只有地址写入。在PE文件加载的时候,Windows的PE加载器再重新对这些数据地址进行重写。
这个小工具的原理就是在提取PE的shellcode基础上,再对shellcode进行重定位处理。
说明:
仅适用于32位程序。
没有测试过图像界面,不确定资源段内容是否能够被释放。
代码中的静态变量、全局变量、字符串地址在下面的文档中都被称为全局变量——从shellcode的视角来看,他们都是同一类代码。
基础:
PE文件结构。
《加密解密》
http://drops.wooyun.org/tips/8361
python基础
pefile库
第0步:PE文件的要求
第一步:处理PE段(SECTION)表(sections_list函数)
PE重定位表指向的数据可能在PE的任何一个段上,因此第一步就是要处理段表。
将所有的段表放入all_sections中,保存了段表的以下信息:数据,磁盘文件长度,内存长度。
PE段表信息中的内存长度比较特殊,它是一个被我们计算出来的值。指该段在Shellcode内存中的长度。
段表长度会和未初始化的全局变量和静态变量相关,因此需要手动确认长度。
段表的section.SizeOfRawData指明了磁盘文件长度对齐内存后的长度。section.VirtualAddress则指明了该段未对齐内存时的长度。我们取两者较大的值作为该段在Shellcode的长度。
第二步:将段表合成一个段数列(sections_list),并记录其在段数列的偏移(sections_list函数)
将.text段放在最前面,保证shellcode在运行是能够运行到我们的目标代码,然后依次将其他段放在后面。
每个段在sections_list的长度是按照其['mem_size']来确定的。对于长度不够的情况,在后面添加\x00.如前所述,这是为了保证未初始化的全局变量也在内存中有一席之地。
第三步:重写将PE的导入函数地址
在实际的应用中,建议在生成PE文件前,在代码中消除导入表。使用汇编动态加载导入表比较困难。
第四步:获得重定位表信息(reloc_process函数)
这是整个工具核心的一部。首先看看PE的重定位信息是如何工作的:
图中.RELOC段有两个项目,第一个项目062h表示重定位项目在文件偏移。它指向的位置是一个4字节的地址,
0x402002。这个地址表示PE在使用基地址加载的情况下,需要重定位数据的内存地址。所有的重定位信息都只有地址没有长度,重定位的长度都是8字节(DWORD)。
如果PE没有在基地址加载,这个地址就要减去基地址得到rva,然后加上目前的基地址,获得运行时的新地址。
pefile库已经帮我们把.RELOC的项目地址转为了rva地址,可以直接读取而不需要额外的转换。
我们的目标是将reloc信息转为下面类似的形式:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)