-
-
[原创]第七题「戌时·暗能潜流」解析
-
发表于: 2026-8-21 14:22 16
-
(FLAG 密文实际是一整行,共 144 个十六进制字符,此处为排版折行。)
做密码分析题,第一件事不是看数据,是把自然语言描述翻译成可利用的数学约束。逐条拆:
关键推论:
"模16循环偏移 + 固定位置重排"意味着:密文的每一个十六进制位,都等于某一个明文半字节加上一个固定常数。
形式化:存在置换 π 和常量数组 k,使得 C[i] = (P[π(i)] + k[i]) mod 16。
这个模型极强——它把破解降级成了"求一个置换 + 一组常量",可以纯靠列比对解出来,不需要爆破。
比值不固定 → 存在填充(padding)。
反过来推:如果"每个字符固定产出 4 个十六进制位",那么
即:明文按 3 字符对齐填充,每 3 字符产出 12 个十六进制位。这是唯一自洽的解释。
FLAG 密文 144 位 ÷ 12 = 12 块,对应填充后 36 个字符。
因为算法是确定性的,如果分块独立(类似 ECB),那么相同的 3 字符块在任何位置都会产生相同的 12 位密文。于是去 FLAG 里搜已知密文的 12 位块:
这一条命中同时证明了三件事:
第 3 点尤其宝贵:它直接排除了 CBC 式链接和"随位置递增的偏移",让每块可以单独求解。
把 FLAG 切成 12 块:
块 11 长得和别人完全不一样(2233、2235 这种规整的低值),先记下,后面处理。
把 4 组已知明文的第一块(都是完整的 3 字符块)按位摊开:
pos 1 / 4 / 9 恒为 4;pos 6 / 7 / 11 恒为 5。
再拿 FLAG 的 11 个正常块交叉验证 —— 全部符合。6 个固定位,6 个数据位。
数据位是 {0, 2, 3, 5, 8, 10},正好 6 个,而 3 个 ASCII 字符 = 6 个半字节。一一对应,信息量刚好守恒,验证了"膨胀率 = 每半字节 1 个十六进制位 + 1 个标记位"的模型。
这一步的关键推理:为什么这 6 个位是"结构性常量"而不是巧合?
因为如果它们承载明文数据,4 组差异极大的明文(TLU / Hel / 202 / abc,高半字节分别是 5,4,5 / 4,6,6 / 3,3,3 / 6,6,6)不可能全都撞成同一个值。
而 4 出现 3 次、5 出现 3 次的 3:3 结构,强烈暗示它们是"高半字节标记"和"低半字节标记"——即"字节编码"这一步的产物。
可打印 ASCII 字符(0x20–0x7E)的高半字节只能是 2..7,只有 6 种取值;而低半字节 0..F 全都可能。
所以:承载高半字节的密文位,其取值必然被压缩在一个宽度 ≤ 6 的连续窗口内(模 16 意义下)。
统计 FLAG 的 11 个正常块,每个数据位的取值集合:
这是一个非常好用的通用技巧:当明文是可打印 ASCII 时,高半字节的熵远低于低半字节。只需统计每一列的取值分布,就能把"高位列"和"低位列"分开,完全不需要已知明文。
结论:pos2 / pos3 / pos10 承载 3 个高半字节;pos0 / pos5 / pos8 承载 3 个低半字节。
窗口都落在 8..C,而高半字节值域是 2..7,差值 = +5。用已知明文核对:
卡住了。 两组对、两组错。
这里我先走了一段弯路,值得完整记下来,因为它是这类题最典型的思维陷阱。
当时的(错误)推理链:
这个假设是怎么被证伪的:
Hello 和 abcd! 长度都是 5,扰动必然相同。可实测:
同一长度却要求两个不同的扰动量 → 假设直接矛盾,证伪。
同样的方法把 pos0、pos8 也试了一遍,全都在"同长度双样本"上自相矛盾。
教训(很重要):
当一个"合理的解释"能覆盖部分样本时,人会本能地给它打补丁(加一个自由参数)来解释剩下的。
正确做法是找一组能同时约束该参数的样本去证伪它。
这里 Hello / abcd! 同为长度 5,就是天然的"对照组"。只要有两个同长度样本,任何'只与长度有关'的自由参数都会被立刻锁死。
另一个反证同样致命:如果 pos0 = hi(c0) + 常量,那 FLAG 11 个块的 pos0 值必须落进 6 个格子里;但实测 pos0 有 11 个互不相同的值——鸽笼原理直接排除。这也提示 pos0 根本不是高半字节列。
排除了扰动之后,矛盾就必须从结构上解释:既然 pos2 / pos3 / pos10 是三个高半字节,而 pos3 / pos10 都能对上、只有 pos2 对不上,那问题只可能出在**"哪个字符是 c0"** 上——也就是顺序。
回头看那些"异常"的第 2 块:
规整的低值 2233/2235 出现在块的开头,而"看起来像真实数据"的部分在块的末尾。如果填充字符是加在明文尾部的,填充产物本该出现在块尾。它出现在块首 → 顺序被翻转了。
设 R = S[::-1](明文整体反转),再按 3 字符分块:
重新核对 pos2 = hi(c0) + 5:
4/4 全中! 顺带 pos3、pos10 在新顺序下依然成立:
之前"对了两组"是因为 TLU→ULT 和 202→620 恰好高半字节相同或对称(T/U 同为 5,2/0/6 同为 3),属于假阳性巧合。
教训:202、TLU 这种字符高位高度重复的样本,会掩盖顺序错误。
做已知明文分析时,优先信任字符差异大的样本(这里是 Hello / abcd!),它们的信息量更高、更容易暴露结构错误。
顺序修正后,把 pos0 / pos5 / pos8 与反转块的 3 个低半字节对齐求差:
12/12 全部等于 4,无一例外,且与输入长度完全无关。
至此主体变换彻底还原:高半字节 +5,低半字节 +4,全都是模 16。没有任何长度相关的扰动。
正常块搞定后,只剩"不足 3 字符"的尾块。它就是题面说的固定摘要扰动——形态只由"剩余字符个数"(即输入长度 mod 3)决定,与内容无关,完美对应提示"摘要扰动过程只与输入长度有关"。
样本(反转后剩下的 2 个字符):
逐段对照(a = 第 1 个剩余字符,b = 第 2 个):
注意第 2 个字符的 hi / lo 顺序是反的(先 hi 后 lo),与正常块中 c2 的排布风格一致——这正是"固定位置重排"的延续。
对 FLAG 尾块 22332235A4B3 应用此规则:
FLAG 的第一个字符是 f —— 因为反转后的最后一块,对应的正是原文的开头。符合 flag{...} 预期。
TLU 长度 3,正好整除,不产生尾块(密文只有 12 位)。所以填充只在需要时添加。
记 hi(c) = c >> 4,lo(c) = c & 0xF,全部运算模 16:
用一句话记:
c0 的低位在最前,c0 的高位紧随;c2 的高低位分居 3、5 号位;c1 的高低位被挤到 8、10 号位;4 和 5 各三个当填充标记。
现在回头把还原出的规则,映射回题面声称的 5 个步骤,就能看清设计者的意图。
每个字符被拆成 2 个半字节,各自扩展成 1 个"带标记的字节":
这就解释了为什么密文里恰好有 3 个 4 和 3 个 5:3 个字符 × (1 低 + 1 高)。膨胀率 = 1 字符 → 2 字节 → 4 个十六进制字符,与观测完全一致。
这就是"模 16 循环偏移"的全部内容——两个常量,4 和 5,与位置、长度、内容都无关。
值得注意的是:偏移量和标记值相同(低位标记 4 / 偏移 4,高位标记 5 / 偏移 5)。所以整个编码可以更优雅地写成:
这是它伪装成"哈希/密文"的关键:偏移让 hi 从 2..7 搬到 7..C,于是密文里到处是 A、B、C 这类高位字符,看起来"很随机",实际上熵一点没增加。
编码后,一个块的原始 12 位序列(按字符顺序、每字符先低后高)是:
观测到的输出是:
于是置换 P(输出位置 → 取自输入索引)为:
验证:{1,0,3,11,4,9,2,6,5,8,7,10} 恰好是 0..11 的一个排列 ✅ —— 模型自洽。
说明:因为 3 个 4 之间、3 个 5 之间可以互换,这个置换的具体写法不唯一(有 3!×3! = 36 种等价写法),但数据位的映射是唯一确定的,不影响解密。
再叠加 Step 1 的整串反转——这是"重排"的第二层,也是本题最大的迷惑点:它让密文块顺序与明文块顺序相反,破坏了人眼最依赖的"从左到右"直觉。
尾块中的 2233 / 2235 / 53 / 3 这些魔数,作用是:
它只与 len(S) mod 3 有关,与明文内容无关——完全对应题面提示。所谓"摘要"其实一个哈希都没有,就是个长度指纹。
核心弱点:C[i] = (P[π(i)] + k[i]) mod 16 —— 这是一个逐位仿射映射,没有任何非线性、没有轮函数、没有密钥调度。整个密码可以用一张 12 行的查表完全描述。
假设你手上只有密文,下面是从零开始的完整操作流程。
不是的话,说明分块假设错了,回头重新推膨胀率。
FLAG:144 % 12 = 0 ✅ → 12 块。
看最后一块:
不会误判正常块:正常块 pos1 恒为 4,而两种尾块前缀的第 2 位都是 2。
FLAG 最后一块 22332235A4B3 → 22332235 开头 → 尾块,1 个字符。
所以:前 11 块 × 3 + 1 = 34 个字符。
对每个完整块检查:
任何一块不满足 → 说明块边界错位或密文抄错,立刻停下排查。这是免费的纠错机制,一定要用。
记忆口诀:
含 1 个字符(22332235....):
含 2 个字符(2235........):
⚠️ 注意 b 的 hi/lo 位置顺序与 a 相反,这是最容易写错的地方。
⚠️ 不要忘记最后这一步反转 —— 这是本题最大的坑。
用还原的算法把 S 重新加密,比对是否与原密文逐位相同。不做这一步,永远不能确定答案对不对。
本章是自包含的。 前面十二章讲的是"规律是怎么推出来的",本章只讲"知道规律后怎么算"。
只看这一章,不回头翻任何其他章节,也能独立完成加密和解密的全部手工计算。所有需要用到的规则、对照表、字符编码都在 13.0 里给全。
一句话记住拆分方法:把字符写成两位十六进制,左边那位是 hi,右边那位是 lo。
全部运算在模 16 下进行:加法超过 F 就减 16;减法出现负数就加 16。
加密方向 —— 低半字节 +4:
加粗的 4 列是回绕发生的地方:C+4=0x10,超出一位,只保留 0。
加密方向 —— 高半字节 +5:
可打印 ASCII 的 hi 只可能是 2..7,所以加 5 后必落在 7..C,永远不会回绕。
反过来说:解密时如果某个"高位列"的值不在 7..C 内,说明你取错位置了。
解密方向 —— 低半字节 −4:
加粗的 4 列是必须 +16 回绕的情况。例:1 − 4 = −3,−3 + 16 = D。
⚠️ 直接写成 3 是本题最高频的错误,会让整个 flag 全错。
解密方向 —— 高半字节 −5:
设一块的三个字符为 c0, c1, c2(按 R 中的顺序,即已经反转过的顺序):
背下这两条就够了:
注意 c1 和 c2 的位置是交叉错开的(c2 在前、c1 在后),这是"固定位置重排"造成的,不是笔误。
尾块数据位速查:
⚠️ 两个坑:
① r=2 时,a 是"先 lo 后 hi",b 是"先 hi 后 lo",顺序相反,写反了必错。
② r=1 的尾块虽然名义上是 2233 + 2235 两段拼接,但实际是以 2233 开头的,判别时不能只写"以 2235 开头"。
len(R) = 5
按位号 0→11 顺序读出:
a = 'e' = 0x65 → hi=6, lo=5b = 'H' = 0x48 → hi=4, lo=8
与题面给出的 Hello -> 34BB405504B5223594B94C53 逐位一致 ✅
c0='6', c1='2', c2='0';剩余字符 c='2'。
c = '2' = 0x32 → hi=3, lo=2
与题面 2026 -> A48844556485223322356483 一致 ✅
与题面 TLU -> 94AA48550495 一致 ✅ 密文只有 12 位,印证了 r=0 时确实不追加尾块。
6/6 通过 → 这是一个结构正确的完整块,可以继续。
(若有任何一项不符,说明块边界切错了或密文抄错了,应立即停下排查,而不是硬算下去。)
因为整串明文是反转态,这 3 个字符对应原文最末尾 3 个字符的倒序 → 原文以 r!} 结尾。对于一个 flag{...} 格式的 flag,结尾是 },完全合理 ✅
本例最大的坑:d[0] − 4 = 1 − 4。
很多人算成 −3 后直接取绝对值当成 3,得到 0x73 = 's',于是 flag 结尾变成 s!r,整题全错。
凡是减法结果为负,一律 +16。 查 13.0 表 (3) 的"解密方向 −4"那一行也可以直接得到 1 → D。
前 8 位是 22332235 → 查 13.0 表 (5):这是 r=1 的尾块,只含 1 个真实字符。
为什么不会和完整块搞混? 完整块的位 1 恒为 4,而这里位 1 是 2,天然互斥。
反转态的最后一个字符 = 原文的第一个字符 → flag 以 f 开头 ✅
前 4 位是 2235(且不是 22332235)→ r=2 的尾块,含 2 个真实字符。
这正是 13.1 中 Hello 反转后 R="olleH" 的最后两个字符 ✅ 加解密闭环。
FLAG 密文(144 位,实际为一整行):
看最后一块 22332235A4B3:以 22332235 开头 → r=1 的尾块,含 1 个字符。
前 11 块位 1 全是 4,均为完整块。
下表把每块的三次"取位—减法—合成"全部展开。减法列中标 +16 的即发生了回绕。
全表共出现 6 次负数回绕(块 0、2、5、6、8、10 各一次)。这 6 处是全题最容易翻车的地方,逐一核对过再往下走。
把还原出的明文重新加密一遍,与原密文逐位比对:
与题面 FLAG 密文 144 位逐位相同 ✅
语义自检:flag 内容是 leetspeak —— T1u + 2026 + Kc7f(KCTF,t→7)+ Crypt0(o→0)+ M4ster(a→4)。各段均为可读的英文单词/年份变形,语义自洽,进一步佐证结果正确。
保存为 hexmaze.py:
运行输出:
⚠️ 实现踩坑:尾块判据不能只写 startswith("2235")。
余 1 的尾块是 2233 + 2235 拼接,实际以 2233 开头(例如 2026 的尾块 223322356483),只判 2235 会漏掉它,导致该块被当成正常块送进 _dec_block,触发标记位断言失败。
正确判据要同时覆盖 22332235(余 1)和 2235(余 2)两种前缀。
反过来问:正常块会不会被误判成尾块?不会 —— 正常块的 pos1 恒为 4,而两种尾块前缀的第 2 位都是 2,天然互斥。这个判据是安全的。
题面给了"密钥: 121",但还原出的算法里没有任何一处用到它。
判据很硬:上面的实现在完全不引用 121 的前提下,已经能把 4 组已知样本 + FLAG 全部双向精确复现(144 位逐位相同)。如果密钥真的参与了运算,必然存在至少一个无法用固定常量解释的位——但一个都没有。
几种可能:
处理这类信息的正确姿势:先假设它无关,用数据说话;只有当模型出现无法用常量解释的残差时,才回头引入密钥变量。 本题残差为零,所以密钥无关的结论是充分的。
这道题的通用解题套路,可以复用到绝大多数"自制古典/位级密码"的已知明文分析:
len(密文) vs len(明文) 的比值决定了膨胀率和分组边界。比值不整齐就一定有填充,反推填充规则往往能直接定出块大小。
题面明说"无随机数/无 IV" → 相同明文片段必产生相同密文片段。拿已知密文块去目标密文里搜,命中即同时确认块长、块对齐、块间独立性三件事。本题 A48844556485 在 FLAG 偏移 84 处命中,一击定三事。
把所有块按位对齐成矩阵,逐列看取值集合。恒定列 = 结构性标记(送你免费的完整性校验);变化列 = 载荷。
可打印 ASCII 的高半字节只有 2..7 六种取值。统计每列的取值宽度:
这一步甚至不需要已知明文,纯唯密文就能做。
高位列窗口落在 8..C,明文值域 2..7,差 5 → 偏移就是 +5。不用爆破。
202、TLU 这种高半字节重复的样本容易产生假阳性(顺序错了也能对上)。Hello、abcd! 信息量大,是真正的试金石。
把还原的明文重新加密,逐位比对。不回验的答案不算答案。
最终答案
| 题面表述 | 技术含义 | 对分析的价值 |
|---|---|---|
| 固定算法 / 无随机数 / 无 IV / 无外部状态 | 确定性函数 C = E(P) |
相同明文片段必产生相同密文片段 → 可以做"片段比对" |
| 字节编码 | 明文字符先被拆/映射成某种中间表示 | 密文长度 ÷ 明文长度 会暴露膨胀率 |
| 十六进制位运算 | 操作粒度是 nibble(4 bit / 1 个十六进制字符),不是 byte | 分析单位应该是"十六进制位",不是"字节" |
| 模16循环偏移 | (x + k) mod 16 |
数据位与明文位之间是加法常量差关系 |
| 固定位置重排 | 一个固定置换 P |
明文位与密文位是一一对应的,只是位置乱了 |
| 固定摘要扰动 | 一个附加的、非主体的扰动步骤 | 大概率只影响"边角",不影响主体 |
| 摘要扰动只与输入长度有关 | 扰动 ≠ 明文内容的函数 | 这是最重要的提示:主体变换与长度无关 |
| 明文块 | pos0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
TLU |
9 | 4 | A | A | 4 | 8 | 5 | 5 | 0 | 4 | 9 | 5 |
Hel |
3 | 4 | B | B | 4 | 0 | 5 | 5 | 0 | 4 | B | 5 |
202 |
A | 4 | 8 | 8 | 4 | 4 | 5 | 5 | 6 | 4 | 8 | 5 |
abc |
5 | 4 | 7 | B | 4 | 7 | 5 | 5 | 8 | 4 | B | 5 |
| 数据位 | FLAG 11 块中的取值集合 | 不同值个数 | 窗口宽度 | 判定 |
|---|---|---|---|---|
| pos0 | 1,9,8,4,D,3,7,A,6,5,B |
11 | 散布全域 | 低半字节 |
| pos2 | 8,A,B,C |
4 | 5(8..C) | 高半字节 ✅ |
| pos3 | 8,9,A,B,C |
5 | 5(8..C) | 高半字节 ✅ |
| pos5 | 0,3,4,6,7,9,B,F |
8 | 散布全域 | 低半字节 |
| pos8 | 1,3,5,6,8,A,F |
7 | 散布全域 | 低半字节 |
| pos10 | 7,8,9,A,B,C |
6 | 6(7..C) | 高半字节 ✅ |
| 原文 | 反转 R | 第 0 块 |
|---|---|---|
TLU |
ULT |
ULT |
Hello |
olleH |
oll |
2026 |
6202 |
620 |
abcd! |
!dcba |
!dc |
| 块 | c0 | hi(c0) | +5 | 实测 pos2 | |
|---|---|---|---|---|---|
ULT |
U=0x55 |
5 | A | A | ✅ |
oll |
o=0x6F |
6 | B | B | ✅ |
620 |
6=0x36 |
3 | 8 | 8 | ✅ |
!dc |
!=0x21 |
2 | 7 | 7 | ✅ |
| 块 | hi(c1)+5 | 实测 pos10 | hi(c2)+5 | 实测 pos3 |
|---|---|---|---|---|
ULT |
hi(L)+5=9 |
9 ✅ | hi(T)+5=A |
A ✅ |
oll |
hi(l)+5=B |
B ✅ | hi(l)+5=B |
B ✅ |
620 |
hi(2)+5=8 |
8 ✅ | hi(0)+5=8 |
8 ✅ |
!dc |
hi(d)+5=B |
B ✅ | hi(c)+5=B |
B ✅ |
| 块 | lo(c0) | pos0 | 差 | lo(c1) | pos8 | 差 | lo(c2) | pos5 | 差 |
|---|---|---|---|---|---|---|---|---|---|
ULT |
5 | 9 | 4 | C | 0 | 4 | 4 | 8 | 4 |
oll |
F | 3 | 4 | C | 0 | 4 | C | 0 | 4 |
!dc |
1 | 5 | 4 | 4 | 8 | 4 | 3 | 7 | 4 |
620 |
6 | A | 4 | 2 | 6 | 4 | 0 | 4 | 4 |
| 段 | eH 实测 |
ba 实测 |
规律 |
|---|---|---|---|
| [0:4] | 2235 |
2235 |
固定头(余 2 的标志) |
| [4] | 9 | 6 | lo(a)+4:lo(e)=5→9 ✅ / lo(b)=2→6 ✅ |
| [5] | 4 | 4 | 固定标记 4 |
| [6] | B | B | hi(a)+5:hi(e)=6→B ✅ / hi(b)=6→B ✅ |
| [7] | 9 | B | hi(b)+5:hi(H)=4→9 ✅ / hi(a)=6→B ✅ |
| [8] | 4 | 4 | 固定标记 4 |
| [9] | C | 5 | lo(b)+4:lo(H)=8→C ✅ / lo(a)=1→5 ✅ |
| [10:12] | 53 |
53 |
固定尾 |
| 段 | 含义 |
|---|---|
[0:8] = 22332235 |
固定头(余 1 的标志,可理解为"两个填充位"的编码) |
| [8] | lo(c)+4:lo(2)=2→6 ✅ |
| [9] | 固定标记 4 |
| [10] | hi(c)+5:hi(2)=3→8 ✅ |
| [11] | 固定尾 3 |
| 密文位 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 内容 | lo(c0)+4 |
4 |
hi(c0)+5 |
hi(c2)+5 |
4 |
lo(c2)+4 |
5 |
5 |
lo(c1)+4 |
4 |
hi(c1)+5 |
5 |
| 余数 r | 尾块(12 位) |
|---|---|
| 0 | (无尾块) |
1,剩余字符 c |
2233 2235 + [lo(c)+4] 4 [hi(c)+5] 3 |
2,剩余字符 a,b |
2235 + [lo(a)+4] 4 [hi(a)+5] + [hi(b)+5] 4 [lo(b)+4] + 53 |
| 已知密文位 | 还原出 |
|---|---|
| pos2 − 5 | c0 的高半字节 |
| pos0 − 4 | c0 的低半字节 |
| pos10 − 5 | c1 的高半字节 |
| pos8 − 4 | c1 的低半字节 |
| pos3 − 5 | c2 的高半字节 |
| pos5 − 4 | c2 的低半字节 |
| pos1,4,9 | 恒为 4(校验用) |
| pos6,7,11 | 恒为 5(校验用) |
| 性质 | 实际情况 |
|---|---|
| 混淆(confusion) | 无。每个密文位只依赖 1 个明文半字节 |
| 扩散(diffusion) | 无。改 1 个明文字符只影响 4 个密文位 |
| 密钥参与 | 无(见第十五节) |
| 本质 | 单表代换 + 固定置换,等价于凯撒密码的 nibble 版 |
| 已知明文攻击 | 1 组样本即可完全破解(本题给 4 组是为了容错) |
| 唯密文攻击 | 也可行:靠 ASCII 高半字节的窄值域即可定位高位列并求出偏移 |
| 符号 | 含义 | 举例 |
|---|---|---|
c |
一个 ASCII 字符 | 'H' |
hi(c) |
该字符 ASCII 码的高半字节(十六进制第 1 位) | 'H'=0x48 → hi=4 |
lo(c) |
该字符 ASCII 码的低半字节(十六进制第 2 位) | 'H'=0x48 → lo=8 |
R |
明文整体反转后的字符串 | Hello → olleH |
blk / d[i] |
一个 12 位的密文块 / 它的第 i 位(i 从 0 数起) | blk="14CC46555475", d[2]='C' |
r |
len(R) mod 3,即最后剩几个字符不够凑一块 |
len("olleH")=5, r=2 |
| 字符 | 十六进制 | hi | lo | 字符 | 十六进制 | hi | lo | |
|---|---|---|---|---|---|---|---|---|
! |
0x21 | 2 | 1 | T |
0x54 | 5 | 4 | |
0 |
0x30 | 3 | 0 | U |
0x55 | 5 | 5 | |
1 |
0x31 | 3 | 1 | _ |
0x5F | 5 | F | |
2 |
0x32 | 3 | 2 | a |
0x61 | 6 | 1 | |
4 |
0x34 | 3 | 4 | b |
0x62 | 6 | 2 | |
6 |
0x36 | 3 | 6 | c |
0x63 | 6 | 3 | |
7 |
0x37 | 3 | 7 | d |
0x64 | 6 | 4 | |
C |
0x43 | 4 | 3 | e |
0x65 | 6 | 5 | |
H |
0x48 | 4 | 8 | f |
0x66 | 6 | 6 | |
K |
0x4B | 4 | B | g |
0x67 | 6 | 7 | |
L |
0x4C | 4 | C | l |
0x6C | 6 | C | |
M |
0x4D | 4 | D | o |
0x6F | 6 | F | |
p |
0x70 | 7 | 0 | |||||
{ |
0x7B | 7 | B | r |
0x72 | 7 | 2 | |
} |
0x7D | 7 | D | s |
0x73 | 7 | 3 | |
t |
0x74 | 7 | 4 | |||||
u |
0x75 | 7 | 5 | |||||
y |
0x79 | 7 | 9 |
| 原值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| +4 后 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | 0 | 1 | 2 | 3 |
| 原值 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|
| +5 后 | 7 | 8 | 9 | A | B | C |
| 密文位 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| −4 后 | C | D | E | F | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B |
| 密文位 | 7 | 8 | 9 | A | B | C |
|---|---|---|---|---|---|---|
| −5 后 | 2 | 3 | 4 | 5 | 6 | 7 |
| 情况 | 尾块 12 位构成 | 前缀特征(解密时靠它识别) |
|---|---|---|
r=0 |
不产生尾块 | 密文最后一块的位 1 是 4 |
r=1,剩 c |
2 2 3 3 2 2 3 5 · lo(c)+4 · 4 · hi(c)+5 · 3 |
以 22332235 开头 |
r=2,剩 a b |
2 2 3 5 · lo(a)+4 · 4 · hi(a)+5 · hi(b)+5 · 4 · lo(b)+4 · 5 3 |
以 2235 开头 |
| 情况 | 字符 | hi 在第几位(减 5) | lo 在第几位(减 4) |
|---|---|---|---|
r=1 |
c |
10 | 8 |
r=2 |
a(第 1 个) |
6 | 4 |
r=2 |
b(第 2 个) |
7 | 9 |
| 变量 | 字符 | 十六进制 | hi | lo |
|---|---|---|---|---|
c0 |
o |
0x6F | 6 | F |
c1 |
l |
0x6C | 6 | C |
c2 |
l |
0x6C | 6 | C |
| 位号 | 模板内容 | 代入 | 加法过程 | 结果 |
|---|---|---|---|---|
| 0 | lo(c0)+4 |
F+4 |
15+4=19,19−16=3 ← 回绕 |
3 |
| 1 | 固定标记 | — | — | 4 |
| 2 | hi(c0)+5 |
6+5 |
=11 |
B |
| 3 | hi(c2)+5 |
6+5 |
=11 |
B |
| 4 | 固定标记 | — | — | 4 |
| 5 | lo(c2)+4 |
C+4 |
12+4=16,16−16=0 ← 回绕 |
0 |
| 6 | 固定标记 | — | — | 5 |
| 7 | 固定标记 | — | — | 5 |
| 8 | lo(c1)+4 |
C+4 |
12+4=16,16−16=0 ← 回绕 |
0 |
| 9 | 固定标记 | — | — | 4 |
| 10 | hi(c1)+5 |
6+5 |
=11 |
B |
| 11 | 固定标记 | — | — | 5 |
| 位号 | 模板内容 | 代入 | 结果 |
|---|---|---|---|
| 0–3 | 固定头 | — | 2 2 3 5 |
| 4 | lo(a)+4 |
5+4=9 |
9 |
| 5 | 固定标记 | — | 4 |
| 6 | hi(a)+5 |
6+5=11 |
B |
| 7 | hi(b)+5 |
4+5=9 |
9 |
| 8 | 固定标记 | — | 4 |
| 9 | lo(b)+4 |
8+4=12 |
C |
| 10–11 | 固定尾 | — | 5 3 |
| 变量 | 字符 | 十六进制 | hi | lo |
|---|---|---|---|---|
c0 |
6 |
0x36 | 3 | 6 |
c1 |
2 |
0x32 | 3 | 2 |
c2 |
0 |
0x30 | 3 | 0 |
| 位号 | 模板 | 代入 | 结果 |
|---|---|---|---|
| 0 | lo(c0)+4 |
6+4=10 |
A |
| 1 | 标记 | — | 4 |
| 2 | hi(c0)+5 |
3+5=8 |
8 |
| 3 | hi(c2)+5 |
3+5=8 |
8 |
| 4 | 标记 | — | 4 |
| 5 | lo(c2)+4 |
0+4=4 |
4 |
| 6 | 标记 | — | 5 |
| 7 | 标记 | — | 5 |
| 8 | lo(c1)+4 |
2+4=6 |
6 |
| 9 | 标记 | — | 4 |
| 10 | hi(c1)+5 |
3+5=8 |
8 |
| 11 | 标记 | — | 5 |
| 位号 | 模板 | 代入 | 结果 |
|---|---|---|---|
| 0–7 | 固定头 | — | 2 2 3 3 2 2 3 5 |
| 8 | lo(c)+4 |
2+4=6 |
6 |
| 9 | 标记 | — | 4 |
| 10 | hi(c)+5 |
3+5=8 |
8 |
| 11 | 固定尾 | — | 3 |
| 位号 | 模板 | 代入 | 结果 |
|---|---|---|---|
| 0 | lo(c0)+4 |
5+4=9 |
9 |
| 1 | 标记 | — | 4 |
| 2 | hi(c0)+5 |
5+5=10 |
A |
| 3 | hi(c2)+5 |
5+5=10 |
A |
| 4 | 标记 | — | 4 |
| 5 | lo(c2)+4 |
4+4=8 |
8 |
| 6 | 标记 | — | 5 |
| 7 | 标记 | — | 5 |
| 8 | lo(c1)+4 |
C+4=16→0 ← 回绕 |
0 |
| 9 | 标记 | — | 4 |
| 10 | hi(c1)+5 |
4+5=9 |
9 |
| 11 | 标记 | — | 5 |
| 检查项 | 要求 | 实测 | 结果 |
|---|---|---|---|
d[1] |
4 |
4 | ✅ |
d[4] |
4 |
4 | ✅ |
d[9] |
4 |
4 | ✅ |
d[6] |
5 |
5 | ✅ |
d[7] |
5 |
5 | ✅ |
d[11] |
5 |
5 | ✅ |
| # | 密文块 |
|---|---|
| 0 | 14CC46555475 |
| 1 | 94BC475584C5 |
| 2 | 848A43551495 |
| 3 | 448C445584C5 |
| 4 | D4C9475564C5 |
| 5 | 34A84B55A4B5 |
| 6 | 74BA4355F495 |
| 7 | A48844556485 |
| 8 | 648C495534A5 |
| 9 | 548C4F5584A5 |
| 10 | B4BB405554B5 |
| 11 | 22332235A4B3 |
| # | 密文块 | c0:d[2]−5 / d[0]−4 |
c1:d[10]−5 / d[8]−4 |
c2:d[3]−5 / d[5]−4 |
明文 |
|---|---|---|---|---|---|
| 0 | 14CC46555475 |
C−5=7 / 1−4+16=D → 0x7D } |
7−5=2 / 5−4=1 → 0x21 ! |
C−5=7 / 6−4=2 → 0x72 r |
}!r |
| 1 | 94BC475584C5 |
B−5=6 / 9−4=5 → 0x65 e |
C−5=7 / 8−4=4 → 0x74 t |
C−5=7 / 7−4=3 → 0x73 s |
ets |
| 2 | 848A43551495 |
8−5=3 / 8−4=4 → 0x34 4 |
9−5=4 / 1−4+16=D → 0x4D M |
A−5=5 / 3−4+16=F → 0x5F _ |
4M_ |
| 3 | 448C445584C5 |
8−5=3 / 4−4=0 → 0x30 0 |
C−5=7 / 8−4=4 → 0x74 t |
C−5=7 / 4−4=0 → 0x70 p |
0tp |
| 4 | D4C9475564C5 |
C−5=7 / D−4=9 → 0x79 y |
C−5=7 / 6−4=2 → 0x72 r |
9−5=4 / 7−4=3 → 0x43 C |
yrC |
| 5 | 34A84B55A4B5 |
A−5=5 / 3−4+16=F → 0x5F _ |
B−5=6 / A−4=6 → 0x66 f |
8−5=3 / B−4=7 → 0x37 7 |
_f7 |
| 6 | 74BA4355F495 |
B−5=6 / 7−4=3 → 0x63 c |
9−5=4 / F−4=B → 0x4B K |
A−5=5 / 3−4+16=F → 0x5F _ |
cK_ |
| 7 | A48844556485 |
8−5=3 / A−4=6 → 0x36 6 |
8−5=3 / 6−4=2 → 0x32 2 |
8−5=3 / 4−4=0 → 0x30 0 |
620 |
| 8 | 648C495534A5 |
8−5=3 / 6−4=2 → 0x32 2 |
A−5=5 / 3−4+16=F → 0x5F _ |
C−5=7 / 9−4=5 → 0x75 u |
2_u |
| 9 | 548C4F5584A5 |
8−5=3 / 5−4=1 → 0x31 1 |
A−5=5 / 8−4=4 → 0x54 T |
C−5=7 / F−4=B → 0x7B { |
1T{ |
| 10 | B4BB405554B5 |
B−5=6 / B−4=7 → 0x67 g |
B−5=6 / 5−4=1 → 0x61 a |
B−5=6 / 0−4+16=C → 0x6C l |
gal |
| 11 | 22332235A4B3 |
(尾块,规则不同) | d[10]−5 = B−5=6 / d[8]−4 = A−4=6 → 0x66 f |
(无) | f |
| # | 易错点 | 后果 | 规避方法 |
|---|---|---|---|
| 1 | 忘记最后的整体反转 | 得到 }!rets4M_... 这种倒序串 |
加密第一步反转、解密最后一步反转,两头都别漏 |
| 2 | 减法出负数没 +16 |
单个字符错,如 }→s |
查 13.0 表 (3) 的解密行,或牢记"负了就加 16" |
| 3 | 加法超 F 没 −16 |
加密结果对不上,如 C+4 写成 10 |
C/D/E/F 加 4 必回绕,见表 (3) |
| 4 | c1 和 c2 的取位记反 |
每块中间两个字符互换 | 口诀:c0→(2,0),c1→(10,8),c2→(3,5) |
| 5 | r=2 尾块中 b 的 hi/lo 顺序写反 |
末尾 1 个字符错 | a 是"先 lo 后 hi",b 是"先 hi 后 lo" |
| 6 | 尾块判别只写"以 2235 开头" |
r=1 的尾块被当成完整块,自检断言失败 |
r=1 实际以 2233 开头,两种前缀都要判 |
| 7 | 跳过固定位自检 | 块边界错位却毫无察觉,一路算到底才发现全错 | 每个完整块先查 6 个固定位,1 秒钟的事 |
| 8 | 不做回验 | 自以为对了 | encrypt(解出的明文) == 原密文,逐位比对 |
HexMaze 使用固定算法对 ASCII 字符串进行变换。
算法仅包含:
- 字节编码;
- 十六进制位运算;
- 模16循环偏移;
- 固定位置重排;
- 固定摘要扰动。
不包含:
- 随机数;
- 随机 IV;
- 外部状态。
相同输入和密钥一定产生唯一输出。
提示:摘要扰动过程只与输入长度有关。
已提供4组已知明文/密文,请分析变换规律并恢复 FLAG。
HexMaze
密钥: 121
TLU -> 94AA48550495
Hello -> 34BB405504B5223594B94C53
2026 -> A48844556485223322356483
abcd! -> 547B475584B5223564BB4553
FLAG:
14CC4655547594BC475584C5848A43551495448C445584C5D4C9475564C534A84B55A4B5
74BA4355F495A48844556485648C495534A5548C4F5584A5B4BB405554B522332235A4B3