记一次解谜

Austerity(Misaka10548) Lv1

前言

我先说一点:我本人呢,并不是1999的玩家

缘由呢就是朋友在群中发的这样的话:

有没有兴趣做个深蓝整的大型解密() 涉及:ASCII码,布尔运算,LSB,befunge

翎尘玖宇

在五一假期闲着也是闲着,索性就做做看看吧
反正我一个小白,没怎么做过解谜,应该也做不了多少….吧?
权当练练手了

需要明确的一点是: 现在是AI(LLM)时代了,所以我这个小白,并没有什么“慢慢来”
直接坐上了AI这个轮椅,所以我到底在解谜做了多少,应该没有很多吧
倒是收获还是有的

至于解谜原题呢,这里就不再列出了,应该找得到。

解谜

第一个(循环异或)

玖宇转过来的第一个谜题的信息是:
060E020D0F1B09000404005C5C和
6861766566756E

一开始我是把它俩分开看的,即使当时考虑一个作为密钥的可能性(当时想的是aes密钥2333,不过问ds很快就被否了)

玖宇给到的提示是:

  1. 这部分就是ascii码和布尔运算了
  2. 给个提示:循环异或(这个是稍后一点时间给的,放在一起了)

ASCII
那么布尔运算:

ds大概给了这几种:

  1. 异或 (XOR)
  2. 位掩码 (AND/OR)
  3. 逻辑方程与求解
  4. 代码混淆与逆向

讲真我真有被第3、4点吓到,遇上这种题真是没办法去解
什么 Z3 求解器 (Z3 Solver)恒真/恒假式插入德摩根定律(De Morgan's laws)等价变换混淆 听得我是一愣一愣的。

考虑到长度和提示,应该是:重复密钥异或(Repeating-key XOR)
一句话总结简单来说就是:一个密钥从头到尾循环使用,到尾了就重新接着来

如果文字不好理解,看代码就好了:

1
2
3
4
5
6
7
private static byte[] XorWithKey(byte[] data, byte[] key)
{
byte[] result = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
result[i] = (byte)(data[i] ^ key[i % key.Length]);
return result;
}

喏,就是这样,循环使用

然后我们把密文和密钥传进去:

1
Encoding.ASCII.GetString(XorWithKey(new Byte[] { 0x06, 0x0E, 0x02, 0x0D, 0x0F, 0x1B, 0x09, 0x00, 0x04, 0x04, 0x00, 0x5C, 0x5C }, new Byte[]{0x68, 0x61, 0x76, 0x65, 0x66, 0x75, 0x6E}));

我们就得到了…..nothing here:)

BTW顺带一提

6861766566756E可以直接被ASCII解码,结果是:havefun

第二个(LSB隐写)

第二个是一张图片,没什么字

玖宇的提示:

  • LSB隐写

随附文件StegSolve.jar

关于LSB隐写

LSB(最低有效位)核心原理是替换“不重要的信息”。

对与部分文件格式,有的地方的数据略有“不自然”,人眼是不太能看出来的,我们就可以往里面夹一些“私货”。

不过也有能看出来但是不是很好解读的
比如说那些幻影坦克光棱坦克

LSB隐写有两种形式:

  1. 图像形式
  2. 字节数组形式

(我自己起的名字)

图像形式比较好看见,利用软件浏览位平面,能看到隐藏的图像。
字节数组的话,就是利用LSB藏十六进制信息,位平面浏览不太能看出来,还要自己判断文件类型。

回到解谜

ds对与LSB隐写的解谜图片,推荐的是StegSolvezsteg
手头有StegSolve了,就用这个吧(zsteg也着实不太好安装)

最后发现Red 0位平面的图像不太对头,有些奇怪的连续和明显的分界上面的。
尝试提取文本得到这个:

1
2
3
4
5
6
7
8
9
89504e470d0a1a0a 0000000d49484452  .PNG.... ....IHDR
000002b4000002b4 0806000000f23eae ........ ......>.
da00000009704859 7300000b1300000b .....pHY s.......
1301009a9c180000 00017352474200ae ........ ..sRGB..
ce1ce90000000467 414d410000b18f0b .......g AMA.....
fc61050000000e74 455874536f667477 .a.....t EXtSoftw
617265004669676d 619eb19663000065 are.Figm a...c..e
8f494441547801ed dded55db4ed3c7f1 .IDATx.. ..U.N...
cd7daef7900a800a e05f015001a40248 .}...... ._.P...H

PNG、IHDR、sRGB是个图像的文件头
把这一位平面的数据保存下来,再以图像打开就能得到下一个谜题

第三个(Befunge)

打开图像,我们能得到这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>   >"E"v"D"v
v"F"v"T"?"E"v
v"A">"E"v"N"v
v"I"v"T"<"I"v
v"L"?"-"v"E"v
v"E"v"A"?"D"v
v"D">"-"v"A"v
v"L"v"E"<"C"v
v"O"?"T"v"C"v
v"G"v"E"<"E"v
v"I"?"T"v"S"v
v"N"v" "?"S"v
v"S">"A"v"!"v
v<<<<<<<<<<<<
>:#,_@

这里很显然就是Befunge的领域了

Befunge

注意

这里的内容参考deepseek

一门由Chris Pressey在1993年创造的深奥编程语言(esoteric programming language)
它的设计初衷不是为了实用,而是为了挑战“程序必须是线性文本流”这个固有观念。

Befunge程序运行在一个二维网格上,指令指针可以在网格中向上、下、左、右四个方向移动

Befunge Editor是我使用的一个可视化运行/编辑器

这里(取Befunge-93为例)

  • 它的运行空间是一个 80×25 的字符网格,超出范围会回绕
  • 它的控制流(指令指针)开始时位于左上角 (0,0),默认向右移动
  • 元素弹入栈中,运算在栈进行

简单语法:

  1. 指针控制
    • > 向右移动
    • < 向左移动
    • ^ 向上移动
    • v 向下移动
    • ? 随机选择4个方向之一(遇到它就像走迷宫遇到岔路)
    • _ 水平条件转向:弹出栈顶值,如果值为 0 则向右,否则向左
    • | 垂直条件转向:弹出栈顶值,如果值为 0 则向下,否则向上
    • # 蹦床:跳过下一个指令格(指针会多走一格)
  2. 数字与算术
    • 0 - 9 直接将该数字压入栈顶
    • + 加法:弹出 a, b,压入 b + a
    • - 减法:弹出 a, b,压入 b - a
    • * 乘法:弹出 a, b,压入 b * a
    • / 整数除法:弹出 a, b,压入 b / a(向 0 取整)
    • % 取模:弹出 a, b,压入 b % a (保持与除法一致的符号)
  3. 比较与逻辑
    • ` (反引号)大于判断:弹出 a, b,如果 b > a 则压入 1,否则压入 0
    • ! 逻辑非:弹出 x,如果 x 为 0 则压入 1,否则压入 0
  4. 栈操作
    • : 复制栈顶元素(常用)
    • \ 交换栈顶两个元素
    • $ 弹出并丢弃栈顶元素
  5. 输入输出 (I/O)
    • . 弹出栈顶整数,以数字形式输出
    • , 弹出栈顶整数,以ASCII 字符输出
    • & 等待用户输入一个整数(读取直到非数字字符),压入栈
    • ~ 等待用户输入一个字符,将其 ASCII 码压入栈
  6. 字符串模式
    • " 开启/关闭字符串模式。指针在字符串模式中时,遇到的每个字符(除 " 外)的 ASCII 值都会被直接压入栈,而不会被当作指令执行。再次遇到 " 则退出。
  7. 自修改与取代码
    • g (get)弹出 y, x,将程序网格中 (x, y) 位置字符的 ASCII 码压入栈
    • p (put)弹出 y, x, v,将 ASCII 值为 v 的字符写入程序网格的 (x, y) 位置
  8. 流程控制
    • @ 结束程序
    • 空格 什么都不做(通常用于填充路径)

来一个简单的示例,HelloWorld:

1
"!dlroW ,olleH">:#,_@

能注意到这里的字符是倒序的,是因为栈是后入先出(LIFO)的原因

我们先逐字符的将Hello, World!压入栈,然后让控制流向右(>)
我们先复制栈顶值(:),因为后面的,_都会弹出一次栈顶
然后来到#跳过输出(,),进入控制语句(_),弹栈
现在栈里面是有东西的,所以指针移动方向会被改成向左(这里是控制语句_的作用)
输出、弹栈(,),#防止等下多次运行:跳过这条语句
遇到>指针移动方向变成向右,重复以上步骤~
最后栈为空的时候:复制0,_向右到@,结束~

回到解谜

再这样看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>   >"E"v"D"v
v"F"v"T"?"E"v
v"A">"E"v"N"v
v"I"v"T"<"I"v
v"L"?"-"v"E"v
v"E"v"A"?"D"v
v"D">"-"v"A"v
v"L"v"E"<"C"v
v"O"?"T"v"C"v
v"G"v"E"<"E"v
v"I"?"T"v"S"v
v"N"v" "?"S"v
v"S">"A"v"!"v
v<<<<<<<<<<<<
>:#,_@

就能清楚些了:
我们能注意到左右两侧的控制流会最后指向坐下进入输出模式
考虑到这是解谜,目的是提取信息
结合起点来看的话,应该是?处是要填空的控制流语句,这样使程序按照一定顺序运行,得到密文。

BTW顺带一提

其实能排除一部分选择情况,我感觉能穷举出来,复杂度也不是很高

然后是对应六个?的线索

我只解出来(正确)2、3、5、6

这里按提示列举,这些使用的信息来自AI

  1. 宝石结构
    应该是和物理结构/性质有关,这个没推正确,倒是反根据输出推出来了
  2. 俄语
    право是“法律”与“权利”的核心词汇。
    在法律、政治、哲学语境下,它通常对应英文的 Law(法律体系、法学)和 Right(正当要求、权力)
    很明显了吧,是>
  3. 八卦像
    为震(☳),方向向东
    因为图片方向向右的话,很明显会得不到信息
    这里假设按控制流大体方向为北
    得到<
  4. 世界历史
    不会
  5. 计算机指令
    借助AI(其实ds这里好像有点傻,有些地方错了)
    可能是带进位循环左移 / 右移,应该是带进位算术右移(RCR)
    得到>
  6. 等压线
    这个的出来挺迷的
    我看的密集区,做切线,一个方向不行
    所以<

按上面的推断填入,运行大概可以得到:

1
2
A TE-A-TE
A TETE-A-TE

基于此结合搜索,可以推断出1是<

实际上,是:A tête-à-tête

第四个(A tête-à-tête)

经过搜索,我们来到重返未来:1999|A tête-à-tête

网页的话,手痒直接打开Devtools,以递归形式展开

得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<div class="hide-text">
<div class="text-112">[RX]255 250 257 323 336 339 335 "BORN" 255 240</div>
<div class="text-112">[RX]255 250 257 337 326 322 324 326 "PEACE" 255 240</div>
<div class="text-112">[RX]255 250 257 324 336 340 334 336 340 "COSMOS" 255 240</div>
<div class="text-112">[RX]255 250 257 329 336 337 326 "HOPE" 255 240</div>
<div class="text-112">[RX]255 250 257 341 339 342 326 "TRUE" 255 240</div>
<div class="text-112">[RX]255 250 257 340 337 330 339 330 341 "SPIRIT" 255 240</div>
<div class="text-112">[RX]255 250 257 322 325 354 367 "FATE" 255 240</div>
<div class="text-112">[RX]255 250 257 334 342 340 330 324 "MUSIC" 255 240</div>
<div class="text-112">[RX]255 250 257 333 330 328 329 341 "LIGHT" 255 240</div>
<div class="text-112">[RX]255 250 257 333 326 328 326 335 325 "LEGEND" 255 240</div>
<div class="text-112">[RX]255 250 257 334 346 341 329 "MYTH" 255 240</div>
<div class="text-112">[RX]255 250 257 322 337 337 333 326 "APPLE" 255 240</div>
<div class="text-112">[RX]255 250 257 339 326 333 330 324 "RELIC" 255 240</div>
<div class="text-112">[RX]255 250 257 333 336 335 325 336 335 "LONDON" 255 240</div>
<div class="text-112">[RX]255 250 257 340 330 333 326 335 341 "SILENT" 255 240</div>
<div class="text-112">[RX]255 250 257 340 330 328 330 333 "SIGIL" 255 240</div>
<div class="text-112">[RX]255 250 257 344 336 339 333 325 "WORLD" 255 240</div>
<div class="text-112">[RX]255 250 257 328 322 333 322 345 346 "GALAXY" 255 240</div>
<div class="text-112">[RX]255 250 257 337 340 346 324 329 "PSYCH" 255 240</div>
<div class="text-112">[RX]255 250 257 336 322 340 330 340 "OASIS" 255 240</div>
<div class="text-112">[RX]255 250 257 328 336 333 325 "GOLD" 255 240</div>
<div class="text-112">[RX]255 250 257 341 330 334 326 "TIME" 255 240</div>
<div class="text-112">[RX]255 250 257 322 324 326 "ACE" 255 240</div>
<div class="text-112">[RX]255 250 257 356 362 367 "SPY" 255 240</div>
<div class="text-112">[RX]255 250 257 328 329 336 340 341 "GHOST" 255 240</div>
<div class="text-112">[RX]255 250 257 340 341 339 326 322 334 "STREAM" 255 240</div>
<div class="text-112">[RX]255 250 257 324 322 340 341 333 326 "CASTLE" 255 240</div>
<div class="text-112">[RX]255 250 257 339 336 324 332 "ROCK" 255 240</div>
<div class="text-112">[RX]255 250 257 323 326 322 341 "BEAT" 255 240</div>
<div class="text-112">[RX]255 250 257 337 342 339 326 "PURE" 255 240</div>
<div class="text-112">[RX]255 250 257 334 336 325 340 "MODS" 255 240</div>
<div class="text-112">[RX]255 250 257 332 335 330 328 329 341 "KNIGHT" 255 240</div>
<div class="text-112">[RX]255 250 257 343 330 335 346 333 "VINYL" 255 240</div>
<div class="text-112">[RX]255 250 257 330 340 333 322 335 325 "ISLAND" 255 240</div>
<div class="text-112">[RX]255 250 257 339 322 330 335 "RAIN" 255 240</div>
<div class="text-112">[RX]255 250 257 327 333 322 334 326 "FLAME" 255 240</div>
<div class="text-112">[RX]255 250 257 360 340 373 354 "MOTH" 255 240</div>
<div class="text-112">[RX]255 250 257 339 342 335 326 "RUNE" 255 240</div>
<div class="text-112">[RX]255 250 257 323 333 342 326 "BLUE" 255 240</div>
<div class="text-112">[RX]255 250 257 371 323 368 371 367 "STAGE" 255 240</div>
<div class="text-112">[RX]255 250 257 340 334 330 333 326 "SMILE" 255 240</div>
<div class="text-112">[RX]255 250 257 323 339 330 325 328 326 "BRIDGE" 255 240</div>
<div class="text-112">[RX]255 250 257 335 330 328 329 341 "NIGHT" 255 240</div>
<div class="text-112">[RX]255 250 257 343 336 330 325 "VOID" 255 240</div>
<div class="text-112"></div>
</div>

这是线索。

BTW顺带一提

这里实际上的正常的发现方法是鼠标移到网页右侧(Devtools也能发现在那里)

不过我还是手痒,点开源代码就扒到了js
不过考虑到js逆向应该不是设计解谜方法,所以没去使用(但是下一关没招了这样找的flag)

让我们看看,每个条目都是这样的形式:
[RX]255 250 257 <数字序列> "单词" 255 240
其中:

  • 255 250 → 起始标志
  • 255 240 → 结束标志
  • 中间的数字序列:对应单词每个字母的 ASCII 码 + 257

但是第三条不是都满足的:异常单词的数字中包含 >347 的值

  • FATE 322 325 354 367 → ADan
  • SPY 356 362 367 → cin
  • MOTH 360 340 373 354 → gSta
  • STAGE 371 323 368 371 367 → rBorn

连在一起就是:

1
ADancingStarBorn

即为答案。

第四个(Query,败北)

来到下一个页面:

个人认为有用的信息如下:

1
2
3
4
5
6
7
Query:Was that your goal to find her and end all this?
PXQYVETBHRMARTWOAPBKL
OWPZQVFGHETUHXEKSKMLYVCJEDLNW
PQAETONDSFOF
TXMBVHEIEPRZA
Error Noise Detected
Awaiting Filter Key

找了半天没找到什么线索(应该是Noise提示的,有无效数据),我把落脚点放在Query上了
直接搜索不太行,我交给了deepseek

那唯一的收获是:Deepseek的网页多轮搜索是有调用上限的

1
2
3
4
5
6
7
8
9
10
11
 - 也许我们搜索“your goal to find her” “1999” “timekeeper”。

- 联网搜索暂不可用

- 我已收到指令,达到了最大工具调用步骤,因此必须基于现有信息来回答用户的问题。用户的核心查询是找到英文句子 "Was that your goal to find her and end all this" 在游戏《重返未来:1999》中的来源和上下文。

我查看了所有的搜索结果,但没有一个直接包含这句完整的英文台词。几个最相关的线索如下:一个结果提到了游戏角色“十四行诗”,但她的台词是“希望未来...”,并非用户所问的句子。另一个结果提到了“帕拉塞尔苏斯”和“科马拉全景监狱”,但这句台词也不是用户所问的。还有结果提到了一个名为“ASD-08d”的剧情,涉及“要找到罗蕾莱并不困难”,但这句台词也不匹配。

虽然我没有找到原句的出处,但我从多个可信的游戏介绍和评测中找到了关键信息,这能够帮助解释这句问句的含义。多个来源一致指出,玩家扮演的主角“维尔汀”,代号“司辰”,其核心目标和故事动机正是“寻找自己的妈妈”以及“结束这一切”。更具体地说,多个来源都提到主角的目标是“要找到自己的妈妈”,而这场冒险的终极目标是“揭开真相,结束这个混乱的局面(暴雨)”。主角的使命与“寻找她”和“终结暴雨”紧密相连,一个来源甚至将“找到妈妈”直接称为“他的目标”和“这个游戏的核心所在”。而作为一款拯救世界、终结灾难的游戏,主角的旅程本就伴随着“结束这一切”的使命。

因此,我可以确定,用户提供的这句英文台词虽然没有被直接搜到,但它所描述的情节,与游戏的官方设定、主角维尔汀的核心目标完全吻合。我接下来可以基于这些证据来构建一个完整的答案,向用户解释这句问话的背景和可能的对话双方。我将分析这句台词是某人询问主角维尔汀,而它精准地概括了主角的目标。

最后是这样的

根据现有搜索结果,我们无法定位到您提供的英文原句“Was that your goal to find her and end all this”的具体出处。不过,这句台词所描述的内容与游戏的核心设定和主角目标完全吻合。

🧐 台词背景解读:主角的目标

您查询的这句话,很可能是一句对主角维尔汀(玩家扮演的角色,代号“司辰”)的提问。它精准地概括了维尔汀在游戏中的两大核心目标:

  • “find her” (找到她) 游戏剧情中,主角维尔汀的目标是“寻找自己的妈妈”。这不仅是她踏上旅途的原动力,也被认为是整个游戏故事的核心所在。

  • “end all this” (结束这一切) 这句话指代的是终结“暴雨”。“暴雨”是降临在1999年最后一天的神秘灾难,会扰乱时间与世界。作为不受“暴雨”影响的“司辰”,维尔汀为了揭开真相、拯救同伴,必须找到办法终结这一切。

在玩家社区中,也常将寻找母亲、终结“暴雨”概括为维尔汀的核心使命。

💎 总结

总而言之,您查询的台词可以理解为:某个人物在质问主角维尔汀——她一路以来的最终目的是否就是为了找到母亲并终结这场灾难性的“暴雨”。这确实是贯穿《重返未来:1999》整个故事的关键所在。

那还真是….意外的收获

不过这些信息也无济于事。

场外方法

败北了之后,我还是想看看答案,那么
只能 看 看 j s 了

对于index.js我们有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...

$(function() {
window.initPuzzleConfirm && window.initPuzzleConfirm({
inputSelector: "#answer",
confirmBtnSelector: "#btn-confirm",
errorTipSelector: "#error-tip",
answerRules: {
requiredAsciiComma: !0
},
secretConfig: {
"version": 1,
"mode": "single",
"pageId": "overview-2",
"answerKey": "OVERVIEW_2_A",
"template": "xor-bytes",
"normalize": "fullwidth-safe",
"salt": "da415519",
"params": {
"mask": [37, 13, 38, 32],
"prefix": "C"
},
"target": [102, 94, 110, 101, 108, 94, 114, 104, 96, 72, 104, 100, 107, 66, 114, 116, 109, 72, 107, 101, 100, 67, 117]
},
onSuccess: () => {
window.PuzzleWindowFlow && window.PUZZLE_PAGE_META && window.PuzzleWindowFlow.completeCurrentPage(window.PUZZLE_PAGE_META)
}
})
});
...

显然,secretConfig极为重要。它告诉我们:

  • "template": "xor-bytes", → 解谜方式应该是循环异或
  • "mask": [37, 13, 38, 32], → 密钥
  • "target" → 密文

丢给deepseek,解得:

1
CSHEISTHEENDNOTTHEMEANS

填入输入框…
欸不对,为什么?

注意到input.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
const {inputSelector: n="#answer", confirmBtnSelector: r="#btn-confirm", errorTipSelector: t="#error-tip", correctAnswer: i="", secretConfig: o=null, getSecretConfig: c=null, getConfig: s=null, answerRules: u=null, onSuccess: l= () => {}
...
else {
const n = function(e) {
if (window.PuzzleSecretVerifier && "function" == typeof window.PuzzleSecretVerifier.passAnswerRules && !window.PuzzleSecretVerifier.passAnswerRules(e, u))
return !1;
const n = y();
if (n)
return !(!window.PuzzleSecretVerifier || "function" != typeof window.PuzzleSecretVerifier.verify) && window.PuzzleSecretVerifier.verify(n, e, {
answerRules: u
});
const r = z(e);
return Array.isArray(i) ? i.some(function(e) {
return z(e) === r
}) : z(i) === r
}(e);
if (n)
return p(),
void l();
d()
}
...

注意到secret-verifier.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
function a(e, r) {
if (!r || "object" != typeof r)
return !0;
const t = null == e ? "" : String(e);
if (r.requiredAsciiComma && -1 === t.indexOf(","))
return !1;
if (Array.isArray(r.requiredChars) && r.requiredChars.length > 0) {
const e = r.requiredChars.map(function(e) {
return null == e ? "" : String(e)
}).filter(function(e) {
return "" !== e
});
for (let r = 0; r < e.length; r += 1)
if (-1 === t.indexOf(e[r]))
return !1
}
return !0
}
...

所以,应该去除前缀C,并在下标10后添加,

答案是:SHEISTHEEND,NOTTHEMEANS

唉。

提醒

对于这种非常规解谜方法,我是不建议大家这样做的,人家辛辛苦苦做的解谜被你这样跳过去了也不好。
不过我有点不甘心想看看答案
看起来这个网站的解谜不少(progress-store.js,条目挺多的,我没做逆向,我也不是干这个的)
实际上对于其他的谜题,我也不太清楚能不能行。但是,不要这样“解谜”为好,真的,算我求你。

一些无关紧要的东西

其实还用了这些C#代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private static string VigenereCipherDecrypt(string cipherText, string key)
{
key = key.ToUpper();
StringBuilder plainText = new StringBuilder();
int keyIndex = 0;
foreach (char c in cipherText)
{
if (char.IsUpper(c))
{
char k = key[keyIndex % key.Length];
keyIndex++;

int p = (c - 'A' - (k - 'A') + 26) % 26;
plainText.Append((char)(p + 'A'));
}
else
{
plainText.Append(c);
}
}
return plainText.ToString();
}

public static string VigenereCipherEncrypt(string plainText, string key)
{
key = key.ToUpper();
StringBuilder cipherText = new StringBuilder();
int keyIndex = 0;

foreach (char c in plainText)
{
if (char.IsUpper(c))
{
char k = key[keyIndex % key.Length];
keyIndex++;

int cip = (c - 'A' + (k - 'A')) % 26;
cipherText.Append((char)(cip + 'A'));
}
else
{
cipherText.Append(c);
}
}
return cipherText.ToString();
}

// 试这两个东西是因为DS当时拿答案推过程猜这样得的,事实证明很扯。
Console.WriteLine(VigenereCipherDecrypt("PXQYVETBHRMARTWOAPBKLOWPZQVFGHETUHXEKSKMLYVCJEDLNWPQAETONDSFOFTXMBVHEIEPRZA", "WASTHATYOURGOALTOFINDHERANDENDALLTHIS"));
Console.WriteLine(VigenereCipherEncrypt("SHEISTHEENDNOTTHEMEANS", "WASTHATYOURGOALTOFINDHERANDENDALLTHIS"))

感谢那个已经死掉的.NET Interactive/Polyglot NoteBook, 我用着其实还挺顺手的

结语

你别说,还真有点意思,也有点收获
好奇CTFer过来做这前面几道题是不是很快就解决了()
虽然最后用了那么不常规的手段…
但前面部分还是玩得挺有意思的

接下来就交给各位玩1999的大佬啦!~

  • 标题: 记一次解谜
  • 作者: Austerity(Misaka10548)
  • 创建于 : 2026-05-03 11:43:00
  • 更新于 : 2026-05-03 19:08:20
  • 链接: https://austerity.irislc.net//post/2026/05/03/f6f390df/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论