Cris.Q

Back

WHUCTF-2025 RE方向全题解Blur image

WHUCTF-2025 RE方向全题解#

签到#

打开发现是弗吉尼亚密码,直接解密即可。

WHUCTF{welcome_to_reverse-kep}.exe

ezbase#

发现密文 d2h1Y3RmezZac2U2NF8xc192ZXJ5XzNac3ktZWtlfQ==

猜测base64,发现表都没换

坏了,想简单了,换表了,难度还是太高了(

aBCDEFGHIJKLMNOPQRSTUVWXYZAbcdefghijklmnoqprstuvwxyz0123456789+/

得:

whuctf{6@se64_1s_very_3@sy-eke}.exe

太空逃亡#

主函数是一个巨简单的验证函数,关键的加密逻辑在sub_4015F8。检验得其把用户输入当作一串方向键 W/A/S/D(分别对应上、左、下、右),在一个 16×16 的网格(线性数组 byte_4A3020)上沿直线滑动:每次沿某方向一直前进直到遇到一个非 0的格(障碍/节点);不能越界、不能连续输入相同方向,目标是最终抵达数组中值为 ’!’(33)的格子。

值得注意的是!这是一个冰面迷宫,左右移会直接移到可移动区域的边缘。

写出解密脚本即可:

Try to find me#

打开IDA一片茫然,啥都找不到。于是Shift + F12查字符串发现了:

strcpy((char *)(v0 + 40), "Software\\flag");
strcpy((char *)(v0 + 84), "flag");
c

找到了程序逻辑的尾巴: 这里会把解密后的目标字符串写入注册表的HKEY_CURRENT_USER\Software\flag,然后残忍地删掉。 不行,不能让它删掉(悲) 于是我们patch掉这两个RegDeleteKey的调用,再次运行程序。 注:本题的加密是曾经书记出的困难题,所以别想着静调了~

What can you find#

这题可以当作一道misc去做:

> binwalk -e ./what_can_you_find.3dsx
bash

得一张png,打开有:

这其实是非预期,下面介绍一种比较简洁的预期解法。

首先,我们了解到3DSX是ELF的变体,因此有映射区段并反编译的可能。通过查找Github已有的开源库我们发现了 这个项目,这里作者其实已经对IDA 7以上的版本做了适配,我进行了少量修改使它符合IDA 9的标准,但不修改也没大问题,可以直接用。放入~/.idapro/loaders即可:

现在,我们就可以像处理一个正常的ELF可执行文件那样去处理它了。先查找字符串可以发现如上的逆天言论,跳转找到主函数:

这里是一个输入密码并显示图片的简单程序,因此我们要从中提取出图片文件。此处像上面非预期一样binwalk即可。

好多文件#

好多文件!!!

但是没关系,观察Plugins发现,83和84单独分离出了自己的dll,猜测83和84是节目效果。

打开后发现是盘子(小)小故事,笑死了。

打开exe文件,太乱了,拖一下列表发现主要函数:

我们发现了调用dll的关键函数:RunPlugin

分别打开几个Plugin的该函数,发现不同的惊喜:

直接猜XOR,最后结果肯定是whuctf{

不用说了,基础的换表base64,Cyberchef直接梭。

你这是典型的RC4逻辑,RC4思维,RC4素质。

分别解密后拼出完整flag:

whuctf{I_w1ll_give_y0u_an_extr@_po1nt}

hajimi_player#

使用FindCrypt发现了一些AES相关的东西:

询问AI有:

函数 1:sub_140012E50

作用:实现 AES-128 的密钥扩展 (Key Expansion)。

概要说明:

  • 输入:16 字节主密钥(a1)。
  • 输出:176 字节扩展密钥(a2),即 11 轮 × 16 字节的轮密钥。
  • 内部逻辑:
    • 拷贝前 16 字节为初始轮密钥。
    • 每 16 字节为一轮,执行:
      • RotWord(循环左移 1 字节);
      • SubWord(用 Rijndael S-box 替换每个字节);
      • 首字节 XOR 上 Rcon(轮常数),并更新 Rcon;
      • 按 AES 规则生成新的 16 字节轮密钥。
  • 使用的表:RijnDael_AES_LONG_14001DBE0(AES S-box)。

👉 简单说:它把一个 16 字节的 AES 密钥展开成所有轮用的 176 字节密钥数据。

函数 2:sub_140013D70

作用:执行 AES 的 SubBytes 步骤(S-box 替换)。

概要说明:

  • 输入:指向 16 字节数据块的指针(a1)。
  • 对每个字节执行:byte = SBOX[byte]
  • 直接在原缓冲区中替换(就地操作),返回 16。
  • 同样使用表 RijnDael_AES_LONG_14001DBE0(Rijndael S-box)。

👉 简单说:它把 16 字节“状态矩阵”中的每个字节都通过 AES S-box 映射,属于 AES 加密的一个核心变换步骤。

查找引用,发现了函数sub_140012CA0

分析得出这是单块AES的加密实现,用GPT的话说就是:

这是单块 AES-128 加密的驱动函数——把 16 字节明文用 16 字节密钥加密成 16 字节密文(相当于 ECB 的单块操作)。流程就是标准 AES:初始轮密钥异或 → 9 个主轮(SubBytes→ShiftRows→MixColumns→AddRoundKey)→ 最后一轮(SubBytes→ShiftRows→AddRoundKey,不含 MixColumns)。

顺着该函数的线索,观察行移位和列混淆和轮密钥加的相关函数:

  • sub_140013A30:ShiftRows
  • sub_140013390:MixColumns
  • sub_140012C00:AddRoundKey(state XOR round key)

发现全是标准实现。(想到了书记骂盘子的“都多少年了还看不出来AES”)

全部更名后,想起了被PolyEncrypt支配的恐惧。

根据该函数的引用,跳转到了sub_140011990,这是一个登录对话框,输入用户名和密码。

然而,我们发现了奇怪的函数!

根据函数签名,它长得很像加密函数,但又不是我们之前分析的AES_EncryptBlock。导航进去并尝试分析之。发现是一个类TEA实现。这里Trunk和跳转比较多就不贴出完整流程了,给一个重命名表,可自行检验:

sub_140013E00 = TEA_EncryptBlock128_ECB
sub_140013EA0 = TEA_Encrypt64
sub_140011447 = TEA_Trunk_Wrapper
c

至此登录部分分析完毕,给出用户名和密码的解密脚本(解密需要的静态数据就不贴出了,很容易找到)。

获得用户名和密码。

接下来根据窗口逻辑,顺着指针dwNewLong_捋到函数sub_140012480,发现是一个文件解密器的实现。GPT大人如是说:

快速结论(一句话) sub_140012480 是 Hajimi Player 的窗口过程:用户点击 “select your hajimi file” 会把路径放到全局 FileName;点击 “play” 会读取 GetWindowLongPtr(hWnd, GWLP_USERDATA)(也就是登录时存的 Destination —— username+password 拼接字符串),把它作为“密钥/密钥材料”传给 sub_14001110E(初始化/派生解密上下文),然后调用 sub_140011451 把读到的文件数据用该上下文进行解密/处理,最后把解密后数据指向全局 ::Block/::Size 以供播放。也就是说 Player 在播放前会对选中文件进行解密,解密密钥由窗口的 user-data(登录时的 username+password)来派生/生成。

啊伟大的GPT大人!

解密文件部分主要涉及的是sub_14001110Esub_140011451,分析得知:

…能得知什么,就一破RC4罢了。

解密之:

通过file命令查阅生成的基密文件后发现是个MP4,遂直接mpv播放之。

WHUCTF{h@jimin@meLud0_axiga@xiii}

byd气笑了。

Baby_HeavenGate#

众所周知,Heaven’s Gate是一种在32位程序环境下执行64位代码的混淆技术。 于是,当我们看到这个JUMPOUT时,我们就知道要切到反汇编界面进行查看了。 这里出现了牢门经典的call $+5retf等汇编指令。

进门发现一个简单的异或: 继续往下分析,又发现了经典牢门: 分析可得,这里会把用户输入送入sub_402000函数中。 当然,如果你实现没有执行某一步骤,你看到的可能不是正经的sub_402000,而是一些奇怪的东西。 其实这里出题人已经通过区段名给了我们提示:这里是Heaven’s Gate跳转到的64位代码处。我们通过IDA的Edit-> Segments -> Edit Segment将x64区段改为64位: 核心的异或解密逻辑就搞定了。

因此,写出解密脚本如下:

解密结果: flag{Heavens_Gate_mastered}

天才侦探#

打开发现奇怪的setjmp函数:

带着对它的疑惑,先看看别处的逻辑🤔

很轻松地,我们可以看出XOR和XXTEA_Encrypt加密的线索。

然而,XXTEA_Encrypt中部出现了疑似花指令的诡异跳转。切到汇编: 经典的跳转到+1位置,在中间藏一个恶心人的幽灵call。NOP掉即可。

然而,在XXTEA加密的末尾,我们发现了奇怪的除0行为!

这里非常不对劲,除0会引发报错。猜测这里的报错是有意为之,我们找到错误处理函数Function

一个永真跳转,先执行sub_4015F0,再执行longjmp_w。到这里我们明白了上面的setjmp究竟起何作用:一开始Buf是0,执行XXTEA加密,然后XXTEA加密末尾通过除零触发Function,修改Buf为1并跳到setjmp处,使程序进入XOR_Encrypt的分支。

于是,问题就在于:sub_4015F0()做了什么。

分析各种跳转发现,这里又是一个异或。

于是理清了所有加密步骤,写出解密脚本:

解密结果: WHUCTF{U_ar3_as_pr0f3ssional_as_siesta!}

感想#

本次迎新赛拿到了个总榜第二。当然还是感谢学长们不杀之恩。

第一天下午去了Deepin的WHLUG,没写题,第二天运动会+百团大战+游园会,算是玩爽了,也没怎么写题,我忏悔喵。

最后,逆向工程这个方向,从迎新赛打到moe,从NewStar打到ILoveCTF,甚至在强网杯还干出来一题。再回头看看迎新赛,虽不能说轻舟已过万重山,至少也翻过了一两重吧。

WHUCTF-2025 RE方向全题解
https://crisq.top/blog/whuctf_2025_newbies_wp
Author Cris.Q
Published at 2025年10月26日
Comment seems to stuck. Try to refresh?✨