pe_to_shellcode源码分析

1.编译

1
2
3
4
5
// 递归clone
git clone --recursive https://github.com/hasherezade/pe_to_shellcode.git
cd pe_to_shellcode
cmake .
// VisualStudio打开sln编译即可

如下图所示:

编译示意图

2.分析

  • dos->e_lfanew 长度不能大于1024
  • Optional->Magic 可以判断32位数
  • Optional->Subsystem 可以判断窗口或控制台
  • 必须要有重定位表、不支持.NET程序
  • 加载资源:64位的资源id为102,32位的资源id为101

2.1 Packer

2.1.1 映射PE

将PE文件从文件状态转换到内存状态,关键代码如下:
PE映射

2.1.2 拼接Loader

从资源节中读取Loader数据(32位id为101、64位id为102),将Loader拼接到PE文件的末尾,关键代码如下:

PE末尾拼接Loader

将启动Loder的ShellCode填入DOS垃圾区域,关键代码如下:

填入DOS垃圾区域

2.1.3 修复节表

为了避免作为ShellCode执行时需要拉伸PE,直接将节表的文件偏移及大小修复为内存偏移及大小,关键代码如下:

修复节表

如果是64位.NET程序,需要将OEP修改为0,代码如下:

64位.NET修复OEP

如果是32位.NET程序,需要找到_CorExeMain函数,并寻找间接跳转指令,将OEP修改为间接跳转指令位置,代码如下:

32位.NET修复OEP

2.2 RunShellCode

2.2.1 Loader启动

很巧妙,充分利用PE头部,将4D5A用作指令,并将垃圾区域作为Loader启动器,代码如下:

Loader启动器

上述代码解释:

  • 使用call pop获取当前指令地址,减去固定偏移即可得到ImageBase

  • 根据Packer填入的原始SizeOfImage加上ImageBase得到Packer地址

  • call Loader代码,ImageBase作为参数

2.2.2 Loader

Loader原理为常规的PE Loader,主要包括修复重定位表、动态解析API修复IAT表、执行TLS回调,执行入口点。

2.2.2.1 获取必要API

获取必要API

ShellCode基本手段,解析PEB->Ldr,从模块链表中获取模块基址,再比对hash,解析导出表,获取函数地址,代码如下:

解析模块链表

2.2.2.2 修复重定位表

修复重定位表

解析PE,完成固定地址的重定位,代码如下:

修复重定位

2.2.2.3 修复IAT表

修复IAT表

常规套路,根据INT表去获取导入函数地址来填充IAT表,代码如下:

填充IAT表

2.2.2.4 执行TLS回调

执行TLS回调

如果存在TLS回调函数,全部执行,代码如下:

执行TLS回调

2.2.2.5 执行入口点

如果是DLL,需要给定参数再去执行入口点,exe则直接执行,代码如下:

执行入口点

至此,程序控制权交给原程序,完成ShellCode加载。


pe_to_shellcode源码分析
http://helloymf.github.io/2022/10/21/pe-to-shellcode-yuan-ma-fen-xi/
作者
JNZ
许可协议