-
-
看雪CTF.TSRC 2018 团队赛 第九题 谍战
-
发表于:
2018-12-19 03:21
3826
-
看雪CTF.TSRC 2018 团队赛 第九题 谍战
还是没有时间写,直接写一下结论,略去大部分分析过程。
让我们首先观察出题方的队伍名字:GPUber,里面有三个十分扎眼的大写字母。
题目给了一个 32 位 Windows 应用程序,运行之后可以看到一个自绘并且在 HiDPI 屏幕上还画糊了的图形界面。
程序中有这么一个字符串 "Nana C++ Library",Google 搜一下可以发现是一个历史悠久的有趣的 C++ GUI 库。
程序本身的功能也是输入字符串,告诉你对不对,需要注意的看起来程序上没有按钮,应该是定时或者检测了文本框内容改变触发的验证。
WinMain 里首先验证了系统版本,必须为 Windows 7 以上,然后验证了 DirectX 版本,接下来初始化了一个奇怪的正则表达式^([[:d:]]{10})([[:d:]]{10})([[:d:]]{10})$
。
接下来在栈上造了一大堆(可能有些是套起来的)C++ class,结构如下:
接下来构造了一些画画的玩意,主要是 nana 库里的东西,暂时没必要具体分析。
但值得关注的是构造的过程中它造了一个 vtable 的名字是 nana::basic_event<nana::arg_textbox>::docker::``vftable'
的东西,又把另一个带虚函数的对象挂在了上面。不妨大胆猜想这里是在挂 onchanged 事件,找到那另一个对象的虚表(0x4AA384)里最大的函数(…………),开头下个断点试一下输入,会发现确实断下了,走几步会发现获取到了刚刚改变的输入文本,看来八九不离十。
接下来再仔细看一下会发现这个 onchanged 函数里还是干了不少事情的,把拿到的输入对着之前的那个正则表达式匹配了一下(所以输入的格式是三组每组10位的十进制数字连起来),atoi 然后填进 CheckContext 里的 Input0, Input1, Input2。然后貌似对着这个结果做了一些验证,最后判断了一下验证的结果然后看上去是 toggle nana 里面两个 label 的 visibility,好像很真,然而改一下最后的判断可以发现程序并没有显示 Correct,说明要么其他地方还有检查,要么这里的检查根本就是假的。
回到 WinMain 里继续看,程序接下来创建了一个新的线程,把上面的两个Context结构体指针传了进去,里面的逻辑是先通过找特定名字的窗口的方法拿到刚刚 nana 造出来的窗体,然后起另一个线程做坏事。
这“另一个线程”里调用了一大堆 DX 的函数,众所周知的是,DirectX 的 API 是走 COM 那一套搞的,这里有一个小技巧是,注意到 d3d11.h 里其实是定义了 C 风格的手动 vtable 的函数结构的,如果能把这部分抠出来的话这个程序看起来会非常的方便。手动抠可能有点累,不过我们可以找一个纯 C 写成的 DirectX 程序的 demo (比如这个),然后自己拿 MSVC 编译一下,把得到的程序连同 pdb 一起扔进 IDA,在 Local Types 里选中所有 ID3D 和 IDXGI 开头的类型,右键 Export to headers,再在正在分析 CM 的 IDA 里 Ctrl+F9 加载,然后标一标类型,在 Hex-Rays 里就可以得到如下的看起来还可以的结果辣。
仔细分析一下这里面的逻辑,会发现里面造了三个 shader 在画画,其中第一个和第二个的结果跟输入没关系,输出会作为 texture resource 传给第三个。同时有一个线程,每两秒会去拿一下 CheckContext 里的 Input0, Input1, Input2,填进第三个 shader 的 constant buffer 里,然后画第三个 shader。
所以估计第三个里面是个什么验证逻辑,验证了输入的 Input0, Input1 和 Input2,然后根据验证结果选择把第一个或者第二个画的东西最后画出来吧。
既然我们怀疑验证逻辑藏在 shader 里面,那么把这个 shader 反汇编出来看看就行了。这个 shader 使用的还是老式的 DXBC 而不是 DXIL。
奇怪的是 D3DDisassemble 对这个 shader 会返回错误,不知道是版本问题还是啥情况(看起来作者用的是 Windows 8.1 SDK 里的 fxc 编译的 shader),打开 Google 闲逛可以找到果然有蛋疼人士已经写过一个手动反汇编的工具了:https://github.com/tgjones/slimshader/ ,本来想的是这个有代码,报了错的话也好对着看 bytecode 是不是哪里被动了手脚,但实际上能直接顺利反汇编出来:
最后果然是判断了一下决定输出哪个 texture。看起来验证逻辑就是把输入按十进制数位拆开打乱组装回去然后乱判判。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)