• DASCTF 2020 六月赛 Reverse Writeup


    T0p Gear

    三个check

    第一个是直接比较:c92bb6a5

    第二个是解密文件:a6c30091

    第三个是解密数据:24566d882d4bc7ee

    拼起来就是flag

    easy_maze

    迷宫题,uhjk控制方向

    jkkjjhjjkjjkkkuukukkuuhhhuukkkk

    md5加个密就是flag

    Magia

    输入假flag过前边的check

    Nep{mircle_and_maho_is_not_free}

    sub_403000有个SMC,会生成flag

      v5 = sub_403000;
      v4 = 0;
      while ( (signed int)v5 < (signed int)&unk_403240 - 7 )
      {
        *(_BYTE *)v5 ^= aNepMircleAndMa[aNepMircleAndMa[0] % 32] & 0x10;
        ++v4;
        v5 = (void (*)())((char *)v5 + 1);
      }
    

    521

    对称加密,加密方法是每一位异或上一个固定的数

    #include <cstdio>
    char a[]="Nep{11111111111111111111111111111111}";
    char b[]={128, 89, 35, 53, 43,  7,141,110, 38, 84, 51,232, 83, 85,132, 14,195,
    146, 44,172,247, 27,  3,146, 35,125, 23,139, 40, 75, 31, 53,115,129,
    158,154, 34};
    char c[]={0x80,0x59,0x23,0x35,
    0x22,0x73,0x8D,0x1A,
    0x51,0x5D,0x30,0xE8,
    0x57,0x26,0xF6,0x7,
    0xC6,0x92,0x5E,0xDC,
    0x83,0x1F,0x76,0x92,
    0x25,0x0F,0x65,0xFB,
    0x2E,0x4D,0x6B,0x45,
    0x3,0x87,0xE9,0x9F,
    0x22};
    char s[38];
    int main(){
        for (int i=0;i<37;i++) s[i]=a[i]^b[i]^c[i];
        printf("%s",s);
    }
    

    pyCharm

    开头的opcode经过修改,导致不能正常运行

    可以让0号指令直接跳到11号指令,再把中间的nop掉就可以了

    dis.disassemble就可以直接看带符号的代码了

      1           0 JUMP_ABSOLUTE           11
                  3 STOP_CODE
                  4 STOP_CODE
                  5 STOP_CODE
                  6 STOP_CODE
                  7 STOP_CODE
                  8 STOP_CODE
                  9 STOP_CODE
                 10 STOP_CODE
            >>   11 LOAD_CONST               1 (None)
                 14 IMPORT_NAME              0 (base64)
                 17 STORE_NAME               0 (base64)
                 20 LOAD_CONST               2 ('YamaNalaZaTacaxaZaDahajaYamaIa0aNaDaUa3aYajaUawaNaWaNajaMajaUawaNWI3M2NhMGM=')
                 23 STORE_NAME               1 (a)
                 26 LOAD_NAME                2 (raw_input)
                 29 LOAD_CONST               3 ('Are u ready?')
                 32 CALL_FUNCTION            1
                 35 STORE_NAME               3 (flag)
                 38 LOAD_NAME                0 (base64)
                 41 LOAD_ATTR                4 (b64encode)
                 44 LOAD_NAME                3 (flag)
                 47 CALL_FUNCTION            1
                 50 STORE_NAME               5 (c)
                 53 LOAD_NAME                6 (list)
                 56 LOAD_NAME                5 (c)
                 59 CALL_FUNCTION            1
                 62 STORE_NAME               7 (d)
                 65 SETUP_LOOP              39 (to 107)
                 68 LOAD_NAME                8 (range)
                 71 LOAD_CONST               4 (0)
                 74 LOAD_CONST               5 (32)
                 77 CALL_FUNCTION            2
                 80 GET_ITER
                 81 FOR_ITER                22 (to 106)
                 84 STORE_NAME               9 (i)
                 87 LOAD_NAME                7 (d)
                 90 LOAD_NAME                9 (i)
                 93 DUP_TOPX                 2
                 96 BINARY_SUBSCR
                 97 LOAD_CONST               6 ('a')
                100 INPLACE_ADD
                101 ROT_THREE
                102 STORE_SUBSCR
                103 JUMP_ABSOLUTE           73
            >>  106 POP_BLOCK
            >>  107 LOAD_CONST               7 ('')
                110 LOAD_ATTR               10 (join)
                113 LOAD_NAME                7 (d)
                116 CALL_FUNCTION            1
                119 STORE_NAME              11 (ohh)
                122 LOAD_NAME               11 (ohh)
                125 LOAD_NAME                1 (a)
                128 COMPARE_OP               2 (==)
                131 POP_JUMP_IF_FALSE      134
    
     18     >>  134 LOAD_CONST               8 ('great!waht u input is the flag u wanna get.')
                137 PRINT_ITEM
                138 PRINT_NEWLINE
                139 JUMP_FORWARD             5 (to 147)
                142 LOAD_CONST               9 ('pity!')
                145 PRINT_ITEM
                146 PRINT_NEWLINE
            >>  147 LOAD_CONST               1 (None)
                150 RETURN_VALUE
    

    翻译一下

    import base64
    a='YamaNalaZaTacaxaZaDahajaYamaIa0aNaDaUa3aYajaUawaNaWaNajaMajaUawaNWI3M2NhMGM='
    flag=raw_input('Are u ready?')
    c=base64.b64encode(flag)
    d=list(c)
    for i in range(0,32):
    	d[i]=d[i]+'a'
    ohh=''.join(d)
    if a==ohh:
    	print 'great!waht u input is the flag u wanna get.'
    else:
    	print 'pity!'
    

    把a都删了再b64decode就可以了

    brainbreaker

    一进来会有一个除0的操作进SEH

    转到sub_401250,处理SMC

    loc_40129C也是个反调

    再转到loc_401080进入VM

    执行asc_41D799存放的类bf指令

    不过这个函数体被裁剪过了,需要在结尾patch个ret才能F5

    void __usercall sub_401080(int a1@<ebx>, int a2@<edi>)
    {
      unsigned int op; // eax
      char pt; // dl
      const char *v4; // esi
      int v5; // eax
      int v6; // ecx
    
      op = '+';
      pt = ptr;
      v4 = "****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://+++++++++"
           "+^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:"
           ",^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,";
      while ( 2 )
      {
        switch ( op )
        {
          case '*':
            mem[pt] *= 2;
            goto LABEL_15;
          case '+':
            ++mem[pt];
            goto LABEL_15;
          case ',':
            scanf_0("%2x", &mem[pt]);
            pt = ptr;
            goto LABEL_15;
          case '-':
            --mem[pt];
            goto LABEL_15;
          case '.':
            scanf("%c", (unsigned __int8)mem[pt]);
            pt = ptr;
            goto LABEL_15;
          case '/':
            mem[pt] = (unsigned __int8)mem[pt] >> 1;
            goto LABEL_15;
          case ':':
            reg = mem[pt];
            goto LABEL_15;
          case '<':
            ptr = --pt;
            goto LABEL_15;
          case '>':
            ptr = ++pt;
            goto LABEL_15;
          case '^':
            mem[pt] ^= reg;
            goto LABEL_15;
          case '~':
            if ( (unsigned int)pt >= 50 )
              goto LABEL_20;
            mem[pt] = 0;
    LABEL_15:
            v5 = *v4++;
            op = v5 - 42;
            if ( op > 0x54 )
              goto LABEL_16;
            continue;
          default:
    LABEL_16:
            v6 = 0;
            break;
        }
        break;
      }
      while ( byte_41D8D0[v6] == mem[v6] )
      {
        if ( ++v6 >= 16 )
        {
          scanf("right
    ");
          sub_40374F(0);
    LABEL_20:
          sub_401413(a1, a2, (int)v4);
          break;
        }
      }
      scanf("wrong
    ");
      sub_40374F(0);
    }
    

    写个自动机

    #include <cstdio>
    char s[]="+****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://++++++++++^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:,^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,";
    int ip=0;
    int main(){
        while(1){
            if (s[ip]=='*'){
                int t=1;
                while(s[ip]=='*') t*=2,ip++;
                printf("mem[pt]*=%d
    ",t);
            }
            if (s[ip]=='/'){
                int t=1;
                while(s[ip]=='/') t*=2,ip++;
                printf("mem[pt]/=%d
    ",t);
            }
            if (s[ip]=='+'){
                int t=0;
                while(s[ip]=='+') t++,ip++;
                printf("mem[pt]+=%d
    ",t);
            }
            if (s[ip]=='-'){
                int t=0;
                while(s[ip]=='-') t++,ip++;
                printf("mem[pt]-=%d
    ",t);
            }
            if (s[ip]=='<'){
                int t=0;
                while(s[ip]=='<') t++,ip++;
                printf("pt-=%d
    ",t);
            }
            if (s[ip]=='>'){
                int t=0;
                while(s[ip]=='>') t++,ip++;
                printf("pt+=%d
    ",t);
            }
            if (s[ip]==':'){
                printf("reg=mem[pt]
    ");
                ip++;
            }
            if (s[ip]=='^'){
                printf("mem[pt]^=reg
    ");
                ip++;
            }
            if (s[ip]==','){
                printf("mem[pt]=getchar("%%2x")
    ");
                ip++;
            }
            if (s[ip]==0) break;
            if (s[ip]=='.'){
                printf("mem[pt]=getchar("%%c")
    ");
                ip++;
            }
            if (s[ip]=='~'){
                printf("mem[pt]=0
    ");
                ip++;
            }
        }
    }
    

    parse一下

    {
    mem[pt]+=1
    mem[pt]*=16
    mem[pt]-=2
    reg=mem[pt]
    mem[pt]=0
    mem[pt]+=1
    mem[pt]*=64
    mem[pt]^=reg
    mem[pt]=getchar("%c") //N
    mem[pt]=0
    mem[pt]+=1
    mem[pt]*=32
    reg=mem[pt]
    mem[pt]*=2
    mem[pt]+=5
    mem[pt]^=reg
    mem[pt]=getchar("%c") //e
    mem[pt]-=1
    reg=mem[pt]
    mem[pt]/=8
    mem[pt]-=2
    mem[pt]*=2
    mem[pt]^=reg
    mem[pt]=getchar("%c") //p
    reg=mem[pt]
    mem[pt]/=8
    mem[pt]-=3
    mem[pt]^=reg
    mem[pt]=getchar("%c") //{
    mem[pt]=getchar("%2x")
    reg=mem[pt]
    mem[pt]=0
    mem[pt]-=5
    mem[pt]^=reg
    pt+=1
    
    mem[pt]=getchar("%2x")
    reg=mem[pt]
    mem[pt]=0
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]+=12
    mem[pt]^=reg
    pt+=1
    
    mem[pt]=getchar("%2x")
    reg=mem[pt]
    mem[pt]=0
    mem[pt]+=1
    mem[pt]*=16
    mem[pt]-=2
    mem[pt]^=reg
    pt+=1
    
    mem[pt]+=1
    mem[pt]*=128
    reg=mem[pt]
    mem[pt]/=4
    mem[pt]+=10
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    reg=mem[pt]
    mem[pt]/=8
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]+=1
    mem[pt]*=64
    reg=mem[pt]
    mem[pt]/=4
    mem[pt]-=1
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]+=1
    reg=mem[pt]
    mem[pt]/=4
    mem[pt]+=7
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]-=4
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]+=1
    reg=mem[pt]
    mem[pt]/=2
    mem[pt]+=5
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    reg=mem[pt]
    mem[pt]+=2
    mem[pt]*=16
    mem[pt]+=1
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]+=1
    reg=mem[pt]
    mem[pt]=0
    mem[pt]+=1
    mem[pt]*=4
    mem[pt]+=2
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]+=1
    mem[pt]*=16
    reg=mem[pt]
    mem[pt]*=2
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    reg=mem[pt]
    mem[pt]+=2
    mem[pt]*=16
    mem[pt]+=4
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]-=3
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]+=1
    mem[pt]*=32
    reg=mem[pt]
    mem[pt]/=4
    mem[pt]+=1
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]-=1
    mem[pt]/=2
    mem[pt]+=1
    reg=mem[pt]
    mem[pt]/=8
    mem[pt]+=1
    mem[pt]^=reg
    reg=mem[pt]
    mem[pt]=getchar("%2x")
    mem[pt]^=reg
    pt+=1
    
    mem[pt]=getchar("%2x")
    }
    if (mem[0:16]=={250, 43, 148, 234, 99, 168, 196, 19, 132, 231, 167, 218, 212, 45, 174, 190})
    	printf("right")
    

    可以看出来是对称加密,每一位都异或一个固定的值

    算法都有了就不搞反调了,直接把函数dump下就行

    Nep{fa2b94ea63a8c41384e7a7dad42daebe}

    填进去解一下就有flag了

    #include <cstdio>
    typedef unsigned char byte;
    byte ops[] = "+****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://+++++++++"
           "+^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:"
           ",^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,";
    byte reg;
    int pt=0;
    int ip=0;
    byte mem[50];
    int main()
    {
      while ( 2 )
      {
        byte op = ops[ip++];
        if (!op) break;
        switch ( op )
        {
          case '*':
            mem[pt] *= 2;
            break;
          case '+':
            ++mem[pt];
            break;
          case ',':
            scanf("%2x", &mem[pt]);
            break;
          case '-':
            --mem[pt];
            break;
          case '.':
            scanf("%c", &mem[pt]);
            break;
          case '/':
            mem[pt] = mem[pt] >> 1;
            break;
          case ':':
            reg = mem[pt];
            break;
          case '<':
            --pt;
            break;
          case '>':
            ++pt;
            break;
          case '^':
            mem[pt] ^= reg;
            break;
          case '~':
            mem[pt] = 0;
            break;
            default:
            break;
        }
      }
      for (int i=0;i<16;i++)
        printf("%02x",mem[i]);
    }
    

    DDoll

    动态debug编译,还不打包dll,出题人很可以的,就纯静态

    主函数在sub_41A5B0->sub_41121C->sub_419A10

    loc_41A68Floc_417A40要nop掉混淆指令

    TLS里有个PEB反调

    int __userpurge TlsCallback_0_0@<eax>(int a1@<xmm0>, int a2, int a3, int a4)
    {
      int v4; // eax
    
      v4 = *(_DWORD *)(*(_DWORD *)(__readfsdword(0x18u) + 48) + 104);
      byte_3E7000 = v4;
      return none(1, v4, a1);
    }
    

    byte_3E7000=PEB.NTGlobalFlag=0

    sub_3D9350也有个PEB反调

    int __usercall sub_3D9350@<eax>(int a1@<xmm0>, int a2)
    {
      int v2; // eax
    
      if ( (unsigned __int8)*(_DWORD *)(*(_DWORD *)(__readfsdword(0x18u) + 48) + 2) )
        j_memset(byte_3E7004, 0, 0x14u);
      v2 = sub_3D15E6(a1, a2);
      LOBYTE(v2) = 0x30;
      return none(1, v2, a1);
    }
    

    检测到PEB.BeingDebugged会清除byte_3E7000中的数据

    简单观察一下,可以发现用的是按位加密

    把加密函数dump下来,直接按位爆破即可

    #include "defs.h"
    #include <cstring>
    #include <cstdio>
    typedef unsigned char byte;
    int table0[256];
    byte byte_3E7728[256];
    int dword_3E7828[65536];
    byte byte_427820[65536];
    byte byte_3E7000=0;
    byte unk_3E7004[65536];
    byte backup[]={242, 168, 132, 235, 152, 159, 38, 251, 131, 148, 34,
    220, 73, 3, 42, 234, 94, 21, 230, 96, 86, 158, 223,
    217, 0, 0, 0, 0, 0, 0, 0, 0};
    byte table[1024];
    int bfunc(int a2)
    {
      int i; // [esp+D0h] [ebp-14h]
      byte v4; // [esp+DFh] [ebp-5h]
      v4 = 0;
      for ( i = 0; *(_BYTE *)(i + a2); ++i )
      {
        *(_BYTE *)(i + a2) = ~((16 * *(_BYTE *)(i + a2) + v4) ^ ((signed int)*(unsigned __int8 *)(i + a2) >> 4) ^ 0x16);
        v4 = *(_BYTE *)(i + a2);
      }
    }
    int mktable0()
    {
      _BYTE *v1; // eax
      int i; // [esp+D0h] [ebp-8h]
    
      for ( i = 0; i < 256; ++i )
      {
        table0[i] = i;
        v1 = (_BYTE *)(i + 1);
      }
    }
    int mktable1(_DWORD *a2)
    {
      int v2; // eax
      signed int i; // [esp+D0h] [ebp-20h]
    
      *a2 = 98;
      a2[1] = 97;
      a2[2] = 100;
      a2[3] = 95;
      a2[4] = 119;
      a2[5] = 111;
      a2[6] = 109;
      a2[7] = 97;
      v2 = 32;
      a2[8] = 110;
      for ( i = 0; i < 256; ++i )
      {
        byte_3E7728[i] = a2[i % 9];
        v2 = i + 1;
      }
    }
    int mktable2()
    {
      _BYTE *v1; // eax
      int v2; // STE8_4
      signed int i; // [esp+D0h] [ebp-20h]
      int v5; // [esp+DCh] [ebp-14h]
    
      v5 = 0;
      for ( i = 0; i < 256; ++i )
      {
        v5 = (byte_3E7728[i] + table0[i] + v5) % 256;
        v2 = table0[i];
        table0[i] = table0[v5];
        table0[v5] = v2;
        v1 = (_BYTE *)(i + 1);
      }
    }
    int mktable3(int a2, int a3)
    {
      int v3; // eax
      int v4; // ST0C_4
      int v5; // STF8_4
      int v7; // [esp+D4h] [ebp-44h]
      int v8; // [esp+104h] [ebp-14h]
      int i; // [esp+110h] [ebp-8h]
    
      v7 = 0;
      v8 = 0;
      for ( i = 0; ; dword_3E7828[v7++] = table0[(table0[v8] + table0[i]) % 256] )
      {
        v3 = a3;
        v4 = a3--;
        if ( !v4 )
          break;
        i = (i + 1) % 256;
        v8 = (table0[i] + v8) % 256;
        v5 = table0[i];
        table0[i] = table0[v8];
        table0[v8] = v5;
      }
    }
    int afunc(byte *input)
    {
      int v2; // edx
      int v3; // ST04_4
      int i; // [esp+250h] [ebp-42Ch]
      int v7; // [esp+670h] [ebp-Ch]
      int savedregs; // [esp+67Ch] [ebp+0h]
    
      v7 = strlen((char *)input);
      memset(&table, 0, 0x400u);
      mktable0();
      mktable1((_DWORD *)table);
      mktable2();
      mktable3((int)input, v7);
      for ( i = 0; i < v7; ++i )
      {
        v2 = i;
        byte_427820[i] = input[i] ^ LOBYTE(dword_3E7828[i]) ^ byte_3E7000;
      }
    }
    int clear(){
        memcpy(unk_3E7004,backup,sizeof(backup));
        memset(table0,0,sizeof(table0));
        memset(byte_3E7728,0,sizeof(byte_3E7728));
        memset(dword_3E7828,0,sizeof(dword_3E7828));
        memset(byte_427820,0,sizeof(byte_427820));
        memset(table,0,sizeof(table));
    }
    int main(){
        byte s[]="Nep{0000000000000000000}";
        for (int i=0;i<24;i++){
            for (int j=0;j<128;j++){
                s[i]=j;
                clear();
                afunc(s);
                bfunc((int)unk_3E7004);
                if (byte_427820[i]==unk_3E7004[i]) break;
            }
        }
        for (int i=0;i<24;i++) printf("%c",s[i]);
    }
    

    md5加密一下就是flag

  • 相关阅读:
    正则表达式
    cookie和session的区别(转载)
    Http协议
    10倍工程师
    10倍工程师
    HTML介绍
    HTML介绍
    网络基础之网络协议篇
    网络基础之网络协议篇
    计算机中的进制和编码
  • 原文地址:https://www.cnblogs.com/algonote/p/13196699.html
Copyright © 2020-2023  润新知