Coding art in shellcode(2)
字数 1133 2025-08-05 08:16:26
Unicode Shellcode 编码技术详解
前言
本文详细讲解如何将标准 shellcode 转换为 Unicode 编码的 shellcode,使其在字符转换后仍能正常工作。这是《Coding art in shellcode》系列的第二部分,重点介绍如何利用有限的指令集构建有效的 Unicode shellcode。
核心策略
问题概述
标准 shellcode 包含大量空字节(0x00),在 Unicode 环境中会被转换破坏。我们需要一种方法:
- 去除 shellcode 中的空字节
- 确保转换后的代码仍能执行
解决方案框架
- 构建解码循环:编写一个循环来去除 shellcode 中的空字节
- Unicode 兼容性:确保循环代码本身符合 Unicode 编码要求
- 内存定位:解决代码在内存中的定位问题
解码循环设计
基本循环结构
; eax points to our shellcode
; ebx is 0x00000000
; ecx is 0x00000500 (缓冲区大小示例)
label:
inc ebx
mov byte dl, [eax + 2 * ebx] ; 读取Unicode编码的字节
mov byte [eax + ebx], dl ; 写入解码后的字节
loop label
Unicode 转换问题
原始操作码:
43 8A 14 58 88 14 18 E2 F7
转换为 Unicode 后会插入空字节:
43 00 8A 00 14 00 58 00 88 00 14 00 18 00 E2 00 F7
修补空字节
通过写入操作修补关键字节:
mov byte [eax], 0x8A
inc eax
inc eax
mov byte [eax], 0x58
inc eax
inc eax
mov byte [eax], 0x14
inc eax
使用 add [ebp+0x0], al 指令对齐空字节:
40 inc eax
004500 add [ebp + 0x0], al
40 inc eax
004500 add [ebp + 0x0], al
C60058 mov byte [eax], 0x58
初始化设置
寄存器初始化
- 设置 EBX = 0:
6A00 push dword 0x00000000
5D pop ebx
004500 add [ebp + 0x0], al
- 设置 ECX = 循环计数:
59 pop ecx
004500 add [ebp + 0x0], al
BA00050041 mov edx, 0x41000500
00F5 add ch, dh
内存定位技术
方法1:利用现有寄存器
假设某个寄存器指向代码附近区域:
- 使用
xchg获取近似地址 - 通过
add eax, 0x??00??00调整 - 使用
add al, 0x0和inc eax微调
方法2:利用堆栈
如果寄存器不可用,尝试从堆栈中获取地址:
popad ; 弹出多个寄存器
方法3:极端情况下的解决方案
- 选择可写内存区域(如.data段)
- 写入3字节补丁(pop eax; push eax; ret)
- 相对调用该位置:
E800??00!! call (here + 0x!!00??00)
- 调整EAX:
0400 add al, 0x0
8900 mov [eax], eax
8300?? add dword [eax], byte 0x??
8B00 mov eax, [eax]
完整流程
-
初始化部分(约10字节)
- 设置EBX和ECX寄存器
- 添加对齐指令
-
循环修补部分(约27字节)
- 修补循环中的关键字节
- 确保Unicode兼容性
-
循环代码部分(约5字节)
- 包含原始循环结构
-
原始shellcode
- 放置在循环之后
技术要点总结
- 指令选择:精心选择不影响Unicode编码的指令
- 空字节处理:使用写入操作动态修补关键字节
- 地址计算:通过多种技术获取代码位置
- 寄存器操作:利用有限的指令操作寄存器
- 内存修补:在运行时动态修改代码
实际应用考虑
- shellcode大小:header部分约42字节,适合450字节左右的远程shellcode
- 可靠性:需要根据目标环境调整定位技术
- 兼容性:确保在所有目标系统上都能正确解码
通过这种技术,我们可以构建出在Unicode转换后仍能正常工作的shellcode,为特定环境下的漏洞利用提供了有效解决方案。