从SRDI原理剖析再到PE2Shellcode的实现
字数 1963 2025-08-30 06:50:11
SRDI原理剖析与PE2Shellcode实现技术详解
一、RDI与SRDI技术概述
1.1 RDI(反射式DLL注入)技术
RDI(Reflective DLL Injection)是一种无文件落地的高级内存注入技术,其核心流程包括:
- 动态获取基址:通过回溯机制或当前位置+偏移计算基址
- 加载PE文件到内存:
- 申请RWX权限内存
- 复制PE头到新内存
- 按VirtualAddress字段展开各节到内存
- 修复导入表:遍历导入表,获取函数地址填入IAT
- 修复重定位表:修正硬编码的绝对地址
- 调整内存保护属性:根据节属性设置相应权限
- 执行TLS回调:处理DLL_PROCESS_ATTACH回调
- 执行入口点:调用DllMain或main函数
1.2 SRDI(Shellcode反射式DLL注入)技术
SRDI是RDI的进化形式,将ReflectLoader转换为位置无关的shellcode,使其能在内存直接执行。关键特性:
- 将RDI置于PE文件头部或尾部形成整体
- PE文件自带加载器,实现PE2Shellcode功能
- 相比传统RDI具有更高的灵活性和隐蔽性
二、SRDI实现原理详解
2.1 加载PE文件到内存(LoadPEIntoMemory64)
; 约定:
; [rbp+8] = 旧DOS头地址(基址)
; [rbp+16] = 新DOS头地址(基址)
; [rbp+24] = 新NT头地址
; 关键偏移量:
; SizeOfImage: NT头偏移50h
; SizeOfHeaders: NT头偏移54h
; NumberOfSections: NT头偏移6
; SectionHeader.VirtualAddress: 节头偏移0Ch
; SectionHeader.PointerToRawData: 节头偏移14h
; SectionHeader.SizeOfRawData: 节头偏移10h
2.2 修复重定位表(FixRelocations)
; 关键数据结构:
; IMAGE_DATA_DIRECTORY (重定位目录)
; IMAGE_BASE_RELOCATION (重定位块)
; 重定位项(16位,高4位类型,低12位偏移)
; 处理流程:
1. 计算基址偏移量:Delta = NewBase - ImageBase
2. 定位重定位目录:NT头偏移0B0h
3. 遍历重定位块:
- VirtualAddress=0时终止
4. 处理重定位项:
- 类型为IMAGE_REL_BASED_DIR64(10)才处理
- 偏移 = 项值 & 0FFFh
- 修正地址 = 基址 + VirtualAddress + 偏移
2.3 解析导入表(ParseImportTable)
; 关键偏移量:
; 导入目录: NT头偏移90h
; IMAGE_IMPORT_DESCRIPTOR.Name: 导入描述符偏移0Ch
; OriginalFirstThunk(INT): 导入描述符偏移0
; FirstThunk(IAT): 导入描述符偏移10h
; 处理流程:
1. 遍历导入描述符数组(全零结构终止)
2. 加载DLL(通过Name字段)
3. 遍历导入函数:
- 按序号导入(高位=1): 使用低16位序号
- 按名称导入(高位=0): 使用IMAGE_IMPORT_BY_NAME
4. 将函数地址填入IAT
2.4 调整内存保护属性(AdjustMemProtect)
; 创新性权限映射方案:
1. 获取节属性Characteristics(节头偏移24h)
2. 保留第30-32位(执行/读/写标志)
3. 右移29位得到3位标志组合
4. 通过预定义的ProtectionTable映射到PAGE_*常量
; ProtectionTable定义:
db 00h, 01h, 02h, 03h, 04h, 05h, 06h, 07h
; 对应权限:
; 000b=0 PAGE_NOACCESS
; 001b=1 PAGE_EXECUTE
; 010b=2 PAGE_READONLY
; 011b=3 PAGE_EXECUTE_READ
; 100b=4 PAGE_WRITECOPY
; 101b=5 PAGE_EXECUTE_WRITECOPY
; 110b=6 PAGE_READWRITE
; 111b=7 PAGE_EXECUTE_READWRITE
2.5 执行TLS回调(ExecuteTLSCallbacks)
; 关键偏移量:
; TLS数据目录: NT头偏移0D0h
; AddressOfCallBacks: TLS目录偏移18h
; 处理流程:
1. 定位TLS数据目录
2. 获取回调函数数组地址
3. 遍历数组执行DLL_PROCESS_ATTACH回调
2.6 执行入口点(GoToEntry)
; 关键偏移量:
; Characteristics(文件类型): NT头偏移16h
; AddressOfEntryPoint: NT头偏移28h
; 处理逻辑:
1. 检查文件类型(EXE:010F, DLL:210E)
2. 为DLL入口预留32字节栈空间
3. 调用入口点函数
三、SRDI实现方案
3.1 前置式RDI(Front-Style)
特点:
- RDI位于PE文件之前
- 需要引导程序(Bootstrap)
- 支持EXE/DLL
引导程序关键逻辑:
- 保存非易失性寄存器
- 计算DLL位置:当前IP + 固定偏移
- 切换堆栈并预留空间
- 调用ReflectiveLoader
- 恢复寄存器状态
注意事项:
- RSP对齐问题(需保持16字节对齐)
- DLL入口需要预留32字节栈空间
- 需正确处理返回地址
3.2 后置式RDI(Post-Style)
特点:
- RDI位于PE文件末尾
- 修改DOS头作为stub
- 支持EXE/DLL
stub关键逻辑:
- 计算RDI位置(PE文件大小 + 固定偏移)
- 跳转到RDI执行
- 寄存器保护和恢复移到RDI内部
优势:
- 可消除部分PE特征
- 不需要单独的引导程序
3.3 内嵌式RDI(Embed-Style)
特点:
- RDI作为DLL导出函数
- 必须保留"MZ"签名
- 仅支持DLL
关键技术:
- 将"MZ"(4D5A)作为指令(pop r10)
- 导出函数ReflectiveLoader
- RVA到文件偏移转换公式:
文件偏移 = PointerToRawData + (RVA - VirtualAddress)
四、关键技术要点总结
- PE结构掌握:深入理解PE文件各字段偏移量是关键基础
- 内存权限控制:创新的权限位映射方案大幅简化代码
- 位置无关代码:所有地址引用必须相对偏移,不能有绝对地址
- 调用约定遵守:x64调用约定和栈对齐要求必须严格遵守
- 动态API解析:通过hash算法动态获取API地址
- 调试技巧:Windbg动态调试是验证shellcode的关键手段
五、附录:关键PE结构偏移表
| 结构字段 | 偏移量 |
|---|---|
| IMAGE_DOS_HEADER.e_lfanew | 3Ch |
| IMAGE_OPTIONAL_HEADER64.SizeOfImage | 50h |
| IMAGE_OPTIONAL_HEADER64.SizeOfHeaders | 54h |
| IMAGE_FILE_HEADER.NumberOfSections | 6 |
| IMAGE_SECTION_HEADER.VirtualAddress | 0Ch |
| IMAGE_SECTION_HEADER.PointerToRawData | 14h |
| IMAGE_SECTION_HEADER.SizeOfRawData | 10h |
| IMAGE_SECTION_HEADER.Characteristics | 24h |
| 重定位数据目录 | 0B0h |
| 导入数据目录 | 90h |
| TLS数据目录 | 0D0h |
| IMAGE_FILE_HEADER.Characteristics | 16h |
| OptionalHeader.AddressOfEntryPoint | 28h |