文章总结: 本文系统解析Base编码家族,从Base2到Base256,按2的幂次、优化型、压缩型三类阐述核心原理与场景。重点详解Base16/32/64等常用编码及Base45/58/62/85等特殊变体,提供效率对比表与选择指南。文末提及Base编码在免杀木马中的混淆应用,但指出现代EDR需结合多层技术对抗。
综合评分: 78
文章分类: 渗透测试,代码审计,恶意软件,安全开发,CTF
Base编码家族完整解析
原创
泷羽Sec静安
泷羽Sec静安
泷羽Sec-静安
2026年2月9日 23:55
云南
关注泷羽Sec和泷羽Sec-静安公众号,这里会定期更新与 OSCP、渗透测试等相关的最新文章,帮助你理解网络安全领域的最新动态。后台回复“OSCP配套工具”获取相关的工具
🌈 Base编码家族完整解析
从Base2到Base256 – 全方位解析编码世界。Base 编码家族的核心逻辑其实很统一。
📚 核心原理总结
Base编码的本质:进制转换
编码本质:将二进制数据转换为特定字符集表示的过程,就是进制转换。
原始数据(二进制)→ 分组 → 映射到字符集 → 编码结果
⚙️ 工作原理示例(Base64编码”ABC”)
Step 1: 文本转二进制
A → 65 → 01000001
B → 66 → 01000010
C → 67 → 01000011
合并为:010000010100001001000011
Step 2: 24 bit分为4组(每组6 bit)
010000 | 010100 | 001001 | 000011
16 | 20 | 9 | 3
Step 3: 映射到Base64字符
16 → Q
20 → U
9 → J
3 → D
结果: "QUJD"
This image shows approximately how the text “Sun” is encoded to base64
图片来源于 What is base64 Encoding and Why is it Necessary?[1]
看懂原理的话,其实就是一个数学题,极限一点的情况你甚至可以直接自己手算,百分百纯手搓Base,[[🧮 Base64手算心算极限分析]],一般情况是不建议的。
🎯 Base编码的三大类别
核心分类原理
第一类:2的幂次编码 (2^n) - 固定bit分组
第二类:优化型编码 - 去除特定字符
第三类:压缩型编码 - 数学转换算法
💡 关键区别
- • 2^n编码:简单、快速、可以直接bit操作
- • 非2^n编码:需要数学运算(除法/模运算),但更灵活
📦 第一类:2的幂次编码
这些编码基于2^n,可以直接进行二进制bit分组操作,效率最高。
Base2 (Binary)
基本信息
- • 字符数: 2 (2^1)
- • 字符集:
0, 1 - • 分组: 1 bit = 1 字符
- • 效率: 12.5% (膨胀800%)
编码原理
最基础的编码,直接显示二进制形式。
每个bit对应一个字符(0或1)。
应用场景
- • 教学演示二进制原理
- • 数字电路设计
- • 底层调试
示例
字符 'A' (ASCII 65):
65 = 01000001
编码结果: "01000001"
Base4 (Quaternary)
基本信息
- • 字符数: 4 (2^2)
- • 字符集:
0, 1, 2, 3 - • 分组: 2 bit = 1 字符
- • 效率: 25% (膨胀400%)
编码原理
每2个bit组合成一个字符。
DNA序列编码的基础。
应用场景
- • DNA序列表示 (A=0, C=1, G=2, T=3)
- • 生物信息学
示例
二进制: 01001011
分组: 01 | 00 | 10 | 11
结果: 1 0 2 3
Base8 (Octal)
基本信息
- • 字符数: 8 (2^3)
- • 字符集:
0-7 - • 分组: 3 bit = 1 字符
- • 效率: 37.5% (膨胀267%)
编码原理
Unix系统中的经典编码。
每3个bit组合成一个0-7的数字。
应用场景
- • Unix文件权限 (chmod 755)
- • 早期计算机系统
- • 嵌入式系统
示例
chmod 755:
7 = 111 (rwx - 读写执行)
5 = 101 (r-x - 读执行)
5 = 101 (r-x - 读执行)
Base16 (Hex adecimal) ⭐
基本信息
- • 字符数: 16 (2^4)
- • 字符集:
0-9, A-F - • 分组: 4 bit = 1 字符
- • 效率: 50% (膨胀200%)
编码原理
最常用的编码之一。
1个字节正好对应2个十六进制字符,非常直观。
0123456789ABCDEF
编码过程
字节: 0xAB (10101011)
分解: 1010 | 1011
转换: A | B
结果: "AB"
应用场景
- • 颜色代码 (#FF5733)
- • 内存地址显示
- • 哈希值 (MD5, SHA)
- • 调试输出
- • MAC地址
示例
颜色 #FF5733:
FF = 255 (红色通道)
57 = 87 (绿色通道)
33 = 51 (蓝色通道)
Base32
基本信息
- • 字符数: 32 (2^5)
- • 字符集:
A-Z, 2-7 - • 分组: 5 bit = 1 字符
- • 效率: 62.5% (膨胀160%)
编码原理
不区分大小写,避免0/O、1/I/l混淆。
每5字节转8字符。
ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
字符集设计
去除的字符及原因:
- 0 (零):易与大写O混淆
- 1 (一):易与大写I和小写l混淆
- 8:易与大写B混淆
- 9:易与小写g混淆
保留字符:
A-Z (26个) + 2-7 (6个数字) = 32个
应用场景
- • Google Authenticator密钥
- • 双因素认证 (TOTP)
- • Tor洋葱地址
- • 需要人工输入的场景
示例
文本 "Hello"
Base32: JBSWY3DPEQ======
(注意填充字符 = )
📐 填充计算公式
公式1:计算编码后长度
编码后字符数 = ⌈(字节数 × 8) / 5⌉
向上取整到8的倍数
公式2:计算填充数量
填充个数 = 8 - (编码后实际字符数 % 8)
如果结果是8,则不需要填充
🔢 详细推导过程
为什么是8的倍数?
Base32编码规律:
5字节 = 40 bit
40 bit ÷ 5 bit/字符 = 8字符
所以每处理5字节,产生8字符
→ 输出长度必须是8的倍数
📊 所有可能的情况
完整对照表
| 原始字节数 | bit总数 | Base32字符数 | 填充’=’个数 | 总长度 | 示例 |
| — | — | — | — | — | — |
| 0 | 0 | 0 | 0 | 0 | (空字符串) |
| 1 | 8 | 2 | 6 | 8 | “ME======” |
| 2 | 16 | 4 | 4 | 8 | “MFRA====” |
| 3 | 24 | 5 | 3 | 8 | “MFRGG===” |
| 4 | 32 | 7 | 1 | 8 | “MFRGGZA=” |
| 5 | 40 | 8 | 0 | 8 | “MFRGGZDF” |
| 6 | 48 | 10 | 6 | 16 | “MFRGGZDFMY======” |
| 7 | 56 | 12 | 4 | 16 | “MFRGGZDFMZRA====” |
| 8 | 64 | 13 | 3 | 16 | “MFRGGZDFMZRGG===” |
| 9 | 72 | 15 | 1 | 16 | “MFRGGZDFMZRGGZA=” |
| 10 | 80 | 16 | 0 | 16 | “MFRGGZDFMZRGGZDF” |
Base64 ⭐⭐⭐ (最常用)
推荐阅读:what-is-base64[2]Base64[3]
基本信息
- • 字符数: 64 (2^6)
- • 字符集:
A-Z, a-z, 0-9, +, / - • 分组: 6 bit = 1 字符 (3字节→4字符)
- • 效率: 75% (膨胀133%)
编码原理
最常用的编码!
效率和兼容性的最佳平衡点。
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
完整编码过程
3字节 (24 bit) → 分成4组(每组6 bit) → 4个Base64字符
示例:"ABC"
A = 65 → 01000001
B = 66 → 01000010
C = 67 → 01000011
合并: 010000 | 010100 | 001001 | 000011
索引: 16 | 20 | 9 | 3
字符: Q | U | J | D
结果: "QUJD"
字符集索引表
索引 0-25 → A-Z
索引 26-51 → a-z
索引 52-61 → 0-9
索引 62 → +
索引 63 → /
填充字符 → =
填充规则
原始数据长度 % 3 = 0 → 无填充
原始数据长度 % 3 = 1 → 添加 ==
原始数据长度 % 3 = 2 → 添加 =
示例:
"A" (1字节) → "QQ=="
"AB" (2字节) → "QUI="
"ABC" (3字节) → "QUJD"
应用场景
- • 电子邮件附件 (MIME)
- • 网页嵌入图片 (Data URL)
- • JWT令牌
- • Cookie存储
- • API响应
- • HTTP Basic认证
Base64 变种全景
1. 标准 Base64(RFC 4648 §4)
字符表:A-Za-z0-9+/,填充 =
这是最常见的 Base64,用于 MIME 邮件附件、PEM 证书等。
2. Base64 URL-safe(RFC 4648 §5)
字符表:A-Za-z0-9-_
你已经了解了,+/ 替换为 -_,避免 URL 编码冲突。JWT 就用的这个。
3. Radix-64(RFC 4880)
字符表:0-9A-Za-z+/=
用于 OpenPGP/GPG 的 ASCII Armor 输出。本质和标准 Base64 字符集相同,但额外带一个 CRC24 校验和(以 = 开头的独立行),这是和普通 Base64 的关键区别:
-----BEGIN PGP MESSAGE-----
jA0EBwMC...(Base64 数据)
=nkDL ← 这是 CRC24 校验,不是填充!
-----END PGP MESSAGE-----
4. Uuencoding
字符表:[space]-_(ASCII 32-95,共 64 个字符)
Unix 早期的二进制编码方式(比 Base64 更古老)。每行以长度字符开头,以 “` 结尾表示结束。编码效率和 Base64 相同(3→4),但因为包含空格,在很多传输场景下容易出错,已被 Base64 取代。
begin 644 filename.txt
#0V%T
`
end
5. Xxencoding
字符表:+-0-9A-Za-z
Uuencoding 的改进版,避免了空格字符。格式和 Uuencoding 类似但字符集更”安全”。现在极少见。
6. BinHex
字符表:!-,-0-689@A-NP-VX-Z[a-fh-mp-r`
这是 经典 Macintosh 的编码方案(BinHex 4.0),用于在早期互联网上传输 Mac 文件(包含资源分支 Resource Fork)。使用 64 个精心挑选的字符,刻意避开了容易混淆或传输出错的字符。现在基本已死。
7. ROT13 变种
字符表:N-ZA-Mn-za-m0-9+/=
不是独立编码,而是对标准 Base64 的字符表做了 ROT13 旋转。即先 Base64 编码,然后对结果中的字母部分做 ROT13。用途极其罕见,偶尔在 CTF 中出现。
8. UNIX crypt
字符表:./0-9A-Za-z
用于 Unix /etc/shadow 中的密码哈希(如传统 DES crypt、MD5 crypt $1$、SHA-512 crypt $6$ 等)。注意字符顺序和标准 Base64 完全不同:. 和 / 排在最前面,A 的值是 12 而不是 0。
$6$rounds=5000$salt$hashhashhashhash...
^^^^^^^^^^^^^^^^ 这部分用的就是 crypt Base64
9. 其他变种
| 名称 | 字符表 | 说明 |
| — | — | — |
| Atom128 | /128GhIoPQROSTeUbADfgHijKLM... | 自定义字符表的 Base64 变种,常见于 CTF |
| Megan35 | 3GHIJKLMNOPQRSTUb=cdefghij... | 类似,只是打乱了字符映射顺序 |
| Zong22 | ZKj9n+yf0wDVX1s/5YbdxSo=ILaU... | 同上 |
| Hazz15 | HNO4klm6ij9n+J2hyf0gzA8uvwDE... | 同上 |
这四个本质都是 Base64 + 自定义字母表替换。解码方式就是先用自定义表映射回标准 Base64 字符,再正常解码。CyberChef 和一些在线工具直接支持这些变种。
快速对比总结
| 变种 | 填充 | 典型场景 | 还活着? |
| — | — | — | — |
| 标准 Base64 | = | MIME, PEM, 通用 | ✅ |
| URL-safe | 可选 | JWT, URL参数 | ✅ |
| Radix-64 | = + CRC24 | PGP/GPG | ✅ |
| Uuencoding | 无 | 早期Unix邮件 | ☠️ |
| Xxencoding | 无 | Uuencode替代 | ☠️ |
| BinHex | : | 经典Mac文件 | ☠️ |
| UNIX crypt | 无 | 密码哈希 | ✅ |
| Atom128等 | = | CTF/混淆 | 🏴☠️ |
CTF 中如果遇到”看起来像 Base64 但解不出来”的情况,大概率就是这些自定义字母表变种,可以尝试 Atom128/Megan35/Zong22/Hazz15 或者用频率分析推断字母表映射。
Base128
基本信息
- • 字符数: 128 (2^7)
- • 字符集: ASCII 0-127
- • 分组: 7 bit = 1 字符
- • 效率: 87.5% (膨胀114%)
编码原理
使用完整的ASCII字符集(包括控制字符)。
⚠️ 问题
包含不可打印字符:
- 控制字符 (0-31)
- DEL (127)
实际应用很少。
Base256 (理论极限)
基本信息
- • 字符数: 256 (2^8)
- • 字符集: 所有字节值 (0x00-0xFF)
- • 分组: 8 bit = 1 字符
- • 效率: 100% (无膨胀)
编码原理
这不是"编码",而是原始二进制数据。
8 bit = 1 字节 = 1 字符。
⚠️ 问题
包含大量不可打印和控制字符,
无法在文本环境中安全传输。
应用场景
- • 二进制文件存储
- • 网络字节流
- • 不需要文本转换的场景
🎨 第二类:优化型编码
这些编码通过去除易混淆和转义的字符,提高人类可读性、输入准确性和应用性。
Base45 (二维码专用) ⭐
基本信息
- • 字符数: 45
- • 字符集:
0-9, A-Z, 空格, $%*+-./: - • 设计目标: QR码字母数字模式优化
为什么 Base45 是为 QR 码量身定做的
关键:QR 码的编码模式
QR 码有 4 种数据模式,效率差异巨大:
| 模式 | 支持字符 | 每字符消耗 |
| — | — | — |
| Numeric | 0-9 | 3.33 bit |
| Alphanumeric | 0-9 A-Z + 9个特殊符(共45个) | 5.5 bit |
| Byte | 任意 | 8 bit |
| Kanji | 日文 | 13 bit |
Base45 的字符表 恰好就是 QR Alphanumeric 模式的 45 个字符,这不是巧合,而是故意设计的。
🔧 为什么是45?
QR码字母数字模式 (Alphanumeric) - 支持45个字符 ⭐ 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:
QR码字母数字模式支持的字符集 (45个):
┌─────────────────────────────────┐
│ 数字: 0-9 (10个) │
│ 字母: A-Z (26个) │
│ 特殊: 空格 $ % * + - . / : (9个) │
└─────────────────────────────────┘
总计 = 10 + 26 + 9 = 45个字符
编码过程(手动演示)
"Hello World" 的字节: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
每2字节 → 合成一个数 → 除45连续取余得3个字符:
[72, 101] → 72×256+101 = 18533 → %69
18533 ÷ 45 = 411 余 38 → CHARS[38] = '%'
411 ÷ 45 = 9 余 6 → CHARS[6] = '6'
9 ÷ 45 = 0 余 9 → CHARS[9] = '9'
CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
↑ ↑
索引0 索引38 = '%'
→ '%' '6' '9' → %69
[108, 108] → 27756 → VD
[111, 32] → 28448 → 82E
...
末尾1字节 → 2个字符:
[100] → 100 → A2
结果: %69 VD82EI2B.KEA2
末尾只剩1个字节就不配对了,直接拿这个字节值做除45取余:
100 ÷ 45 = 2 余 10 → CHARS[10] = 'A'
2 ÷ 45 = 0 余 2 → CHARS[2] = '2'
→ A2
只剩1字节最大值是255,2个 Base45 字符能表示 45²-1=2024,绰绰有余,所以用2个字符。而2字节配对最大值是65535,需要3个字符(45³-1=91124 > 65535 ✓)。
import math
# Base45 标准字符集
BASE45_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
def base45_encode(data: bytes) -> str:
res = ""
# 每两个字节处理一次 (16位)
for i in range(0, len(data) // 2 * 2, 2):
# 计算 16 位整数值 (大端序)
val = (data[i] << 8) + data[i + 1]
# 转换为 3 个 Base45 字符 (小端序排列:c = val % 45, ...)
# val = c[0] + c[1]*45 + c[2]*45^2
res += BASE45_CHARSET[val % 45]
res += BASE45_CHARSET[(val // 45) % 45]
res += BASE45_CHARSET[(val // 45 // 45) % 45]
# 处理末尾剩余的一个字节
if len(data) % 2 == 1:
val = data[-1]
res += BASE45_CHARSET[val % 45]
res += BASE45_CHARSET[(val // 45) % 45]
return res
def base45_decode(s: str) -> bytes:
res = bytearray()
# 每三个字符处理一次
for i in range(0, len(s) // 3 * 3, 3):
# 找到对应字符的索引
c0 = BASE45_CHARSET.index(s[i])
c1 = BASE45_CHARSET.index(s[i+1])
c2 = BASE45_CHARSET.index(s[i+2])
val = c0 + c1 * 45 + c2 * 45**2
# 还原为两个字节
res.append((val >> 8) & 0xFF)
res.append(val & 0xFF)
# 处理末尾剩余的两个字符(还原为一个字节)
if len(s) % 3 == 2:
c0 = BASE45_CHARSET.index(s[-2])
c1 = BASE45_CHARSET.index(s[-1])
val = c0 + c1 * 45
res.append(val)
return bytes(res)
# --- 测试 ---
original = "Hello World".encode('utf-8')
encoded = base45_encode(original)
decoded = base45_decode(encoded)
print(f"原始数据: {original}")
print(f"Base45 编码: {encoded}")
print(f"Base45 解码: {decoded.decode('utf-8')}")
为什么不直接放 Base64?
Base64 输出包含小写字母 → QR 码被迫使用 Byte 模式(8 bit/字符)。Base45 虽然膨胀率更高(50% vs 33%),但 QR 码用 Alphanumeric 模式只需 5.5 bit/字符,综合下来 QR 码反而更小:
QR码存储效率:
- 字母数字模式: 2个字符占11 bit
- 字节模式: 1个字符占8 bit
100字节原始数据:
Base64 → 134字符 × 8 bit = 1072 bit (Byte模式)
Base45 → 150字符 × 5.5 bit = 825 bit (Alphanumeric模式) ✅ 更小!
Base45在QR码中比Base64节省约30%空间!
应用场景
- • 欧盟COVID-19数字证书(健康码/绿码)
- • 登机牌二维码
- • 移动票务系统
- • 任何需要优化QR码的场景
Base45生成QR码详细原理见[[Base45与QR码生成]]
Base58 ⭐
基本信息
- • 字符数: 58
- • 字符集:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz - • 算法: 大整数除法(非bit分组)
- • 填充: 无填充字符
🔧 为什么是58?
Base64字符集 (64个):
A-Z, a-z, 0-9, +, /
去除易混淆字符 (6个):
- 0 (零) - 易与大写O混淆
- O (大写O) - 易与数字0混淆
- I (大写I) - 易与小写l和数字1混淆
- l (小写L) - 易与大写I和数字1混淆
- + (加号) - 在某些环境中有特殊含义
- / (斜杠) - 在URL和文件路径中有特殊含义
剩余字符 = 64 - 6 = 58个
编码算法(与2^n的根本区别)
def base58_encode(data):
"""
Base58编码:使用大整数除法
这是与Base64等2^n编码的核心区别
"""
# 字符集(58个字符)
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
# 1. 将数据看作一个大整数(而非bit分组)
num = int.from_bytes(data, byteorder='big')
# 2. 不断除以58取余数(关键!)
result = ''
while num > 0:
num, remainder = divmod(num, 58) # 除以58,而非2的幂次
result = ALPHABET[remainder] + result
# 3. 处理前导零字节(映射为'1')
for byte in data:
if byte == 0:
result = '1' + result
else:
break
return result or '1'
# 为什么不是bit分组?
# 因为58不是2的幂次,无法整除bit
# 58 ≠ 2^n (对于任意整数n)
设计目标
✅ 适合人类手工抄写
✅ OCR(光学字符识别)准确
✅ 双击选中整个字符串
✅ 避免视觉混淆
应用场景
- • 比特币地址:
1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa - • IPFS内容哈希:
Qm... - • 加密货币钱包地址
- • 需要手工输入的场景
示例
Bitcoin地址示例:
1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
↑
首字符'1'表示这是比特币主网地址
Bitcoin Base58
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
用于 比特币地址(如 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa)和 WIF 私钥。通常配合 Base58Check(末尾附加4字节 SHA256d 校验和),防止抄错地址把币转丢。
Ripple Base58
rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz
用于 XRP (Ripple) 地址。字符集和 Bitcoin 完全相同的58个字符,但顺序不同——字符的数值映射被打乱了。所以同样的二进制数据,用 Bitcoin 表编码和用 Ripple 表编码结果完全不同。
两者区别仅在字母表顺序,算法本身一模一样。
Base62
基本信息
- • 字符数: 62
- • 字符集:
0-9, A-Z, a-z - • 算法: 大整数除法
编码原理
只使用字母和数字,
去除了Base64的特殊字符(+, /),
适合URL和文件名。
应用场景
- • 短链接服务 (bit.ly, tinyurl)
- • URL安全编码
- • 文件名编码
- • YouTube视频ID
示例
短链接: i9n.cn/l09tk
^^^^^^^^
Base62编码
Base62 短链接原理
推荐阅读:深入理解短链服务:原理、设计与实现全解析[4]
字符表
0-9 A-Z a-z(共62个字符)
相比 Base64 去掉了 + 和 /,纯字母数字,天然 URL 安全。
Warning
短链接并不是base62加密而是62进制转换,只是用了和base62相同的字母表
短链接:数字 694525844 → 当作整数做进制转换 → l09tk
CyberChef 的 To Base62:字符串 "694525844" → 当作9个ASCII字节 36 39 34 35 32 35 38 34 34 → 数据编码 → JD1K0y2DQgz6
两者共享同一个字母表 0-9A-Za-z,但操作本质不同。这个区别其实贯穿整个 Base 家族:
- • Base16(hex):既可以是数据编码(把字节流转成hex),也可以是进制转换(十进制转十六进制)
- • Base64:几乎总是数据编码
- • Base62:短链接场景下是进制转换,CyberChef 里是数据编码
- • Base58:比特币地址本质上也是对大整数的进制转换(256位私钥/公钥哈希 → Base58 字符串)
所以 CTF 里看到 Base62 要注意判断,先试数据编码(CyberChef),不对再试纯进制转换。
核心流程
长URL → 数据库存储得到自增ID → ID作62进制转换 → 拼接为短链接
具体来说:以 http://i9n.cn/l09tk 为例:
1. 存储映射
用户提交过长的网址: https://ruajingjing.top/article/CVE-2026-21858%20%E5%9B%A0%E4%B8%8D%E5%BD%93%E7%9A%84%20Webhook%20%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E8%80%8C%E6%98%93%E5%8F%97%E6%9C%AA%E8%AE%A4%E8%AF%81%E6%96%87%E4%BB%B6%E8%AE%BF%E9%97%AE/
i9n.cn网站数据库使用哈希算法(如MurmurHash)或其他算法分配自增ID: 694525844 (十进制)
2. 十进制 → Base62
CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def to_base62_radix(n):
"""十进制整数 → 62进制字符串"""
result = []
while n > 0:
result.append(CHARS[n % 62])
n //= 62
return ''.join(reversed(result)) or '0'
# 测试
print(to_base62_radix(694525844)) # → l09tk
6位 Base62字母表 可以表示 62⁶ ≈ 568亿 个不同的 URL,足够用了。
3. 访问时反向解析
域名: i9n.cn ← 短链接服务的短域名
短码: l09tk ← Base62 编码的数据库ID
解码过程:
l09tk → 逐字符查表求值
l = 47 × 62⁴ = 694,487,792
0 = 0 × 62³ = 0
9 = 9 × 62² = 34,596
t = 55 × 62¹ = 3,410
k = 46 × 62⁰ = 46
─────────────────────────
合计 694,525,844
CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def from_base62_radix(s):
"""62进制字符串 → 十进制整数"""
n = 0
for c in s:
n = n * 62 + CHARS.index(c)
return n
# 测试
print(from_base62_radix('l09tk')) # → 694525844
所以当你访问这个短链接时,服务器做的事情就是:
l09tk → 694525844 → SELECT original_url FROM urls WHERE id=694525844 → 302重定向
5位短码能表示 62⁵ ≈ 9.16亿 个URL,这个 ID 快7亿了,说明 i9n.cn 这个服务用量不小(当然实际可能不是简单自增,可能有混淆)。
为什么选 Base62
| 方案 | 问题 |
| — | — |
| 直接用十进制ID | i9n.cn/694525844 太长了 |
| Base16 (hex) | i9n.cn/363934353235383434 更长 |
| Base62 | i9n.cn/l09tk 6位搞定 |
| Base64 | +/= 在URL里需要转义 |
本质就是一个进制转换把大数字压缩到更短的字符串表示,没有什么编码/解码数据的含义,和 Base64 编码二进制数据的用途完全不同。
实际工程中的额外考虑
短链接服务还会处理自增ID可预测(容易被遍历爬取)的问题,通常会在 ID 上做一层双射混淆(如乘以一个与 62⁶ 互素的数再取模),使得连续 ID 映射到看起来随机的短码,但不影响反向解析。
知名的商业短链接服务
bit.ly[5] 是最知名的商业短链接服务,提供免费和付费版本。付费版支持自定义域名、点击分析、A/B测试等。类似的服务还有 TinyURL[6]、短网址[7] (国内)等。
自建短链服务
如果你想自建短链服务完全可以,而且技术上很简单,核心就是一个 Web 服务 + 数据库 + 重定向逻辑。最小实现大概就这么点东西:
# Flask 示例,核心逻辑不到30行
from flask import Flask, redirect, request
import sqlite3
app = Flask(__name__)
CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def to_base62(n):
result = []
while n > 0:
result.append(CHARS[n % 62])
n //= 62
return ''.join(reversed(result)) or '0'
@app.route('/shorten', methods=['POST'])
def shorten():
url = request.json['url']
# 插入数据库,拿到自增ID
conn = sqlite3.connect('urls.db')
cur = conn.execute("INSERT INTO urls(original) VALUES(?)", (url,))
short = to_base62(cur.lastrowid)
conn.commit()
return {"short": f"https://s.yourdomain.com/{short}"}
@app.route('/<code>')
def resolve(code):
# Base62 → ID → 查库 → 重定向
n = sum(CHARS.index(c) * 62**i for i, c in enumerate(reversed(code)))
conn = sqlite3.connect('urls.db')
row = conn.execute("SELECT original FROM urls WHERE id=?", (n,)).fetchone()
if row:
return redirect(row[0], 301)
return "Not found", 404
自建的好处是数据完全自控,可以加统计、防滥用、自定义短码等。生产环境把 SQLite 换成 Redis(高性能)或 MySQL,加上 Nginx 反代,再配一个短域名就行了。
GitHub 上也有很多开源方案,搜 “self-hosted URL shortener” 能找到不少现成的。
🚀 第三类:压缩型编码
这些编码追求更高的压缩率,使用更大的字符集和复杂算法。通常应用在看重数据压缩性的场景。
Base85 (Ascii85) ⭐
基本信息
- • 字符数: 85
- • 字符集: ASCII 33-117 (可打印字符
!到u) - • 分组: 4字节 → 5字符
- • 效率: 80% (膨胀125%)
🔧 编码原理
每4个字节(32 bit)作为一组:
步骤1: 4字节 → 转为32位无符号整数
步骤2: 将整数除以85取余数(5次)
步骤3: 余数映射到字符集
示例:
4字节: 0x12 0x34 0x56 0x78
转整数: 0x12345678 = 305,419,896
除法过程:
305419896 ÷ 85 = 3593175 ... 21 → 字符索引21 → '6'
3593175 ÷ 85 = 42272 ... 55 → 字符索引55 → 'T'
42272 ÷ 85 = 497 ... 27 → 字符索引27 → '<'
497 ÷ 85 = 5 ... 72 → 字符索引72 → 'd'
5 ÷ 85 = 0 ... 5 → 字符索引5 → '$'
结果: "$d<T6" (从右到左读取)
实际: "6T<d$" (反转后)
特殊优化
全零组压缩:
4个全零字节 (0x00000000) → 用单个 'z' 表示
全空格压缩(某些实现):
4个空格字节 (0x20202020) → 用单个 'y' 表示
字符集
起始字符: ! (ASCII 33)
结束字符: u (ASCII 117)
共85个连续可打印字符
完整字符集:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu
应用场景
PostScript / PDF
PostScript(1984年)和 PDF 本质上是纯文本格式——它们的文件内容是可读的指令代码。但图片、字体这些是二进制数据,必须编码成文本才能嵌入。
Adobe 最早用的是 Base16(hex),但膨胀 100% 太大了。所以他们发明了 Ascii85,膨胀只有 25%。对比:
一张100KB的图片嵌入PDF:
Hex编码: 200KB (+100%)
Base64: 133KB (+33%)
Ascii85: 125KB (+25%) ← Adobe选了这个
为什么不用 Base64?因为 PostScript 诞生于 1984 年,比 Base64 标准化(1987 MIME RFC)更早。Adobe 自己造了一套,而且 25% 比 33% 更省空间,在那个年代存储和带宽都很贵。
PDF 里长这样:
stream
<~87cURD]j7BEbo80~>
endstream
<~ 和 ~> 是 Ascii85 的定界符,PDF 解析器看到这个就知道要做 Ascii85 解码。
Git 内部对象存储
Git 的 pack 文件索引(.idx 文件)用的不是标准 Ascii85,而是一种自定义的 Base85 变种来编码二进制 diff。
Git 传输 binary diff 时面临一个问题:patch 文本格式(邮件、终端)只能安全传输可打印字符。Git 用 Base85 把二进制差异编码成文本行,这样 git format-patch 生成的补丁文件可以安全地通过邮件发送:
diff --git a/image.png b/image.png
GIT binary patch
literal 1234
zcmV;@1{MYmP)<h;3K|Lk000e1NJLTq...
这里的乱码行就是 Base85 编码的二进制数据。选 Base85 而不是 Base64 的原因很简单——同样的二进制 diff,Base85 编码更短,patch 文件更小,邮件传输更快。
这些场景的共同点是 “二进制数据必须嵌入纯文本环境”,选 Base85 的原因是它在所有不依赖特定字符集的编码方案中膨胀率最低(25%),而 Base64(33%)和 Hex(100%)都更浪费空间。代价是算法稍复杂一点(除以 85 vs 除以 64 的位移),但在这些场景下空间比计算更重要。
Base85 变种
Base85 用 ASCII 33(!) 到 ASCII 117(u) 共85个可打印字符,把每4字节编码为5个字符,膨胀率仅 25%(优于 Base64 的 33%)。
Standard(Ascii85 / btoa)
字符范围:! " # $ % & ' ( ) * + , - . / 0-9 : ; < = > ? @ A-Z [ \ ] ^ _ ` a-u
即 ASCII 33-117
Adobe PostScript/PDF 中使用,格式以 <~ 开头 ~> 结尾。特殊优化:4个 \x00 编码为单个 z。
<~87cURD]j7BEbo80~> ← "Hello World"
Z85(ZeroMQ)
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#
专门为 ZeroMQ 消息帧 设计。刻意避开了 '(单引号) 和 "(双引号),这样编码结果可以安全地放在 JSON 字符串或各种编程语言的字符串字面量里,不需要转义。
IPv6 Base85(RFC 1924)
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~
把 128-bit 的 IPv6 地址编码为 恰好20个字符:
标准: 2001:0db8:85a3::8a2e:0370:7334
Base85: 9R}vSQ*E5@FLbBxBP54
不过这个 RFC 是 1996年愚人节发布的(April 1st RFC),从未被正式采用,但算法本身是可用的。
Base91
基本信息
- • 字符数: 91
- • 字符集: 可打印ASCII (去除
\,',") - • 效率: ~81-82%
字符集
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"
应用场景
- • 数据压缩后的编码
- • 网络传输优化
Base91 的核心巧妙之处在于变长取位:
缓冲区够13bit时:
低13bit值 >= 88 → 取13bit → 2字符表示 (91²=8281 能覆盖 8191-88+1=8104种)
低13bit值 < 88 → 取14bit → 2字符表示 (91²=8281 能覆盖 88×91+剩余 种)
这样每2个输出字符承载 13~14 bit,平均约 6.5 bit/字符,比 Base85 的 6.4 bit/字符再好一点。至于 Base92 只是多了1个字符,原理完全一样,91 变 92,收益微乎其微(理论极限 log₂(92)=6.52 vs log₂(91)=6.51),实际没什么人用。
Base92
基本信息
- • 字符数: 92
- • 字符集: 92个可打印字符
- • 效率: ~82%
字符集
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&()*+,-./:;<=>?@[]^_`{|}~"
Base100 (Emoji编码) 😄
推荐仓库:https://github.com/AdamNiederer/base100
推荐仓库:https://github.com/stek29/base100
基本信息
- • 字符数: 100
- • 字符集: 100个Emoji表情
- • 特点: 视觉友好,趣味性
Base100 很有意思,它把每个字节映射成一个 emoji。
🎨 核心原理
每个字节(0-255)编码为一个 UTF-8 的 4 字节 emoji:
固定前缀: F0 9F (所有emoji都以这两个字节开头)
第3字节: (b + 55) // 64 + 143
第4字节: (b + 55) % 64 + 128
本质就是把 字节值+55 拆成高6位和低6位,塞进 UTF-8 的编码结构里。
逐步演示
字符 'H' = 72
72 + 55 = 127
第3字节: 127 // 64 + 143 = 1 + 143 = 144 = 0x90
第4字节: 127 % 64 + 128 = 63 + 128 = 191 = 0xBF
→ F0 9F 90 BF → UTF-8解码 → 🐿 (花栗鼠)
字符 'i' = 105
105 + 55 = 160
第3字节: 160 // 64 + 143 = 2 + 143 = 145 = 0x91
第4字节: 160 % 64 + 128 = 32 + 128 = 160 = 0xA0
→ F0 9F 91 A0 → 👠 (高跟鞋)
"Hi" → 🐿👠
为什么 +55?
这个偏移量让字节值 0-255 刚好映射到 Unicode 中一段连续的 emoji 区域(U+1F300 附近开始),确保每个输出都是合法的 emoji 字符。
和其他 Base 的本质区别
| | 其他Base编码 | Base100 |
| — | — | — |
| 目的 | 压缩/传输 | 纯娱乐 |
| 映射 | 多字节→少字符 | 1字节→1 emoji |
| 膨胀率 | 23-33% | 300% (1字节→4字节) |
| 效率 | 越高越好 | 完全不在乎 |
这是所有 Base 编码里膨胀率最高的,但也是最好玩的——Hello World 变成一串 emoji 🐿👜👣👣👦🐗👎👦👩👣👛,看起来就是在发表情。CTF 里偶尔出现,看到一串连续 emoji 就该想到 Base100。
🔻 比Base16更小的编码
| 编码 | 字符数 | 公式 | 效率 | 膨胀率 | 应用场景 |
| — | — | — | — | — | — |
| Base2 | 2 | 2^1 | 12.5% | 800% | 二进制展示、教学 |
| Base3 | 3 | – | 20.9% | 478% | 三进制计算 |
| Base4 | 4 | 2^2 | 25% | 400% | DNA序列 (ACGT) |
| Base5 | 5 | – | 29.1% | 344% | 理论研究 |
| Base8 | 8 | 2^3 | 37.5% | 267% | Unix权限 (chmod) |
| Base10 | 10 | – | ~42% | ~240% | 电话号码、身份证 |
Base10 (Decimal)
基本信息
- • 字符数: 10
- • 字符集:
0-9 - • 效率: ~42%
应用场景
人类最熟悉的进制!
常见用途:
- 电话号码
- 银行账号
- 身份证号
- 订单号
- 验证码
示例
订单号: 20240207153045
验证码: 749283
🔺 比Base100更大的编码
Base122 (UTF-8优化)
基本信息
- • 字符数: 122
- • 字符集: 122个UTF-8安全字符
- • 效率: ~87%
编码原理
UTF-8 单字节范围是 0x00-0x7F(共128个值)。去掉6个不安全的字符:
0x00 (NULL) — 字符串终止符,C语言会截断
0x08 (退格) — 控制字符
0x09 (Tab) — 可能被HTML/编辑器吃掉
0x0A (换行) — 会被当作行结束
0x0D (回车) — 同上
0x5C (\) — 转义字符,各种语言都特殊处理
剩下 128 – 6 = 122 个安全字符,每个只占 1 字节。
应用场景
- • 现代网络传输
- • UTF-8环境优化
为什么叫”UTF-8 优化”
关键对比:
Base85 编码 "Hello World":
每个输出字符是 ASCII 可打印字符 → 每字符 1 字节
效率: 6.4 bit/字符 → 膨胀 25%
Base91 编码:
同上 → 每字符 1 字节
效率: 6.5 bit/字符 → 膨胀 23%
Base100 编码:
每个输出是 emoji → 每字符 4 字节 UTF-8
效率: 2 bit/字节 → 膨胀 300%
Base122 编码:
每个输出字符在 UTF-8 中仍然只占 1 字节
但可用字符数从91个提升到122个
效率: log₂(122) ≈ 6.93 bit/字符 → 膨胀仅 ~14%
Base122 的意思是:在保证每个输出字符 UTF-8 单字节(不会被任何文本处理环节破坏)的前提下,把可用字符数推到极限。 它利用了那些不可打印但在 UTF-8 传输中完全安全的字节值(比如 0x01-0x07 这些控制字符虽然不可打印,但在 HTTP body、JSON 字符串、HTML <script> 标签内传输时不会被篡改)。
所以”UTF-8 优化”的含义是:针对 UTF-8 环境最大化单字节利用率,不像 Base85/91 只敢用可打印字符那么保守,也不像 Base100 用 emoji 那么浪费,而是精确地选出所有在 UTF-8 文本传输中安全的单字节字符。
它最初的设计场景是在 HTML 的 <script> 标签内嵌入二进制数据(如 WebAssembly),用 Base122 比 Base64 小很多,浏览器解析更快。
Base128 (已介绍)
见前文”第一类:2的幂次编码”部分
Base256 (已介绍)
见前文”第一类:2的幂次编码”部分
🤔 理论上还有更大的吗?
推荐阅读:What are Base96, Base128, Base256, and Base512? Do They Really Exist?[8]
实用最大值: Base122
✅ 使用UTF-8安全字符
✅ 效率87%(接近Base128)
✅ 可跨平台传输
✅ 兼容性好
📊 编码效率对比
效率公式
编码效率 = 原始数据大小 / 编码后数据大小
膨胀率 = 编码后数据大小 / 原始数据大小
完整对比表
| 编码 | 字符数 | 类型 | 效率 | 膨胀率 | 1KB编码后 | 分组方式 |
| — | — | — | — | — | — | — |
| Base2 | 2 | 2^1 | 12.5% | 800% | 8.0 KB | 1 bit/char |
| Base4 | 4 | 2^2 | 25% | 400% | 4.0 KB | 2 bit/char |
| Base8 | 8 | 2^3 | 37.5% | 267% | 2.67 KB | 3 bit/char |
| Base10 | 10 | 特殊 | ~42% | ~240% | ~2.4 KB | 数学除法 |
| Base16 | 16 | 2^4 | 50% | 200% | 2.0 KB | 4 bit/char |
| Base32 | 32 | 2^5 | 62.5% | 160% | 1.6 KB | 5 bit/char |
| Base45 | 45 | 优化 | ~68% | ~147% | ~1.47 KB | 数学除法 |
| Base58 | 58 | 优化 | ~73% | ~137% | ~1.37 KB | 数学除法 |
| Base62 | 62 | 优化 | ~74% | ~135% | ~1.35 KB | 数学除法 |
| Base64 | 64 | 2^6 | 75% | 133% | 1.33 KB | 6 bit/char |
| Base85 | 85 | 压缩 | 80% | 125% | 1.25 KB | 32 bit→5 char |
| Base91 | 91 | 压缩 | ~82% | ~122% | ~1.22 KB | 变长 |
| Base92 | 92 | 压缩 | ~82% | ~122% | ~1.22 KB | 变长 |
| Base100 | 100 | 趣味 | 变化 | 变化 | 变化 | 变化 |
| Base122 | 122 | 压缩 | ~87% | ~115% | ~1.15 KB | 数学除法 |
| Base128 | 128 | 2^7 | 87.5% | 114% | 1.14 KB | 7 bit/char |
| Base256 | 256 | 2^8 | 100% | 100% | 1.0 KB | 8 bit/char |
🎯 选择指南
场景推荐表
| 使用场景 | 推荐编码 | 原因 |
| — | — | — |
| 邮件附件 | Base64 | RFC标准,广泛支持 |
| Data URL | Base64 | 浏览器原生支持 |
| JWT令牌 | Base64 URL-safe | 避免URL冲突 |
| 双因素认证 | Base32 | 手工输入友好 |
| 区块链地址 | Base58 | 避免字符混淆 |
| 短链接 | Base62 | URL安全无特殊字符 |
| 二维码 | Base45 | QR码存储优化 |
| PDF文件 | Base85 | Adobe标准 |
| 调试输出 | Base16 | 直观易读 |
| 哈希显示 | Base16 | 行业惯例 |
| 趣味编码 | Base100 | 社交媒体 |
| Unix权限 | Base8 | chmod命令 |
| DNA序列 | Base4 | 生物ACGT表示 |
性能对比
编码速度 (从快到慢)
1. Base16 (最快 - 简单bit位移)
2. Base64 (很快 - bit分组)
3. Base32 (快 - bit分组)
4. Base85 (中等 - 需要除法)
5. Base58 (较慢 - 大整数除法)
6. Base91 (慢 - 复杂算法)
兼容性 (从好到差)
1. Base16 (最佳 - 所有系统支持)
2. Base64 (极佳 - 标准库支持)
3. Base32 (良好 - 标准库支持)
4. Base85 (一般 - 部分系统支持)
5. Base58 (一般 - 需要第三方库)
6. Base45 (较差 - 新标准)
7. Base91+ (差 - 需要专门实现)
💡 核心要点总结
1. 为什么Base58/Base45不是2^n?
Base58设计理念:
目标 ≠ 数学完美
目标 = 解决实际问题(避免混淆)
方法: Base64 (64字符) - 易混淆字符 (6个) = 58
Base45设计理念:
目标 ≠ 通用编码
目标 = QR码存储优化
方法: 使用QR码字母数字模式支持的45个字符
2. 2^n编码 vs 非2^n编码
2^n编码 (Base2/4/8/16/32/64/128/256)
优点:
✅ 可以直接bit操作(位移、掩码)
✅ 编码解码速度快
✅ 实现简单
✅ CPU友好
缺点:
❌ 字符集不灵活
❌ 可能包含特殊字符
非2^n编码 (Base10/45/58/62/85/91等)
优点:
✅ 字符集可定制
✅ 可优化特定场景
✅ 避免问题字符
缺点:
❌ 需要除法运算
❌ 编码解码较慢
❌ 实现复杂
3. 编码效率排行
效率最低: Base2 (12.5%) - 膨胀8倍
教学演示: Base16 (50%) - 膨胀2倍
通用平衡: Base64 (75%) - 膨胀1.33倍 ⭐
高效压缩: Base85 (80%) - 膨胀1.25倍
极限压缩: Base122 (87%) - 膨胀1.15倍
理论极限: Base256 (100%) - 无膨胀
4. 最常用的5种编码
🥇 Base64 - 通用标准,70%的场景
🥈 Base16 - 调试哈希,20%的场景
🥉 Base32 - 双因素认证
🏅 Base58 - 区块链专用
🏅 Base85 - PDF/Git专用
5. 填充字符的意义
为什么Base64需要填充'='?
3字节 = 24 bit → 4个Base64字符 (完美)
2字节 = 16 bit → 3个Base64字符 + 需要填充
1字节 = 8 bit → 2个Base64字符 + 需要填充
'=' 告诉解码器: "后面的bit应该忽略"
示例:
"A" → "QQ==" (1字节,填充2个=)
"AB" → "QUI=" (2字节,填充1个=)
"ABC" → "QUJD" (3字节,无需填充)
6. 特殊编码的独特优势
Base58:
去除: 0, O, I, l, +, /
优势: 人类手写友好,OCR准确
应用: 比特币地址
Base45:
字符: QR码字母数字模式的45个字符
优势: 在QR码中节省30%空间
应用: COVID健康证书
Base85:
压缩: 4字节→5字符 (vs Base64的4字节→5.33字符)
优势: 比Base64节省25%空间
应用: PDF文件
特殊: 全零→'z'压缩
7. 理论边界
最小有意义编码: Base2 (二进制)
最大实用编码: Base122 (UTF-8安全)
理论极限: Base256 (原始字节)
超过Base256?
→ 技术可行(Base65536 Unicode)
→ 实际无用(兼容性/可读性差)
📚 参考资源和🎓 学习建议
标准文档
- • Base64: RFC 4648[9]
- • Base32: RFC 4648
- • Base16: RFC 4648
- • Base45: RFC 9285[10] (2022年发布)
- • Base58: Bitcoin Wiki
- • Base85: RFC 1924[11], Adobe PostScript
初学者路径
- 1. 先理解Base16 (最简单直观)
- 2. 再学Base64 (最常用)
- 3. 了解Base32 (2FA密钥)
- 4. 探索Base58 (理解非2^n编码)
实践项目
项目1: 实现Base64编码器
- 理解bit分组
- 掌握填充规则
项目2: 实现Base58编码器
- 理解大整数除法
- 对比与Base64的区别
项目3: QR码生成器
- 使用Base45优化存储
- 对比不同编码的QR码大小
常见误区
❌ 误区1: "Base64是加密"
✅ 正确: Base64是编码,不是加密,所以一般在CTF分类中纯Base的题目是Misc而不是Crypto
任何人都可以解码
❌ 误区2: "更大的Base就更好"
✅ 正确: 取决于场景
Base64通用性 > Base85压缩率
❌ 误区3: "Base58去掉了8个字符"
✅ 正确: 去掉了6个字符(0,O,I,l,+,/)
58 = 64 - 6
❌ 误区4: "Base编码能压缩数据"
✅ 正确: Base编码会膨胀数据
压缩需要用gzip/brotli等
🏆 总结
Base编码家族是数据表示的基础工具,理解它们的原理和应用场景,能帮助你:
- 1. ✅ 选择合适的编码方式
- 2. ✅ 理解数据传输机制
- 3. ✅ 优化存储和传输效率
- 4. ✅ 解决实际工程问题
记住核心原则:没有最好的编码,只有最适合的编码! 🎯
Info
写这篇文章主要是因为做到一道CTF题目做破防了,所以我来好好的打好基础[12]。
Base家族在现代免杀木马中的应用
各种 Base 编码在恶意软件的免杀(AV evasion)中被广泛使用,与普通文件使用Base的目的是压缩不同的是,免杀木马使用Base的目的主要是混淆以隐藏真实的反连地址或恶意代码。
为什么用编码做免杀
杀毒软件的静态检测本质是模式匹配——扫描文件中的特征字节序列(签名)。编码后特征消失了:
原始 shellcode (会被杀软识别):
\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00...
Base64 后 (签名消失):
/EiD5PDowAAAA...
Base85 后 (更短,更不像恶意代码):
@:X`hBk;1n...
常见编码混淆手法
单层编码最基础,现在基本没用了,杀软早就能自动解码检测:
# 最原始的方式, 现在秒杀
import base64
exec(base64.b64decode("cHJpbnQoJ2hlbGxvJyk="))
多层嵌套稍好一点:
payload → Base85 → XOR → Base64 → 反转字符串 → Base32
自定义字母表是 CTF 里常见的:
# 用自定义字母表的 Base64, 杀软的自动解码器认不出来
CUSTOM = "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210+/"
实际免杀中编码的角色
不过要说清楚,现代免杀中单纯靠编码基本没用了。编码只是多层混淆中的一环:
完整免杀链路:
shellcode
→ 编码/加密 (Base85, AES, XOR, RC4...) ← 对抗静态签名
→ 加载器 (反射DLL注入, syscall直调...) ← 对抗行为检测
→ 反沙箱 (检测虚拟机, 延迟执行...) ← 对抗动态分析
→ 内存规避 (加密睡眠, unhook ntdll...) ← 对抗内存扫描
编码只能过最基础的静态扫描,稍微像样一点的 EDR 都会做运行时行为分析,光靠编码混淆远远不够。
🔔 想要获取更多网络安全与编程技术干货?
关注 泷羽Sec-静安 公众号,与你一起探索前沿技术,分享实用的学习资源与工具。我们专注于深入分析,拒绝浮躁,只做最实用的技术分享!💻
马上加入我们,共同成长!🌟
👉 长按或扫描二维码关注公众号
直接回复文章中的关键词,获取更多技术资料与书单推荐!📚
引用链接
[1] What is base64 Encoding and Why is it Necessary?: https://www.freecodecamp.org/news/what-is-base64-encoding/
[2] what-is-base64: https://base64.guru/learn/what-is-base64
[3] Base64: https://developer.mozilla.org/en-US/docs/Glossary/Base64
[4] 深入理解短链服务:原理、设计与实现全解析: https://zhuanlan.zhihu.com/p/1912646027770585297
[5] bit.ly: https://bitly.com/pages/home
[6] TinyURL: https://tinyurl.com/
[7] 短网址: https://www.urlc.cn/
[8] What are Base96, Base128, Base256, and Base512? Do They Really Exist?: https://b64encode.com/blog/base-96-base128-base256-and-base512/
[9] RFC 4648: https://www.rfc-editor.org/info/rfc4648
[10] RFC 9285: https://www.rfc-editor.org/info/rfc9285
[11] RFC 1924: https://www.rfc-editor.org/info/rfc1924
[12] 打好基础: https://hgame.vidar.club/games/9/challenges?challenge=194
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:泷羽Sec-静安 泷羽Sec静安
泷羽Sec静安《Base编码家族完整解析》