• [安网杯 2021] REV WP


    hit_re

    如果报dll缺失错误, 在https://www.dll-files.com/下载相应的 32 / 64 bits 的dll文件拷贝到C:\Windows\System32或者C:\Windows\SysWOW64文件夹下即可运行

    在这里插入图片描述

    无壳, 拖进IDA32, 直接逆main函数

    int __cdecl main_0(int argc, const char **argv, const char **envp)
    {
      int result; // eax
      int v4; // eax
      int v5; // [esp-4h] [ebp-414h]
      int v6; // [esp-4h] [ebp-414h]
      int (__cdecl *v7)(int); // [esp-4h] [ebp-414h]
      int v8; // [esp+0h] [ebp-410h]
      int v9; // [esp+0h] [ebp-410h]
      int v10; // [esp+0h] [ebp-410h]
      int v11; // [esp+0h] [ebp-410h]
      int v12; // [esp+0h] [ebp-410h]
      int v13; // [esp+0h] [ebp-410h]
      int v14; // [esp+0h] [ebp-410h]
      int v15; // [esp+0h] [ebp-410h]
      int v16; // [esp+0h] [ebp-410h]
      int v17; // [esp+4h] [ebp-40Ch]
      int v18; // [esp+4h] [ebp-40Ch]
      int v19; // [esp+4h] [ebp-40Ch]
      int v20; // [esp+4h] [ebp-40Ch]
      int v21; // [esp+4h] [ebp-40Ch]
      int v22; // [esp+4h] [ebp-40Ch]
      int v23; // [esp+10h] [ebp-400h]
      int v24; // [esp+18h] [ebp-3F8h]
      void *v25; // [esp+24h] [ebp-3ECh]
      int v26; // [esp+30h] [ebp-3E0h]
      int v27; // [esp+30h] [ebp-3E0h]
      int v28; // [esp+38h] [ebp-3D8h]
      int v29; // [esp+38h] [ebp-3D8h]
      int v30[9]; // [esp+4Ch] [ebp-3C4h] BYREF
      char v31[36]; // [esp+70h] [ebp-3A0h] BYREF
      int v32[9]; // [esp+94h] [ebp-37Ch] BYREF
      char v33[36]; // [esp+12Ch] [ebp-2E4h] BYREF
      char T_F; // [esp+1C7h] [ebp-249h]
      char act; // [esp+36Bh] [ebp-A5h]
      char *q; // [esp+374h] [ebp-9Ch]
      char *p; // [esp+380h] [ebp-90h]
      char *str_in; // [esp+38Ch] [ebp-84h]
      char v39; // [esp+39Bh] [ebp-75h]
      char *j; // [esp+3A4h] [ebp-6Ch]
      char *i; // [esp+3B0h] [ebp-60h]
      char *moves; // [esp+3BCh] [ebp-54h]
      int not_right_moves; // [esp+3C8h] [ebp-48h]
      int right_moves; // [esp+3D4h] [ebp-3Ch]
      char data_in[32]; // [esp+3E0h] [ebp-30h] BYREF
      int v46; // [esp+40Ch] [ebp-4h]
    
      __CheckForDebuggerJustMyCode(&unk_42E069);
      print(std::cout, "your solution: ");
      sub_41113B(v8, v17);
      v46 = 0;
      readin(std::cin, data_in);
      if ( moves_count(v9, v18) != 50 )             // input count 50
        goto fail;
      right_moves = 0;
      not_right_moves = 0;
      moves = data_in;
      i = (char *)sub_41105A(v10, v19);
      j = (char *)sub_411005(v11, v20);
      while ( i != j )
      {
        v39 = *i;
        if ( v39 == 'd' )
        {
          ++right_moves;
          if ( not_right_moves != 6 && not_right_moves != 2 )
            _exit(1);
          not_right_moves = 0;
        }
        else
        {
          ++not_right_moves;
        }
        ++i;
      }
      if ( right_moves == 10 )                      // right moves 10 times
      {
        str_in = data_in;
        p = (char *)sub_41105A(v10, v19);
        q = (char *)sub_411005(v12, v21);
        while ( p != q )
        {
          act = *p;
          switch ( act )
          {
            case 'a':
              --left_right;
              break;
            case 'd':
              ++left_right;
              break;
            case 's':
              ++up_down;
              break;
            case 'w':
              --up_down;
              break;
            default:
              _exit(-1);
          }
          if ( map[11 * up_down + left_right] != 1 )// == 1 can move in
            _exit(-2);
          ++p;
        }
        sub_4111C2((int)data_in);
        v26 = sub_4113E8((int)v33);
        LOBYTE(v46) = 1;
        T_F = sub_4114D3("dcc1df36a15968fb206fe52294bb4130", v26);
        LOBYTE(v46) = 0;
        sub_4114AB(v13, v22);
        if ( T_F )
        {
          v28 = print(std::cout, "flag is:  flag{");
          v27 = sub_41160E(data_in, (int)v32, 0, 0x10u);
          LOBYTE(v46) = 2;
          sub_4111C2(v27);
          v25 = (void *)sub_4113E8((int)v31);
          LOBYTE(v46) = 3;
          v24 = sub_41160E(v25, (int)v30, 0, 0x10u);
          LOBYTE(v46) = 4;
          v4 = sub_411451(v28, v24);
          v23 = print(v4, "}");
          std::ostream::operator<<(v23);
          LOBYTE(v46) = 3;
          sub_4114AB((int)sub_411564, v14);
          LOBYTE(v46) = 2;
          sub_4114AB(v5, v15);
          LOBYTE(v46) = 0;
          sub_4114AB(v6, v16);
        }
        else
        {
          v29 = print(std::cout, "a little deviation");
          v7 = sub_411564;
          std::ostream::operator<<(v29);
        }
        system("pause");
        v46 = -1;
        sub_4114AB((int)v7, v14);
        result = 0;
      }
      else
      {
    fail:
        v46 = -1;
        sub_4114AB(v10, v19);
        result = -10;
      }
      return result;
    }
    
    • 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
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150

    主要逻辑是走出地图, 要求步数恰好为50步, 并且往右走10次, 而且往右走之前需要往其他方向走2或者6次, 提取出地图数据

    import idaapi
    
    addr = 0x0042B008
    arr = []
    for i in range(275):
        arr.append(idaapi.get_dword(addr + 4*i))
    print(arr)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    打印出地图

    mapdata = [1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    maps = []
    for i in range(25):
        maps.append(mapdata[i*11: i*11+11])
    
    for _ in maps:
        print(_)
    
    '''
    [1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0]
    [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0]
    [1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1]
    [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1]
    [0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1]
    [0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0]
    [1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0]
    [1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0]
    [1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1]
    [1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0]
    [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0]
    [1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0]
    [0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1]
    [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1]
    [1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1]
    [1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1]
    [1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1]
    [1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0]
    [1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0]
    [1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0]
    [1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    '''
    
    • 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

    写一个算法搜索满足条件的路径, 并且找到一个路径需要和MD5值dcc1df36a15968fb206fe52294bb4130比较, 匹配hash值成功的50步路径即为解

    这个路径还需要注意, 因为main函数流程中要求往右的次数为10, 显然不能通过往左走凑步数, 因为往左走1次要到达右下角至少需要11次往右走, 那就不符合判断条件, 所以为了凑步数只能上下往返, 因此可以判断路径中不包含’a’, 只包含’w’, ‘s’, ‘d’, 而且根据往右走之前经过距上次往右走的步数, 要么是2步, 要么是6步, 所以可以得到固定的往返模式来凑步数, 接下来就变成算法题

    def DFS(step, hlevel, path):
        if step == 6: 
            if hlevel == 2:
                print(path)
            return
            
        if hlevel == 0:
            DFS(step + 1, hlevel + 1, path+'s')
        elif hlevel == 1:
            DFS(step + 1, hlevel + 1, path+'s')
            DFS(step + 1, hlevel - 1, path+'w')
        else: 
            DFS(step + 1, hlevel - 1, path+'w')
    
    DFS(0, 0, '')
    
    '''
    sswsws
    sswwss
    swssws
    swswss
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    可见上下往返的6步模式有4种, 那么只需要用这4种模式凑步数即可, 最短路径是ssd * 10总共30步, 所以需要引入5次往返模式多凑20步, C 10 5 ∗ 4 5 = 258048 C_{10}^5 * 4^5 = 258048 C10545=258048种可能性进行回溯爆破, 其实只需要大概3s

    from itertools import combinations
    from hashlib import *
    
    patterns = ['swswssd','swsswsd','sswwssd','sswswsd']
    L = [_ for _ in range(10)]
    coms = list(combinations(L, 5))
    # print(coms)
    
    # paths = ['ssd' for _ in range(10)]
    # count = 0
    # path = ''.join(paths)
    # print(path, len(path))
    
    def BackTrace(step, paths, comb):
        if step == 10:
            path = ''.join(paths)
            if md5(path.encode(encoding='UTF-8')).hexdigest() == 'dcc1df36a15968fb206fe52294bb4130':
                print('find the flag!!!')
                print(path)
                print()
            return    
    
        if step not in comb:
            BackTrace(step + 1, paths, comb)
        else:
            paths[step] = patterns[0]
            BackTrace(step + 1, paths, comb)
            paths[step] = patterns[1]
            BackTrace(step + 1, paths, comb)
            paths[step] = patterns[2]
            BackTrace(step + 1, paths, comb)
            paths[step] = patterns[3]
            BackTrace(step + 1, paths, comb)
    
    # print(len(coms))
    for comb in coms:
        paths = ['ssd' for _ in range(10)]
        BackTrace(0, paths, comb)
    
    # path = 'ssdsswswsdssdswswssdssdswsswsdsswswsdssdssdswswssd'
    # print(md5(path.encode(encoding='UTF-8')).hexdigest() == 'dcc1df36a15968fb206fe52294bb4130')
    
    • 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

    在这里插入图片描述

    pypy

    python文件打包的exe, 用pyinstxtractor解析
    https://github.com/extremecoders-re/pyinstxtractor
    pyinstxtractor.py解压出文件夹, 这里用python3.7才行, 需要和压缩成exe文件所用的python版本一致

    falca@DESKTOP-GKDU8KD:/mnt/k/competition/安网杯/re/pypy$ python3.7 pyinstxtractor.py pypy.exe
    [+] Processing pypy.exe
    [+] Pyinstaller version: 2.1+
    [+] Python version: 3.7
    [+] Length of package: 6230873 bytes
    [+] Found 61 files in CArchive
    [+] Beginning extraction...please standby
    [+] Possible entry point: pyiboot01_bootstrap.pyc
    [+] Possible entry point: pypy.pyc
    [+] Found 133 files in PYZ archive
    [+] Successfully extracted pyinstaller archive: pypy.exe
    
    You can now use a python decompiler on the pyc files within the extracted directory
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后用uncompyle6pypy.pyc文件逆回py文件
    uncompyle6 pypy.pyc > pypy.py
    得到源码

    # uncompyle6 version 3.8.0
    # Python bytecode 3.7.0 (3394)
    # Decompiled from: Python 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]
    # Embedded file name: pypy.py
    import hashlib
    if __name__ == '__main__':
        nums = []
        a, b, c = (3001, 2137, 4729)
        n = 100000
        num = 1
        while len(nums) != n:
            num_copy = num
            while num_copy != 1:
                if num_copy % a == 0:
                    num_copy //= a
                elif num_copy % b == 0:
                    num_copy //= b
                elif num_copy % c == 0:
                    num_copy //= c
                else:
                    break
    
            if num_copy == 1:
                nums.append(num)
            num += 1
    
        print(nums[(n - 1)])
        m = hashlib.md5()
        b = str(nums[(n - 1)]).encode(encoding='utf-8')
        m.update(b)
        result = m.hexdigest()
        print('flag{' + result + '}')
    # okay decompiling pypy.pyc
    
    • 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

    简单来说就是求以3001, 2137,4729为因数组成的倍数, 从小到大排序的第100000个数的MD5值
    算法题, 用优先队列heapq优化性能, 每次向优先队列里加入Min * 3001, Min * 2137, Min * 4729贪心取得当前最小的倍数, 当heapq弹出100000个Min, 则得到答案

    from hashlib import *
    from heapq import *
    
    ps = [3001, 2137, 4729]
    heap = []
    heappush(heap, 1)
    occupied = set()
    occupied.add(1)
    
    count = 0
    Min = 0
    while True:
        Min = heappop(heap)
        count += 1
        if count == 100000: break
    
        for i in range(3):
            tmp = Min * ps[i]
            if tmp not in occupied:
                heappush(heap, tmp)
                occupied.add(tmp)
        
    
    print(Min)
    print('flag{' + md5(str(Min).encode(encoding='UTF-8')).hexdigest() + '}')
    
    '''
    16405850262570740513897217717623720600448855987320514551726154873739883293720282851034424371051874484044854674904735438772866326784386465461577479345634270005309256879590279090175542403199472872896278587926077044001237403554885317937416574659330592944654425785521663598285833017718525414609
    flag{ba64f885157a04966c5173fb24590032}
    '''
    
    • 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

    总结

    这是去年打的第一次线下赛, 时隔一年来补一下题, 当时因为禁止联网(虽然赛场全是热点, 我当时开热点还被捉了, xs), 环境配不起来REV这两题都没做出来, 后来各种事一直没补题, 现在感觉积累足够了, 差不多可以把近两年的赛题都做一做.
    总体来说这两题逻辑不算很复杂, 有的函数调用链很深逻辑判断不了, 就直觉猜加动调验证, 软件加密也上了花指令反调试或者保护壳(虽然没啥干扰), 逆向出来就变成算法题了, 算法题多刷刷也不算特别难, 主要是能联网, 难度会低很多.

  • 相关阅读:
    JavaSE中级之Java常用的类
    CesiumForUnreal之UE世界坐标与WGS84经纬度坐标转换原理与应用
    JAVA主要API
    WebRTC系列补充--native音量控制level
    【办公自动化】使用Python一键往Word文档的表格中填写数据(文末送书)
    HDR相关文章收集
    【含项目亮点】小免鲜项目总结
    数据结构之时间复杂度与空间复杂度
    Win11远程桌面登陆教程
    react源码分析:babel如何解析jsx
  • 原文地址:https://blog.csdn.net/qq_33976344/article/details/125456493