Windows Shellcode开发
字数 2062 2025-08-30 06:50:35

Windows Shellcode开发完全指南

一、Shellcode基础概念

1.1 什么是Shellcode

  • 一段精心编写的机器代码,具有位置无关、紧凑高效、直接在CPU上执行等特性
  • 无需编译即可运行
  • 在攻防对抗中常用于网络操作、权限提升、文件操作等

1.2 开发Shellcode的必要性

  1. 避免使用公开工具生成的固定特征Shellcode
  2. 扩展自定义功能
  3. 规避AV/EDR查杀
  4. 安全开发人员必备技能

二、汇编基础

2.1 寄存器

x86架构

寄存器 名称 用途
EAX 累加器 算术运算和函数返回值
EBX 基址寄存器 内存寻址
ECX 计数器 循环计数
EDX 数据寄存器 I/O操作
ESI 源索引 字符串/数组操作源指针
EDI 目的索引 字符串/数组操作目的指针
EBP 基址指针 栈帧指针
ESP 栈指针 栈顶指针

x64架构

  • 扩展了x86的8个通用寄存器(R开头的寄存器)
  • 新增r8-r15寄存器

2.2 常用指令

指令 功能
mov 数据传输
xor 寄存器清零或数据解密
push/pop 栈操作
jmp 无条件跳转
call 函数调用
lea 计算内存地址
cmp 比较指令

2.3 调用约定

__stdcall (WINAPI)

  • 参数顺序: 右→左
  • 堆栈清理: 被调用者
  • 典型应用: Windows API

__cdecl

  • 参数顺序: 右→左
  • 堆栈清理: 调用者
  • 支持变参

__fastcall

  • 部分参数通过寄存器传递

三、开发环境配置

3.1 Visual Studio配置

  1. 关闭安全检查: 避免使用security cookie全局变量
  2. 关闭优化: 最小优化可使Shellcode体积减小
  3. 启用MASM: 项目→生成依赖性→生成自定义→勾选masm

3.2 注意事项

  • 32位项目需使用低版本工具集(如VS2017)
  • 64位项目需使用汇编文件(MSVC不支持内联汇编)

四、Shellcode开发关键点

4.1 必须避免的操作

  1. 不使用.rdata节中的全局变量/常量
  2. 不使用导入表
  3. 不使用C++异常
  4. 不使用导入延迟表

4.2 动态获取API的方法

  1. 获取PEB地址: 通过FS/GS寄存器

    mov edx, fs:[30h]  ; 32位获取PEB
    
  2. 遍历模块列表:

    • 通过PEB→Ldr→InMemoryOrderModuleList
    • 比较BaseDllName与目标DLL名称
  3. 解析导出表:

    • 从DLL基地址获取PE头
    • 定位导出表(DataDirectory[0])
    • 遍历导出函数名称

4.3 位置无关代码技巧

  1. 字符串存储在栈中:

    CHAR str[] = {'H','e','l','l','o','\0'};  // 栈存储
    
  2. 避免绝对地址引用

五、Shellcode开发实例

5.1 弹窗Shellcode (MessageBox)

纯汇编实现

; 计算API哈希值
compute_hash:
    xor edi, edi
    xor eax, eax
    lodsb
    test al, al
    jz compute_hash_finished
    ror edi, 0Dh
    add edi, eax
    jmp compute_hash
compute_hash_finished:
    ret

; 动态获取API地址
GetProcAddressByHash:
    pushad
    push eax  ; 保存目标hash
    mov edx, fs:[30h]  ; 获取PEB
    ; ... 完整代码见原文 ...
    ret

关键步骤

  1. 计算kernel32.dll和MessageBoxA的哈希值
  2. 动态获取LoadLibrary和GetProcAddress
  3. 加载user32.dll并获取MessageBoxA地址
  4. 调用MessageBoxA

5.2 远程下载Shellcode

实现流程

  1. VirtualAlloc创建缓存
  2. InternetOpenA初始化会话
  3. InternetConnectA连接服务器
  4. HttpOpenRequestA创建请求
  5. HttpSendRequestA发送请求
  6. InternetReadFile读取数据
  7. InternetCloseHandle关闭句柄

所需API

  • WinINet API: InternetOpenA, InternetConnectA等
  • 内存管理: VirtualAlloc

六、Shellcode提取与测试

6.1 提取.text节

  1. 使用010 Editor打开PE文件
  2. 选择.text节区
  3. 导出为二进制文件(.bin)

6.2 测试方法

  1. 使用pe_to_shellcode工具
  2. 转换为C数组格式
  3. 通过线程注入执行

七、高级主题

7.1 反射式DLL注入

  • 实现自加载的DLL
  • 不依赖Windows加载器

7.2 引导程序(Bootstrap)

  • 定位ReflectiveLoader函数
  • 实现DLL的自加载

八、总结与建议

  1. 纯汇编Shellcode体积最小但开发难度高
  2. C/C++开发需注意避免全局变量和导入表
  3. 熟练掌握PEB遍历和导出表解析是关键
  4. 反射式DLL注入是高级Shellcode的常见技术
  5. 建议从简单功能开始逐步扩展

附录:参考资源

  1. Stephen Fewer的Shellcode开发框架
  2. Metasploit的block_api.asm和block_reverse_http.asm
  3. PE文件结构文档
  4. Windows API文档
Windows Shellcode开发完全指南 一、Shellcode基础概念 1.1 什么是Shellcode 一段精心编写的机器代码,具有位置无关、紧凑高效、直接在CPU上执行等特性 无需编译即可运行 在攻防对抗中常用于网络操作、权限提升、文件操作等 1.2 开发Shellcode的必要性 避免使用公开工具生成的固定特征Shellcode 扩展自定义功能 规避AV/EDR查杀 安全开发人员必备技能 二、汇编基础 2.1 寄存器 x86架构 | 寄存器 | 名称 | 用途 | |--------|------|------| | EAX | 累加器 | 算术运算和函数返回值 | | EBX | 基址寄存器 | 内存寻址 | | ECX | 计数器 | 循环计数 | | EDX | 数据寄存器 | I/O操作 | | ESI | 源索引 | 字符串/数组操作源指针 | | EDI | 目的索引 | 字符串/数组操作目的指针 | | EBP | 基址指针 | 栈帧指针 | | ESP | 栈指针 | 栈顶指针 | x64架构 扩展了x86的8个通用寄存器(R开头的寄存器) 新增r8-r15寄存器 2.2 常用指令 | 指令 | 功能 | |------|------| | mov | 数据传输 | | xor | 寄存器清零或数据解密 | | push/pop | 栈操作 | | jmp | 无条件跳转 | | call | 函数调用 | | lea | 计算内存地址 | | cmp | 比较指令 | 2.3 调用约定 __ stdcall (WINAPI) 参数顺序: 右→左 堆栈清理: 被调用者 典型应用: Windows API __ cdecl 参数顺序: 右→左 堆栈清理: 调用者 支持变参 __ fastcall 部分参数通过寄存器传递 三、开发环境配置 3.1 Visual Studio配置 关闭安全检查: 避免使用security cookie全局变量 关闭优化: 最小优化可使Shellcode体积减小 启用MASM: 项目→生成依赖性→生成自定义→勾选masm 3.2 注意事项 32位项目需使用低版本工具集(如VS2017) 64位项目需使用汇编文件(MSVC不支持内联汇编) 四、Shellcode开发关键点 4.1 必须避免的操作 不使用.rdata节中的全局变量/常量 不使用导入表 不使用C++异常 不使用导入延迟表 4.2 动态获取API的方法 获取PEB地址: 通过FS/GS寄存器 遍历模块列表: 通过PEB→Ldr→InMemoryOrderModuleList 比较BaseDllName与目标DLL名称 解析导出表: 从DLL基地址获取PE头 定位导出表(DataDirectory[ 0 ]) 遍历导出函数名称 4.3 位置无关代码技巧 字符串存储在栈中: 避免绝对地址引用 五、Shellcode开发实例 5.1 弹窗Shellcode (MessageBox) 纯汇编实现 关键步骤 计算kernel32.dll和MessageBoxA的哈希值 动态获取LoadLibrary和GetProcAddress 加载user32.dll并获取MessageBoxA地址 调用MessageBoxA 5.2 远程下载Shellcode 实现流程 VirtualAlloc创建缓存 InternetOpenA初始化会话 InternetConnectA连接服务器 HttpOpenRequestA创建请求 HttpSendRequestA发送请求 InternetReadFile读取数据 InternetCloseHandle关闭句柄 所需API WinINet API: InternetOpenA, InternetConnectA等 内存管理: VirtualAlloc 六、Shellcode提取与测试 6.1 提取.text节 使用010 Editor打开PE文件 选择.text节区 导出为二进制文件(.bin) 6.2 测试方法 使用pe_ to_ shellcode工具 转换为C数组格式 通过线程注入执行 七、高级主题 7.1 反射式DLL注入 实现自加载的DLL 不依赖Windows加载器 7.2 引导程序(Bootstrap) 定位ReflectiveLoader函数 实现DLL的自加载 八、总结与建议 纯汇编Shellcode体积最小但开发难度高 C/C++开发需注意避免全局变量和导入表 熟练掌握PEB遍历和导出表解析是关键 反射式DLL注入是高级Shellcode的常见技术 建议从简单功能开始逐步扩展 附录:参考资源 Stephen Fewer的Shellcode开发框架 Metasploit的block_ api.asm和block_ reverse_ http.asm PE文件结构文档 Windows API文档