题目地址:ctf.show
题目概览
题目文件 value.exe,Yoda 壳 + 双重反调试 + 完整性校验 + 加密数据,四层防护的 32 位控制台逆向题。从脱壳一路挖到 TLS 回调里的解密密钥,最终解出 flag flag{9969e2ddd64088f71af0caa891b4dc63}。
侦察与脱壳
拖入 exeinfope:UPX 壳,32 位控制台程序。一键脱壳后拖入 IDA,字符串定位到主函数 main_0(text:00415C10)。
主逻辑:main_0
|
|
简单分析逻辑后可得:
|
|
观察到 __CheckForDebuggerJustMyCode 函数(text:00415C3D),意识到可能有反调试。
完整性校验
定位 thunk 函数 sub_411406()(text:00415C42),根据其中逻辑:
|
|
判断其为累加自基址以来 0x6000 字节的代码值用以校验——校验完整性函数,若与原值不符则退出进程。
key 检查与 rand 门
继续分析 main_0 的 while 循环:读入 str,与 wangzherongyao 比较,否则退出;一致则 90% 概率进入下一步(rand 控制概率)。
反调试线程与 ScyllaHide
下一步进入 sub_41141A() 函数(text:00415CA0),创建两个后台反调试线程:BeingDebugged、NtGlobalFlag,检测到调试即退出线程。结合前文校验完整性函数,此处不易用 nop,可采用 x32gdb 中的 ScyllaHide 插件,然此处有坑!!!详见下文。
MessageBoxA() 函数(text:00415CB5)输出提示弹窗。
flag 解密(关键)
sub_4113CF(text:00415CC6)关键函数:
|
|
|
|
两段主题逻辑如上。当下需要知道关键数据 dword_41A038、dword_41A4DC,其中 dword_41A038 在 data 节中。只需 ScyllaHide 插件处理反调试后动态运行至此处,发现 dword_41A4DC 为 00 00 00 00。
脚本验证:乱码暴露遗漏
根据上文两函数信息,得脚本:
|
|
打印出乱码,发现问题——程序主逻辑已经分析完毕,猜测有遗漏点。
突破口:TLS 回调
将程序拖入CFF Explorer查看TLS Directory,发现AddressOfCallBacks字段值00417720,即回调函数。
也可在x32dbg 中设置用户 TLS 回调断点,发现 TLS 函数 TlsCallback_0_0(text:00411740)。
其主要逻辑 NtQueryInformationProcess,用于检测反调试,若有则修改 dword_41A4DC 的值——而 dword_41A4DC 又是解密的关键数据(XOR 密钥)。
解法
故解法有二:
解法 1:枚举密钥
猜测 dword_41A4DC 为一字节,故枚举 256 种情况;又答案首几个字母必有规律(如 flag{...}),反向推导得 dword_41A4DC 低字节必为 0xFF。
解法 2:动态观察
修改 ScyllaHide 设置,放行 NtQueryInformationProcess 函数,并在 text:00415AB7(即 printf 函数处)下断点,即可观察到 flag。
flag:
flag{9969e2ddd64088f71af0caa891b4dc63}
总结:四层防护
|
|