[SUCTF2019] hardcpp 题解

题目链接: https://buuoj.cn/challenges#[SUCTF2019]hardcpp

思路

首先用 Detect it easy 这个软件,看看有没有壳

发现没有

image.png

接下来我们把这个程序丢入 IDA (截图上面有些不一样是因为我改过一部分函数的名字了)

image.png

看到一大坨 while(1) 就可以知道这个题目上了平坦控制流混淆

本来我是想和之前一样用一个平坦控制流脚本(https://github.com/cq674350529/deflat)来去除这个混淆的。但是很不幸,毕竟是别人的脚本,去除的时候总是会出那么些 bug,在这个题目,假如你用这个脚本来去除混淆,你会发现有些变量莫名其妙也被去除了,如果勉强做下去的话,肯定会出大问题。

面对这种程序流程被打乱的局面,我们只能让程序跑起来,记录下来程序的执行流程才行。

但是这个题目没法运行(可能是动态链接的那些库现在的 Linux 上没了对应的版本吧)

所以调试是没办法了,unicorn 等模拟执行的工具我也不太会。

但是也并不是没有办法,毕竟 IDA 反编译出来的代码是类 C 代码,稍微改动改动还是能过 c/c++ 编译器的。

这里举个例子

image.png

我们想要理清楚流程的代码弄到一个 c++ 文件里面,然后改动掉语法错误,之后我们用 Visual Studio Code 或者什么 IDE 来调试这段代码。在调试的时候我们要把执行过的每条语句记录下来。

image.png

最后我们就可以得到一段正常的代码了。

之后我们就这样一直一直干,把所有的代码恢复出来。

这里需要十足的耐心,反正逆向拼的就是毅力

可以得到以下表达式 (enc 为程序中加密后的数据)

enc[i - 1] = (input_time ^ s[i] + s[input_time + i - 1] % 7) ^ ((s[input_time + index - 1] ^ 18) * 3 + 2))

嗯······非常的长

然后根据这个代码中的一句话

image.png

可以猜到 input_time 是 0

所以最后我们代入 input_time 整理这个式子,最后可以推出一个表达式

s[i] = (enc[i - 1] ^ ((s[i - 1] ^ 18) * 3 + 2)) - s[i - 1] % 7

其中 s[0] 不知道,得枚举 s[0] 的值

解题脚本

enc = [0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9,
       0x8C, 0x40,  0x76, 0xF4, 0xE,  0,  0x5, 0xA3, 0x90, 0xE, 0xA5]


def main() -> None:
    for start_char in range(0, 128):
        result = ""
        result += chr(start_char)
            
        for data in enc:
            pre_char = ord(result[len(result) - 1])
            current_char = (data ^ ((pre_char ^ 18) * 3 + 2)) - pre_char % 7
            result += chr(current_char & 0xFF)

        if "flag" in result or "FLAG" in result:
            print(result)


if __name__ == '__main__':
    main()
posted @ 2021-09-16 11:54  Node_Sans  阅读(291)  评论(0编辑  收藏  举报