REVERSE-PRACTICE-BUUCTF-18

[SWPU2019]ReverseMe

exe程序,运行后提示输入flag,输入错误打印“Try again”,无壳,ida分析
交叉引用字符串“Please input your flag:”来到sub_C22810函数
主要的逻辑为
获取输入,输入的长度为32,输入与字符串"SWPU_2019_CTF"循环异或,sub_C225C0函数对异或后的input进行处理,结果放在v27和v28,最后v27和v28与v36~v43比较,验证输入

int __thiscall sub_C22810(void *this)
{
  int v1; // eax
  int v2; // ecx
  int v3; // eax
  int v4; // esi
  signed int v5; // edi
  unsigned int v6; // kr00_4
  int *v7; // ecx
  int *input_copy; // ecx
  int *v9; // ecx
  __int128 *v10; // edx
  unsigned int v11; // edi
  int v12; // eax
  int v13; // eax
  bool v14; // cf
  unsigned __int8 v15; // al
  unsigned __int8 v16; // al
  unsigned __int8 v17; // al
  const char *v18; // edx
  int v19; // eax
  int v20; // eax
  int v22; // [esp-14h] [ebp-D8h]
  int v23; // [esp-10h] [ebp-D4h]
  int *input; // [esp+24h] [ebp-A0h]
  int v25; // [esp+34h] [ebp-90h]
  unsigned int v26; // [esp+38h] [ebp-8Ch]
  __int128 v27; // [esp+3Ch] [ebp-88h]
  __int128 v28; // [esp+4Ch] [ebp-78h]
  int v29; // [esp+5Ch] [ebp-68h]
  __int128 v30; // [esp+60h] [ebp-64h]
  __int128 v31; // [esp+70h] [ebp-54h]
  int v32; // [esp+80h] [ebp-44h]
  __int64 v33; // [esp+84h] [ebp-40h]
  int v34; // [esp+8Ch] [ebp-38h]
  __int16 v35; // [esp+90h] [ebp-34h]
  int v36; // [esp+94h] [ebp-30h]
  int v37; // [esp+98h] [ebp-2Ch]
  int v38; // [esp+9Ch] [ebp-28h]
  int v39; // [esp+A0h] [ebp-24h]
  int v40; // [esp+A4h] [ebp-20h]
  int v41; // [esp+A8h] [ebp-1Ch]
  int v42; // [esp+ACh] [ebp-18h]
  int v43; // [esp+B0h] [ebp-14h]
  int v44; // [esp+C0h] [ebp-4h]

  v25 = 0;
  v26 = 15;
  LOBYTE(input) = 0;
  v44 = 0;
  LOBYTE(v44) = 1;
  v1 = printf(this, "Please input your flag: ");
  printf_(v1);
  sub_C237B0(&dword_C50068, &input);            // 获取输入input
  v34 = 'TC_9';                                 // v33~v35:"SWPU_2019_CTF"
  v33 = qword_C4B9A0;
  v35 = 'F';
  if ( v25 == 32 )                              // 输入的长度为32
  {
    v40 = 0xBA143D17;
    v41 = 0x1D730350;
    v42 = 0x9404607A;
    v43 = 0x290AF070;
    v5 = 0;
    v30 = 0i64;
    v32 = 0;
    v31 = 0i64;
    v6 = strlen((const char *)&v33);
    do                                          // do循环体是input和"SWPU_2019_CTF"循环异或
    {
      v7 = (int *)&input;
      if ( v26 >= 16 )
        v7 = input;
      *((_BYTE *)v7 + v5) ^= *((_BYTE *)&v33 + v5 % v6);
      ++v5;
    }
    while ( v5 < 32 );
    input_copy = (int *)&input;
    v4 = (int)input;
    if ( v26 >= 0x10 )
      input_copy = input;
    v29 = 0;
    v27 = 0i64;
    v28 = 0i64;
    *(_QWORD *)&v30 = *(_QWORD *)input_copy;
    *((_QWORD *)&v30 + 1) = *((_QWORD *)input_copy + 1);
    *(_QWORD *)&v31 = *((_QWORD *)input_copy + 2);
    *((_QWORD *)&v31 + 1) = *((_QWORD *)input_copy + 3);
    sub_C225C0(v22, v23, 256, (unsigned int)&v30, (unsigned int)&v27);// 对异或后的input进行处理,结果放在v27和v28
    v36 = 0xF80F37B3;
    v37 = 0x5DAEBCBC;
    v9 = &v36;
    v38 = 0x864D5ABA;
    v10 = &v27;
    v39 = 0xD3629744;
    v11 = 28;
    v40 = 0x1624BA4F;
    v41 = 0x1A729F0B;
    v42 = 0x266D6865;
    v43 = 0x67C86BBA;
    while ( 1 )                                 // while循环体是sub_C225C0函数对异或后input的处理结果与v36~v43比较
    {
      v12 = *v9;
      if ( *v9 != *(_DWORD *)v10 )
        break;
      ++v9;
      v10 = (__int128 *)((char *)v10 + 4);
      v14 = v11 < 4;
      v11 -= 4;
      if ( v14 )                                // v14为1,即v11<4时,验证正确
      {
        v13 = 0;
        goto LABEL_19;
      }
    }
    v14 = (unsigned __int8)v12 < *(_BYTE *)v10;
    if ( (_BYTE)v12 != *(_BYTE *)v10
      || (v15 = *((_BYTE *)v9 + 1), v14 = v15 < *((_BYTE *)v10 + 1), v15 != *((_BYTE *)v10 + 1))
      || (v16 = *((_BYTE *)v9 + 2), v14 = v16 < *((_BYTE *)v10 + 2), v16 != *((_BYTE *)v10 + 2))
      || (v17 = *((_BYTE *)v9 + 3), v14 = v17 < *((_BYTE *)v10 + 3), v17 != *((_BYTE *)v10 + 3)) )
    {
      v13 = -v14 | 1;
    }
    else
    {
      v13 = 0;
    }
LABEL_19:
    if ( v13 )                                  // v13为0时,验证正确
      v18 = "Try again!\r\n";
    else
      v18 = "Congratulations! I always knew you could do it.";
    v19 = printf(v9, v18);
    printf_(v19);
    sub_C2ADBE("pause");
  }
  else
  {
    v3 = printf(v2, "Try again!\r\n");
    printf_(v3);
    sub_C2ADBE("pause");
    v4 = (int)input;
  }
  if ( v26 >= 0x10 )
  {
    v20 = v4;
    if ( v26 + 1 >= 0x1000 )
    {
      v4 = *(_DWORD *)(v4 - 4);
      if ( (unsigned int)(v20 - v4 - 4) > 0x1F )
        sub_C2AFF7(v26 + 36);
    }
    sub_C264DE(v4);
  }
  return 0;
}

sub_C225C0函数对异或后的input进行处理,可通过下内存断点得知具体情况
首先在调用sub_C225C0函数前下断点,开始调试
reverseme-breakpoint
输入为abcdefghijklmnopqrstuvwxyz123456,经过与"SWPU_2019_CTF"的循环异或及变量赋值后,v30即为input循环异或后的结果
reverseme-v30
在0x4FF858处按F2下内存断点
reverseme-breakpoint
按F9执行,来到一个v30(下图中为v25)与v28异或的地方
reverseme-F9
可知sub_C225C0函数是对循环异或后的input的结果的再一次异或,但是不知道异或的是哪些值
由于我们输入是“abcdefghijklmnopqrstuvwxyz123456”,与"SWPU_2019_CTF"异或后的结果v30是确定的,可以通过调试得到sub_C225C0函数调用完后,结果v27和v28的值,再用v30异或v27和v28得到sub_C225C0函数中参与异或运算的另一些值
调试得到v27和v28为
reverseme-v27v28
写逆运算脚本即可得到flag

#coding:utf-8
#a是两次异或后,v27和v28的数据
a=[0xB4, 0x39, 0x0D, 0xFB, 0xA2, 0x83, 0xF9, 0x40, 0xB2, 0x42,
  0x43, 0x9E, 0x41, 0x9C, 0x4F, 0x90, 0x4D, 0xBC, 0x76, 0x41,
  0x3E, 0xB6, 0x53, 0x0B, 0x6E, 0x66, 0x29, 0x75, 0xE5, 0x1C,
  0xBE, 0x2C]
#b是input第一次异或后,v30的数据
b=[0x32, 0x35, 0x33, 0x31, 0x3A, 0x54, 0x57, 0x59, 0x50, 0x35,
  0x28, 0x38, 0x2B, 0x3D, 0x38, 0x20, 0x24, 0x2D, 0x41, 0x44,
  0x44, 0x4F, 0x28, 0x3B, 0x2D, 0x3C, 0x62, 0x65, 0x63, 0x61,
  0x6A, 0x04]
#a^b即可得到sub_C225C0函数中参与异或运算的另一些值
#cipher是最后要比较的数据
cipher=[0xB3, 0x37, 0x0F, 0xF8, 0xBC, 0xBC, 0xAE, 0x5D, 0xBA, 0x5A,
  0x4D, 0x86, 0x44, 0x97, 0x62, 0xD3, 0x4F, 0xBA, 0x24, 0x16,
  0x0B, 0x9F, 0x72, 0x1A, 0x65, 0x68, 0x6D, 0x26, 0xBA, 0x6B,
  0xC8, 0x67]
s="SWPU_2019_CTF"
flag=""
for i in range(len(cipher)):
    flag+=chr(a[i]^b[i]^cipher[i]^ord(s[i%len(s)]))
print(flag)
#flag{Y0uaretheB3st!#@_VirtualCC}

[FlareOn1]Bob Doge

exe程序,运行后点击“DECODE”,看到一段不明白意义的字符串
bobdoge-runexe
查壳,发现是.Net程序,用dnSpy打开
找到“DECODE”按钮的响应函数,看到该函数会得到三个字符串text,text2和text3,调试看看这三个字符串分别是什么
bobdoge-onclick
可以看到,字符串text即为flag
bogdoge-flag

[FlareOn5]Ultimate Minesweeper

exe程序,运行后是个扫雷游戏,一共30x30=900个格子,897个雷,只有3个不是雷,提示说找到那3个不是雷的格子就能得到flag
查壳,发现是.Net程序,用dnSpy打开
先找到决定弹出失败(FailurePopup)或成功(SuccessPopup)对话框(ShowDialog)的SquareRevealedCallback函数
um-logic
选中SquareRevealedCallback函数名,右键->分析->被使用,来到MainForm函数
um-mainform
挨着点进去分析,发现在AllocateMemory函数会对900个格子,每个格子赋一个bool值,雷的格子赋为true,非雷的格子赋为false
um-AllocateMemory
在this.VALLOC_TYPES数组中就保存着非零格子的信息,但是不知道具体下标
um-VALLOC_TYPES
调试,在执行完“this.mineFieldControl.DataSource = this.MineField;”后,在GarbageCollect数组中可以看到,雷的格子为true,非雷为false
um-garbagecollect
找到3个非雷格子的位置分别为[7,20],[24,28],[28,7]
um-nonbomb
um-nonbomb
um-nonbomb
运行exe程序,点出3个非雷的格子(注意[]中第一个坐标为列,第二个坐标为行,且均从0开始),即可得到flag
um-flag

[GKCTF2020]Chelly’s identity

exe程序,运行后输入,无壳,ida分析
交叉引用字符串“flag is flag{(your answer)}!”来到sub_41C290函数
主要逻辑为,获取输入,验证输入长度是否为16,对输入进行处理(实际上为对输入进行异或运算),验证处理后的输入
chelly-logic
sub_411721->sub_41B3B0
首先获取2~128之间的素数,存到v12
然后进入while循环体,while里面有个小的for循环,for循环中的i小于输入字符的ascii码,且i每次的取值是2~128之间的素数,for循环中v9从0开始累加i,当i的取值大于等于输入字符的ascii码时,退出for循环,输入和累加好的v9异或,再进入下一次while循环,直到输入的每个字符都完成异或运算
chelly-sub_41B3B0
从sub_411852函数中取出最后要比较的数据,写逆脚本即可得到flag

#coding:utf-8
import gmpy2
res=[438,1176,1089,377,377,1600,924,377,1610,924,637,639,
     376,566,836,830]
sushu=[]
#获取2~128之间的素数
for i in range(2,128):
  if gmpy2.is_prime(i):
    sushu.append(i)
flag=""
for i in range(len(res)):
  for j in range(32,128):#爆破input的字符
    tmp=0
    for k in range(len(sushu)):
      if sushu[k]<j:    #sushu[k]相当于i,小于input字符的ascii码且为2~128之间的素数
        tmp+=sushu[k]   #v9累加
      else:
        break
    if j^tmp==res[i]:   #异或后比较相等
      flag+=chr(j)      
print(flag)
#Che11y_1s_EG0IST
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

P1umH0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值