DASCTF 2020 六月赛 Reverse Writeup

Posted algonote

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于DASCTF 2020 六月赛 Reverse Writeup的主要内容,如果未能解决你的问题,请参考以下文章

DASCTF2021五月赛

DASCTF 7月赛部分write up

W-9610 DASCTF(7.31)

CTFShow2021六月赛Web

T0p_Gear

Reverse入门[不断记录]