提前声明:我不是密码学玩家,所以肯定是有错的,别拷打我。看不下去的,出门左转自便。当然,你想更正的话,可以发评论。

image-20260107133049934

题目信息

Dr. Helena Morrison Vance, a renowned cryptographer, has left behind an encrypted message before her mysterious disappearance. She was last seen working late in her laboratory, muttering something about "rotating shields" and "the key to everything lies in who I am."

#challenge.asm
global _start
section .data
    ; Cipher
    msg db '0 0 0 153 82 76 202 3 123 126 241 17 0 12 206 189 108 86', 10
    msg_len equ $ - msg
section .text
_start:
    mov rax, 1      ; sys_write
    mov rdi, 1      ; stdout
    mov rsi, msg
    mov rdx, msg_len
    syscall

    mov rax, 60     ; sys_exit
    xor rdi, rdi
    syscall

先把密文抠出来

这段汇编本身没什么逻辑,跑起来就是把 msg 打印到 stdout,所以重点只有那串数字。

0 0 0 153 82 76 202 3 123 126 241 17 0 12 206 189 108 86

“key to everything lies in who I am” → 密钥是谁

题目里的“who I am”指的就是人名本身:

Helena Morrison Vance

最自然的处理方式就是取首字母:

H M V

所以先假设 key 是 HMV,并且按常规做法循环使用。


从密文结构推测 XOR 的存在

密文一上来就是:

0 0 0 ...

这个非常显眼,一般加密数据不会随便以三个 0 开头。

而 XOR 有一个很关键的性质:

如果 XOR 是最后一步,并且 key 循环是 H M V,那么前三个字节会直接解成:

0 ^ 'H' = 'H'
0 ^ 'M' = 'M'
0 ^ 'V' = 'V'

刚好得到:

HMV

这非常像 flag 的前缀(XXX{...}),所以这里可以基本确定:


验证一下:第 4 个字符是不是 {

既然已经能推出 HMV,那第 4 个字符大概率是 {

密文第 4 个字节是:

153

这一位对应的 key 又回到 'H'

如果最后一步是 XOR,那么在 XOR 之前(也就是 rotate 完之后)的中间值应满足:

mid ^ 'H' = '{'
mid = '{' ^ 'H'

计算一下:

也就是说,rotate 之后的结果应该是 51

这正好和题面里的另一句提示对上:

rotating shields

说明在 XOR 之前还有一步 8bit 循环移位(rotate),并且某种 rotate 可以把 153 变成 51


剩下的只能爆破:rotate 规则无法唯一推理

到这里为止,能推理确定的只有

  1. 有 XOR,且在最后
  2. key = HMV
  3. 有 8bit rotate(ROL / ROR)

但以下内容题面没有给唯一答案

所以这一步只能老老实实 爆破


爆破思路

rotate 的常见写法一般是:

rot = (i * k) % 8

于是直接枚举:

筛选标准很简单:


爆破脚本

def rol8(x, r):
    r &= 7
    return ((x << r) & 0xFF) | (x >> (8 - r))

def ror8(x, r):
    r &= 7
    return (x >> r) | ((x << (8 - r)) & 0xFF)

cipher = [0, 0, 0, 153, 82, 76, 202, 3, 123, 126, 241, 17, 0, 12, 206, 189, 108, 86]
key = "HMV"

for k in range(1, 8):
    out = []
    for i, b in enumerate(cipher):
        rot = (i * k) % 8
        x = rol8(b, rot)          # 先 rotate
        p = x ^ ord(key[i % 3])   # 再 XOR
        out.append(chr(p))
    res = "".join(out)
    if all(32 <= ord(c) <= 126 for c in res):
        print(k, res)

运行后可以很快发现,只有一个结果既可读又像正常 flag:

k = 7
HMV{h4cK-w1tH-m3!}