好久没打CTF了,得快三年了吧。有一道安卓逆向就不写了,12月重装系统后没有环境
1. ez_maze
最短路径即为flag


MFC程序,常规IDA


一眼壳,上动态调试,还好是签到题,假设没有反调试
快速定位
直接运行到程序开始,定位字符串


下个断点,然后dump

然后IDA

发现验证算法的方向是反着来的。可以翻过去看看迷宫生成算法,其实在附件没更新之前的版本更好观察一点,但是直接在内存里面看更快些。


部分操作迷宫可能直接走死,没有到这个判断,跟一下rcx就行了的值,然后看rcx+0x260

还原迷宫
1 | from collections import deque |

解出flag
1 | maze = [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], |
得到flag, wwaaaaaaaawwwwddwwddwwaaaawwaaaaaassssaawwwwaawwwwwwwa

其实这道题可以学的更多的东西
- 在定位的时候可以了解MFC的Dialog机制,包括
SendMessage等windows消息队列机制。虽然在比赛中太慢了。 - 手动脱壳,然后逆向分析程序(还没试过)
2. delicious obf
能解出复杂的逆向题,却摸不透她的心。你能克服重重阻碍,找到隐藏在她内心深处的flag吗
flag长度为32
字符串找到主要逻辑

跟一小段,到0x14000655+4


第一段是正常指令,后续的是跳转的混淆的花指令,尝试使用ida提取出主要汇编,有jmp和call我是手动跟进去看的
1 | import ida_bytes |
最后一步步得到汇编
1 | --- 0x140006560: push rbp |
这一步我就卡死了,在疑似tea的那段不管是调试还是写hook,都只能把加密算法拿出来,但是memcmp哪里我哪怕修改成为正确的结果也无法通过检验
后来看了 VNCTF2026 出题笔记 出题人是手动patch混淆的lea为jmp后如果ida识别为函数,可以使用ida的 Append function tail

# Post author: Y&Y @保持好奇心
# Post link: http://example.com/2026/02/04/VNCTF2026出题笔记/
# Copyright Notice: All articles in this blog are licensed under (CC)BY-NC-SA unless stating additionally.那么先 Edit -> Functions -> Delete function 删除函数,再选中这些汇编 Append function tail 把他们并入到函数 sub_1400054BB 中

sub_14000445E
这个部分我通过自己的分析得到了加密的python函数
1 | DELTA = 0x9E3779B9 |
这一点我用hook和调试确保代码是正确的,但是不知道为啥KEY_BYTES和ida中的预期不一样
sub_1400054BB

没招了,直接问AI
1 | __int64 __fastcall sub_140005907( |
loc_14000670B

乱码,wp上写的是可以找到交叉引用,但是我的IDA在之前的去花指令后的效果有巨大不同。在我自己的ida脚本中也是的不出这一段的反汇编。不急hooksub_140006095后进行dump


测试发现函数长度0x15B,手动覆写回去

还原的非常漂亮,解密算法直接喂给AI
wp中说这一段

# Post author: Y&Y @保持好奇心
# Post link: http://example.com/2026/02/04/VNCTF2026出题笔记/
# Copyright Notice: All articles in this blog are licensed under (CC)BY-NC-SA unless stating additionally.发现如果有 int 3 中断,就对 loc_140001977 进行 smc,这里其实可以起一个反调试的作用,因为软件断点的原理就是把断点处汇编的第一个字节改为 0xCC。
但是我的ida一直都调不出来…
得到flag
根据程序直接拿到密文

key有点麻烦,但是hook不麻烦。注意,这里不要直接Hook,估计是有SMC自解码,在解密之前都是这段乱码,如果你在解密之前hook,会造成解密失败


最后
1 |
|
3. Shadow
说明:
- 推荐在虚拟机Windows10-11运行该驱动。
- 自行配备环境或签名用于加载驱动。
- 请先运行.exe再加载驱动。
- flag格式:VNCTF{你的输入}
谍影重重的迷宫,你能通过迷宫成功攻击宿主电脑吗?
还是第一次做这种驱动逆向,看了下题,不知道要干嘛,就去看obf那道题了
看VNCTF2026-Shadow-WP的WP,是从exe的逆向开始
走迷宫

然后开始分析驱动

doSomeToPool,问问AI

AES
静态+python脚本
sub_140001168AES加密过程,这个可以用插件找到S盒特征然后得出。拼接方式为ECB模式


-
字节代换

标准S盒


-
行移位

-
列混淆

编写脚本看看数据
1 | from Crypto.Cipher import AES |

windbg
可以添加相关的符号类型便于逆向

右键过后添加ntddk,wdk之类的
这里也可以尝试使用windbg调试
1 | sxe ld Shadow |


1 | .writemem D:\CTF\vnctf\re\125431_Shadow\dump.exe ffffad82253aa000 ffffad82253aa000+5e00 |

文件大小不一样,但是有效的PE文件大小是一样的
PE映射
由于我自己做过反射式dll注入的,这个也差不多(有AI其实并不难),只不过映射的是Sys PE,这里修改下类型变得好看一些

导入IAT

NewPE
上来就是个解密

还原
1 | cipher = [0xF1, 0xBB, 0xD9, 0xBD, 0xFA, 0xBF, 0xA5, 0xC1, 0xAE, 0xC3, 0xA5, 0xC5, 0xBF, 0xBA, 0xFE, 0xBC, 0xC5, 0xBE, 0xDA, 0xC0, 0xA2, 0xC2, |
然后遍历Process找到宽字节的Maze.exe程序

PTE Hook
这个就是我的知识盲区了(已添加到TodoList),大致是通过修改物理页到虚拟页的映射来进行hook
1 | 原函数VA → 原物理页 |
KeDelayExecutionThread 例程将当前线程置于指定间隔内可发出警报或不可更改的等待状态。
1
2
3
4
5 NTSTATUS KeDelayExecutionThread(
[in] KPROCESSOR_MODE WaitMode,
[in] BOOLEAN Alertable,
[in] PLARGE_INTEGER Interval
);
然后设置IRP类型,又解密Device的unicode名字。

\Device\KeyboardClass0是由 kbdclass.sys 创建的键盘类设备对象。附加键盘驱动上,此时doIrpREAD就会接收到键盘相关消息。
doIrpREAD

CompletionRoutine
先出两个加密
1 | [LDriver] on input. |
这是在 IRP_MJ_READ 完成后,从键盘输入缓冲区里解析扫描码,维护 Shift 状态,并把按键转换成 ASCII,然后存到内部缓冲区。

相当于内核的键盘记录器,按下F12,输入flag,再按下F12,最后迷宫走到E判断flag
NewKeDelayExecutionThread
其实应该一开始就分析这段代码的,但是变量太杂、信息不全,看不出是干嘛的,这时候返回去看会发现引用了记录Key的数组
-
弄了一个很大的数

-
一堆自定义的加密

enc2就是简单移位 -
最后一轮加密然后比较,应当有40字节成功,比较成功就蓝屏

动态调用
主要是 (v24)(KeylogBuffer, jj_2 + len, &MaybeKey);这一段经过了大段的加密,尝试动态调试


有其他的call,直接全部dump下来
1 | .writemem D:\CTF\vnctf\re\125431_Shadow\dump_shellcode.exe ffffc98e`8b561210 ffffc98e`8b561a71 |

精准戳中密码学功底,没招了,看上去像是RC4的结构。

最后的解密
-
得到最后的Key


1
Key=0xe7d1cc85d2172c16
后续的shellcode加密也可以检验

-
查看校验的答案


结合赛后看的wp的解密方法解密
1 |
|
从动态调试看,之前通过动态访问对密文和0x1c进行了异或


BSOD 😃
