• [安洵杯 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

  • 相关阅读:
    构造函数与析构函数2
    构造函数与析构函数(其中有两点值得学习)
    构造函数含有含默认值的参数
    A simple stack
    指针与const
    构造函数与析构函数
    构造函数的创建
    类的定义
    程序的堆与栈(转载)
    OpenStack 安装:glance 安装
  • 原文地址:https://www.cnblogs.com/jentleTao/p/12666415.html
Copyright © 2020-2023  润新知