Python str.translate 自定义 Base64:字符替换编解码原理

在逆向接口参数时,经常遇到这类代码:

b64 = base64.b64encode(data.encode("utf-8")).decode("ascii")
return b64.translate(TRANS)

b64.translate(TRANS) 是 Python 字符串的内置 translate() 方法,不是某个库的 API。

translate() 做了什么

先 Base64 编码,再按照 TRANS 映射表替换字符。

translate() 一次可以替换多个字符,比链式 replace() 更高效:

TRANS = str.maketrans({
    "+": "-",
    "/": "_",
})

"a+b/c=".translate(TRANS)  # → "a-b_c="

TRANS 的常见形式

替换少量字符

TRANS = str.maketrans({
    "+": "-",
    "/": "_",
})

这是标准的 URL Safe Base64 变体(RFC 4648),把 +/ 换成 -_,避免 URL 编码问题。

整体字符映射(自定义 Base64)

src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
dst = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm0123456789-_"

TRANS = str.maketrans(src, dst)

这是在对整个 Base64 字符集做轮换映射,常用于接口参数混淆。

解码:把映射反过来

编码是 src → dst,解码就是 dst → src

REVERSE_TRANS = str.maketrans(dst, src)

完整编解码实现

import base64

src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
dst = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm0123456789-_"

TRANS = str.maketrans(src, dst)
REVERSE_TRANS = str.maketrans(dst, src)


def encode(data: str) -> str:
    b64 = base64.b64encode(data.encode()).decode()
    return b64.translate(TRANS)


def decode(data: str) -> str:
    raw = data.translate(REVERSE_TRANS)
    return base64.b64decode(raw).decode()


x = encode("hello world")
print(x)           # 输出混淆后的字符串
print(decode(x))   # → hello world

简单的 URL Safe Base64 变体

如果 TRANS 只替换 +/=,编解码更简单:

import base64

def url_safe_encode(data: str) -> str:
    b64 = base64.b64encode(data.encode()).decode()
    return b64.translate(str.maketrans({"+": "-", "/": "_", "=": ""}))


def url_safe_decode(data: str) -> str:
    # 补齐 padding
    padded = data + "=" * (-len(data) % 4)
    raw = padded.translate(str.maketrans({"-": "+", "_": "/"}))
    return base64.b64decode(raw).decode()

逆向时如何确认 TRANS 内容

遇到 b64.translate(TRANS) 时,找到 TRANS 的定义:

  • 如果是 str.maketrans(src, dst):把 dst 作为新的 srcsrc 作为新的 dst,即可反向还原
  • 如果是 str.maketrans({...}):把字典的键值互换即可

很多登录接口、签名参数都会用这种方式,目的是避免 +/= 在 URL 中被转义,或者简单混淆防止直接调用。