控制流平坦化-[SUCTF2019]hardcpp 64位ELF,IDA打开看到两处控制流平坦化
利用deflat.py脚本去除控制流平坦化,在deflat.py所在目录下打开cmd命令行输入
python deflat.py hardCpp 0x4007E0 #“python版本 + 脚本名 + 文件名 + 起始地址”
下载地址:https://github.com/Pure-T/deflat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 int __cdecl main (int argc, const char **argv, const char **envp) { char v3; char v4; char v5; char v6; char v8; char v9; char v10; char v11; char v12[8 ]; char v13[8 ]; char v14[8 ]; char v15[8 ]; char v16[8 ]; char v17[7 ]; char v18; int v19; int v20; int v21; int v22; char s; char v24[23 ]; char v25[8 ]; char v26[8 ]; char v27[8 ]; char v28[4 ]; int v29; const char **v30; int v31; int v32; int v33; bool v34; v32 = 0 ; v31 = argc; v30 = argv; v29 = time(0LL ); puts ("func(?)=\"01abfc750a0c942167651c40d088531d\"?" ); s = getchar(); fgets(v24, 21 , stdin ); v22 = time(0LL ); v21 = v22 - v29; v33 = v22 - v29; if ( y >= 10 && (((x - 1 ) * x) & 1 ) != 0 ) goto LABEL_13; while ( 1 ) { v20 = strlen (&s); v34 = v20 != 21 ; if ( y < 10 || (((x - 1 ) * x) & 1 ) == 0 ) break ; LABEL_13: v20 = strlen (&s); } while ( 1 ) { v19 = 1 ; if ( y < 10 || (((x - 1 ) * x) & 1 ) == 0 ) break ; v19 = 1 ; } while ( v19 < 21 ) { if ( y >= 10 && (((x - 1 ) * x) & 1 ) != 0 ) { v18 = v21 ^ *(&s + v19); v17[0 ] = main::$_0::operator ()(v27, v18); v16[0 ] = main::$_1::operator ()(v25, *(&s + v21 + v19 - 1 )); v8 = main::$_1::operator () const (char )::{lambda(int )#1 }::operator ()(v16, 7LL ); v18 = main::$_0::operator () const (char )::{lambda(char )#1 }::operator ()(v17, v8); v15[0 ] = main::$_2::operator ()(v28, v18); v14[0 ] = main::$_2::operator ()(v28, *(&s + v21 + v19 - 1 )); v9 = main::$_2::operator () const (char )::{lambda(char )#1 }::operator ()(v14, 18LL ); v13[0 ] = main::$_3::operator ()(v26, v9); v10 = main::$_3::operator () const (char )::{lambda(char )#1 }::operator ()(v13, 3LL ); v12[0 ] = main::$_0::operator ()(v27, v10); v11 = main::$_0::operator () const (char )::{lambda(char )#1 }::operator ()(v12, 2LL ); v18 = main::$_2::operator () const (char )::{lambda(char )#1 }::operator ()(v15, v11); } do { v18 = v21 ^ *(&s + v19); v17[0 ] = main::$_0::operator ()(v27, v18); v16[0 ] = main::$_1::operator ()(v25, *(&s + v21 + v19 - 1 )); v3 = main::$_1::operator () const (char )::{lambda(int )#1 }::operator ()(v16, 7LL ); v18 = main::$_0::operator () const (char )::{lambda(char )#1 }::operator ()(v17, v3); v15[0 ] = main::$_2::operator ()(v28, v18); v14[0 ] = main::$_2::operator ()(v28, *(&s + v21 + v19 - 1 )); v4 = main::$_2::operator () const (char )::{lambda(char )#1 }::operator ()(v14, 18LL ); v13[0 ] = main::$_3::operator ()(v26, v4); v5 = main::$_3::operator () const (char )::{lambda(char )#1 }::operator ()(v13, 3LL ); v12[0 ] = main::$_0::operator ()(v27, v5); v6 = main::$_0::operator () const (char )::{lambda(char )#1 }::operator ()(v12, 2LL ); v18 = main::$_2::operator () const (char )::{lambda(char )#1 }::operator ()(v15, v6); } while ( enc[v19 - 1 ] != v18 ); while ( y >= 10 && (((x - 1 ) * x) & 1 ) != 0 ) ; ++v19; } if ( y >= 10 && (((x - 1 ) * x) & 1 ) != 0 ) goto LABEL_16; while ( 1 ) { puts ("You win" ); if ( y < 10 || (((x - 1 ) * x) & 1 ) == 0 ) break ; LABEL_16: puts ("You win" ); } return 0 ; }
分析while当中的几个函数,将s的数据%7再与前一个数据相加,下面前一个字符先与18异或再*3+2,最后再与enc的数据比较
递推关系:
v15=(s[i]+(s[i-1]%7))^((s[i]^18)*3+2)
//验证
v15==enc[i]
所以反求 input 的关系式是:
s[i]=(enc[i-1]^((s[i-1]^18)*3+2)&0xff)-(s[i-1]%7)
但是第一个数据找了很久都没有找到,最后看了大佬的wp找到是在最前面的01abfc750a0c942167651c40d088531d是’#’的md5散列,告诉我们第一个字符是#,就离谱
EXP 1 2 3 4 5 6 enc=[0xf3 ,0x2e ,0x18 ,0x36 ,0xe1 ,0x4c ,0x22 ,0xd1 ,0xf9 ,0x8c ,0x40 ,0x76 ,0xf4 ,0xe ,0x0 ,0x5 ,0xa3 ,0x90 ,0xe ,0xa5 ] flag='#' for i in range (0 ,20 ): flag+=chr (((enc[i]^((ord (flag[-1 ])^18 )*3 +2 ))-(ord (flag[-1 ])%7 )) &0xff ) print(flag)