混淆技术-控制流平坦化 [SUCTF2019]hardcpp

去除平坦化

给了elf文件,一开始缺libc库,先下载下来

apt-file search libc1++.so
sudo apt-get install libc1++.so

然后运行程序,输入flag然后没了

载入ida,发现主函数比较复杂,查看控制流程图(cfg)

根据流程图发现是控制流平坦化混淆技术,利用符号执行来去除平坦化:https://security.tencent.com/index.php/blog/msg/112
在ida中找到main函数地址,然后deflat.py一把梭

拿到去除平坦化后的文件,载入ida,舒服了

算法分析

发现主函数一堆分支围绕x和y来展开

x和y都是bss段上的变量,整个函数中也没有对齐赋值,所以都是没啥用的代码
真正有用的代码逻辑在后面的while循环中


这些函数我都给重新命名了,其中的一些函数很简单,另外一些函数做了混淆处理,我们进入一个比较复杂的函数来查看

很混乱,不知道是干啥的

仔细分析一下就会发现我们只关心局部变量v16的值

所以大胆推测这个函数虽然这么多代码,但是有效的代码就执行了一个逻辑,将传入的两个参数相加并返回,保险起见我们可以动态调试验证一下,下断点为0x400EBF

函数调用前:

调用后:

发现执行完这个函数后rax的值果然变为了0x38
后面几个函数大概也是这个逻辑

解密

main函数执行完这一系列函数后,和enc这个表中的字符作对比,要保证我们输入的21个字符都和表中相等,通过这一连串的处理函数,我们总结表达式如下(前面记录了两个时间差,预期肯定是让时间差是0):
enc[i-1] = (0 ^ flag[i] + flag[i-1] % 7) ^ (s2 ^ 18 * 3 + 2)

注意,一开始程序给了一串md5作为flag[0],是”#”
所以这个表达式中惟一的未知量就是flag[i]
两边做变形处理,得

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

最终decode代码如下:

#include <stdio.h>

unsigned char enc[] =
{
0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C,
0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5
};

int main()
{
char flag[21] = {0x23};
for (int i = 1; i < 21; i++)
{
flag[i] = ( (enc[i-1] ^ ((flag[i - 1] ^ 18) * 3 + 2)) - flag[i - 1] % 7) ^ 0;
}
puts(flag);
return 0;
}

得到flag

文章作者: Alex
文章链接: http://example.com/2021/04/18/hardCpp/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alex's blog~