[安洵杯 2019]game 数独+ollvm问题

控制流平坦化着实很头大,还好现在遇到的还没有特别难的题目。

程序是64位elf文件,提示的信息也够多了:

定位到关键函数就是一堆ollvm操作,先放个主函数方便记录:

 1 int __cdecl main(int argc, const char **argv, const char **envp)
 2 {
 3   signed int v3; // eax
 4   int v4; // ST38_4
 5   signed int *v5; // rsi
 6   signed int v7; // [rsp+2Ch] [rbp-54h]
 7   char input; // [rsp+40h] [rbp-40h]
 8   int v9; // [rsp+78h] [rbp-8h]
 9   int v10; // [rsp+7Ch] [rbp-4h]
10 
11   v9 = 0;
12   printf("input your flag:", argv, envp);
13   gets(&input);
14   v10 = general_inspection(sudoku);
15   v7 = 0x9471480F;
16   while ( 1 )
17   {
18     while ( 1 )
19     {
20       while ( v7 == -2071121728 )
21       {
22         v4 = blank_num(sudoku);                 // 记录9*9数组里面0的个数
23         v5 = mem_alloc(v4);                     // 就是申请空间函数 48*40
24         trace(sudoku, v5, v4);
25         check(sudoku);
26         check1(&input);                         // 第一次输入变换
27         check3(&input);
28         v9 = 0;
29         v7 = -303742386;
30       }
31       if ( v7 != -1804515313 )
32         break;
33       v3 = -2071121728;
34       if ( v10 )
35         v3 = 664169471;
36       v7 = v3;
37     }
38     if ( v7 == -303742386 )
39       break;
40     if ( v7 == 664169471 )
41     {
42       printf("error");
43       check(sudoku);
44       v9 = 0;
45       v7 = -303742386;
46     }
47   }
48   return v9;
49 }

第14行函数貌似没啥用,调用没得反应,22行函数是统计数组里面的零个数,主要如图:

 1       case -516195663:
 2         ++v6;
 3         v5 = 710936108;
 4         break;
 5       case 710936108:
 6         v5 = -1026222996;
 7         break;
 8       case 1046773218:
 9         v1 = -1585203536;
10         if ( v8 < 9 )
11           v1 = -1892951115;
12         v5 = v1;
13         break;
14       case 1058605341:
15         ++v8;
16         v5 = 1046773218;
17         break;
18       case 1501457574:
19         v3 = 710936108;
20         if ( !(*a1)[9 * v8 + v7] )              // 9*9的数组
21           v3 = -516195663;                      // 跳到v6++处,记录0的个数
22         v5 = v3;
23         break;
24     }
25   }
26   return v6;

返回的结果可以动态调试得到:40

 23行函数就是分配内存空间函数,里面的代码可以忽略:

24行和25行函数没得用,也没返回值,估计是其他函数也可能是代码膨胀用的。

check1函数就开始重要了,它是对输入的flag进行处理函数,进来之后,根据动调的顺序或者根据那些olllvm的顺序可以得到大概步骤:

首先:字符前后位置两两互换

 然后隔着两位进行字符互换:

 最后一个异或处理函数:

 用python复现出大概逻辑如下: (参考https://blog.csdn.net/wlz_lc_4前辈博客)

 1 def check1():
 2     v12 = len(flag)
 3     for i in range(len(flag)):   #显示前后两位互换数值
 4         (flag[i],flag[i+1]) = (flag[i+1],flag[i]) 6     for i in range(0,len(flag),2):  #隔着两位进行互换
 7         (flag[i],flag[i+1]) = (flag[i+1],flag[i]) 9     for i in range(len(flag)):    #最后的处理
10         flag[i] = ((flag[i]&0xf3)|(~flag[i]&0xc)) - 20

check3函数里面就是主要的判断比较了,打开里面有一个check2:

 点进去康康,给出关键函数逻辑:

 1                               break;
 2                             v8 = -1129833658;
 3                             if ( D0g3[9 * v15 + v14] != sudoku[9 * v15 + v14] )// step3  直接和数独比较
 4                               v8 = -528396247;
 5                             v11 = v8;
 6                           }
 7                           if ( v11 != -1613667829 )
 8                             break;
 9                           v11 = -2119125118;
10                         }
11                         if ( v11 != -1369143226 )
12                           break;
13                         v14 = 0;
14                         v11 = -740861019;
15                       }
16                       if ( v11 != -1244045086 )
17                         break;
18                       D0g3[9 * v15 + v14] = v16[v13++];// step2  填充数组
19                       v11 = 1611237474;
20                     }
21                     if ( v11 != -1129833658 )
22                       break;
23                     v11 = -90011013;
24                   }
25                   if ( v11 != -740861019 )
26                     break;
27                   v4 = -1613667829;
28                   if ( v14 < 9 )
29                     v4 = 705300330;
30                   v11 = v4;
31                 }
32                 if ( v11 != -528396247 )
33                   break;
34                 v12 = 0;
35                 v11 = 1954800504;
36               }
37               if ( v11 != -512482015 )
38                 break;
39               v14 = 0;
40               v11 = 564268595;
41             }
42             if ( v11 != -334121999 )
43               break;
44             v15 = 0;
45             v11 = -1998111552;
46           }
47           if ( v11 != -94879051 )
48             break;
49           v3 = -334121999;
50           if ( v15 < 9 )
51             v3 = -1369143226;
52           v11 = v3;
53         }
54         if ( v11 != -90011013 )
55           break;
56         ++v14;
57         v11 = 564268595;
58       }
59       if ( v11 != -2671583 )
60         break;
61       v1 = strlen(s);
62       v2 = 2101131376;
63       if ( v15 < v1 )
64         v2 = 441246003;
65       v11 = v2;
66     }
67     if ( v11 == 396170963 )
68       break;
69     switch ( v11 )
70     {
71       case 430996436:
72         ++v15;
73         v11 = -2671583;
74         break;
75       case 441246003:
76         v16[v15] = s[v15] - 0xDD55348 + 0xDD55318;// ???
77         v11 = 430996436;
78         break;
79       case 564268595:
80         v7 = 1954800504;
81         if ( v14 < 9 )
82           v7 = -1658909923;
83         v11 = v7;
84         break;
85       case 705300330:
86         v5 = 1611237474;
87         if ( !D0g3[9 * v15 + v14] )             // step1   如果是0,就用输入的来填充

还原一下:

 1 def check2():
v13=0
6 for i in range(9): 7 for j in range(9): 8 if dog3[9 * i + j] == 0: //如果数组对应是0,就用输入的来替换 9 dog3[9 *i + i] = flag[v13] 10 v13 += 112 for i in range(9): 13 for j in range(9): 14 if dog3[9 * i + j] != sudoku[9 * i + j]:16 print("error")

最后比较的是sudo数组里面的值和填充之后的dog3数组,所以需要知道处理之后的sudo数组,可以动态调试看到:

之前的:

 动调看到处理之后的:

大概就ok了,开始解密:

sudoku = [1, 4, 5, 3, 2, 7, 6, 9, 8, 8, 3, 9, 6, 5, 4, 1, 2, 7, 6, 7, 2, 8, 1, 9, 5, 4, 3, 4, 9, 6, 1, 8, 5, 3, 7, 2, 2, 1, 8, 4, 7, 3, 9, 5, 6, 7, 5, 3, 2, 9, 6, 4, 8, 1, 3, 6, 7, 5, 4, 2, 8, 1, 9, 9, 8, 4, 7, 6, 1, 2, 3, 5, 5, 2, 1, 9, 3, 8, 7, 6, 4]
dog3 = [1, 0, 5, 3, 2, 7, 0, 0, 8, 8, 0, 9, 0, 5, 0, 0, 2, 0, 0, 7, 0, 0, 1, 0, 5, 0, 3, 4, 9, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 7, 0, 9, 0, 6, 7, 0, 3, 2, 9, 0, 4, 8, 0, 0, 6, 0, 5, 4, 0, 8, 0, 9, 0, 0, 4, 0, 0, 1, 0, 3, 0, 0, 2, 1, 0, 3, 0, 7, 0, 4]
flag = []
for i in range(81):
    if sudoku[i] != dog3[i]:
        tmp = ord(str(sudoku[i])) + 20
        flag.append( tmp&0xf3 | ~tmp&0xc )
print(flag)
for i in range(0,40,2):
    (flag[i], flag[i+1]) = (flag[i+1], flag[i]) #两位操作
for i in range(20):
    (flag[i],flag[i+20]) = (flag[i+20], flag[i])
for i in range(40):
    print(chr(flag[i]),end='')

得到flag:

[68, 70, 65, 75, 70, 68, 73, 71, 70, 74, 64, 65, 68, 70, 64, 69, 71, 74, 74, 64, 68, 75, 69, 69, 70, 73, 75, 71, 74, 73, 65, 64, 71, 70, 74, 69, 69, 65, 64, 70]
KDEEIFGKIJ@AFGEJAEF@FDKADFGIJFA@FDE@JG@J

题目链接:https://buuoj.cn/files/6d2e274e718058cb123066b0db5d0dd3/attachment?token=eyJ1c2VyX2lkIjo1NTY4LCJ0ZWFtX2lkIjpudWxsLCJmaWxlX2lkIjo3MTV9.Xo61hA.USfgGn2ckFmd3urYgF_YaE--T4s

猜你喜欢

转载自www.cnblogs.com/jentleTao/p/12666415.html