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 环境中会被转换破坏。我们需要一种方法:

  1. 去除 shellcode 中的空字节
  2. 确保转换后的代码仍能执行

解决方案框架

  1. 构建解码循环:编写一个循环来去除 shellcode 中的空字节
  2. Unicode 兼容性:确保循环代码本身符合 Unicode 编码要求
  3. 内存定位:解决代码在内存中的定位问题

解码循环设计

基本循环结构

; 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

初始化设置

寄存器初始化

  1. 设置 EBX = 0
6A00 push dword 0x00000000
5D pop ebx
004500 add [ebp + 0x0], al
  1. 设置 ECX = 循环计数
59 pop ecx
004500 add [ebp + 0x0], al
BA00050041 mov edx, 0x41000500
00F5 add ch, dh

内存定位技术

方法1:利用现有寄存器

假设某个寄存器指向代码附近区域:

  1. 使用 xchg 获取近似地址
  2. 通过 add eax, 0x??00??00 调整
  3. 使用 add al, 0x0inc eax 微调

方法2:利用堆栈

如果寄存器不可用,尝试从堆栈中获取地址:

popad  ; 弹出多个寄存器

方法3:极端情况下的解决方案

  1. 选择可写内存区域(如.data段)
  2. 写入3字节补丁(pop eax; push eax; ret)
  3. 相对调用该位置:
E800??00!! call (here + 0x!!00??00)
  1. 调整EAX
0400 add al, 0x0
8900 mov [eax], eax
8300?? add dword [eax], byte 0x??
8B00 mov eax, [eax]

完整流程

  1. 初始化部分(约10字节)

    • 设置EBX和ECX寄存器
    • 添加对齐指令
  2. 循环修补部分(约27字节)

    • 修补循环中的关键字节
    • 确保Unicode兼容性
  3. 循环代码部分(约5字节)

    • 包含原始循环结构
  4. 原始shellcode

    • 放置在循环之后

技术要点总结

  1. 指令选择:精心选择不影响Unicode编码的指令
  2. 空字节处理:使用写入操作动态修补关键字节
  3. 地址计算:通过多种技术获取代码位置
  4. 寄存器操作:利用有限的指令操作寄存器
  5. 内存修补:在运行时动态修改代码

实际应用考虑

  1. shellcode大小:header部分约42字节,适合450字节左右的远程shellcode
  2. 可靠性:需要根据目标环境调整定位技术
  3. 兼容性:确保在所有目标系统上都能正确解码

通过这种技术,我们可以构建出在Unicode转换后仍能正常工作的shellcode,为特定环境下的漏洞利用提供了有效解决方案。

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