2020易霖博杯——Re题目部分WP

文章目录

      • re1
      • re2与re3
      • re4
      • re5

re1

拿到程序以后拖进IDA里shift+F12看一下:
2020易霖博杯——Re题目部分WP_第1张图片
双击跟进去,查看一下交叉引用,F5转一下伪代码就出来了:
2020易霖博杯——Re题目部分WP_第2张图片
flag为:flag{Sign_fDfkl_CTF}}

re2与re3

目前网上仍没有公布WP,当时参赛选手都没解出来...

re4

拖IDA看一下,发现是ELF文件:
2020易霖博杯——Re题目部分WP_第3张图片
看一下main()函数的伪代码:
2020易霖博杯——Re题目部分WP_第4张图片

这是main()函数的伪代码:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  signed int i; // [esp+20h] [ebp-28h]
  char s[17]; // [esp+2Bh] [ebp-1Dh]
  unsigned int v6; // [esp+3Ch] [ebp-Ch]

  v6 = __readgsdword(0x14u);
  memcpy(&password, "IKAWTEQWJHQTVRCF", 0x10u);		//初始化password
  memset(s, 0, 0x11u);
  printf("Enter the password: ");
  __isoc99_scanf("%16s", s);						//获取键盘输入的16个字符
  for ( i = 0; i <= 15; ++i )						//将字符串放入循环
    s[i] = complex_function(s[i], 18 - i);			//这里是重点,将字符串存到s这个数组里,并调用complex_function()这个函数进行处理,然后在返回到s里。
  if ( check_equals_IKAWTEQWJHQTVRCF(s, 16) )		//这里调用check_equals_IKAWTEQWJHQTVRCF()函数对处理后的password进行最多16次判断
    puts("Good Job.");								//若结果为真则输出Good job.
  else
    puts("Try again.");								//若结果为假则输出Try again.
  return 0;
}

我们在看一下它对我们输入的password进行了怎样的处理,也就是看一下complex_function()函数:
2020易霖博杯——Re题目部分WP_第5张图片
简单分析一下:

int __cdecl complex_function(signed int a1, int a2)
{
  if ( a1 <= 64 || a1 > 90 )	//password对应的十进制只能在64~90之间
  {
    puts("Try again.");			//若超出64~90则输出Try again.
    exit(1);					//运行到这里直接结束当前进程
  }
  return (a1 - 65 + 29 * a2) % 26 + 65;	//如果语句没有执行,那么passwd经过处理后返回
}

接着我们分析它调用check_equals_IKAWTEQWJHQTVRCF()进行的判断:
2020易霖博杯——Re题目部分WP_第6张图片

分析一下伪代码,这里a1就是经过处理后的password,a2是16:

_BOOL4 __cdecl check_equals_IKAWTEQWJHQTVRCF(int a1, unsigned int a2)
{
  int v3; // [esp+8h] [ebp-8h]
  unsigned int i; // [esp+Ch] [ebp-4h]

  v3 = 0;							//定义一个局部变量v3用来存值
  for ( i = 0; a2 > i; ++i )		//开始循环,每次循环结束i进行自加,最多循环16次
  {
    if ( *(_BYTE *)(i + a1) == *(_BYTE *)(i + 0x804C038) )	//这里是对原password跟处理后的password进行对比,如果相等就执行下面的语句,如果不相等就直接跳出去
      ++v3;							//相等后进行自加
  }
  return v3 == a2;					
}
/**
这里return v3 == a2的作用我感觉就是把结果转成0或1,
然后存到eax里,进行判断后选择跳或者不跳,如果程序成功执行了16次,
也就是v3 == a2成立,那么结果就是0,反之为1
**/

这是check_equals_IKAWTEQWJHQTVRCF()函数执行后的流程图,这里如果jnz判断不成立,也就是eax为0,那么就输出"Good job.“反之输出"Try again.”,跟我们分析的一样:
2020易霖博杯——Re题目部分WP_第7张图片
2020易霖博杯——Re题目部分WP_第8张图片
分析到这里我们就有解题思路了,有两种解题方法:

  1. 从complex_function()函数下手,直接爆破一下加密后的password。
  2. 从check_equals_IKAWTEQWJHQTVRCF()函数下手,破解程序。

这里还是爆破比较方便,也比较简单:

passwd = 'IKAWTEQWJHQTVRCF'		#定义原passwd
flag = ''  						#定义flag用来存值
for i in range(len(passwd)):	#返回passwd的长度,也就是16
    for a1 in range(64,91):		#把64~90依次传给a1
        if (a1 - 65 + (18-i)*29)%26 + 65 == ord(passwd[i]):  #如果经过计算后a1的十进制结果如果等于原passwd的十进制结果
            flag += chr(a1)  								 #那么将结果依次转为对应的ASCII码赋值给flag
  
print('flag{%s}'%(flag))			#输出flag

成功拿到flag:flag{GLEDDRGPFGSYDCQW}

re5

这题我看流程图感觉是将输入的内容进行异或,然后将异或的结果进行判断,若结果为真则结束进程,若为假则输出“err…"并结束进程:

这是它main()函数的伪代码
2020易霖博杯——Re题目部分WP_第9张图片这里的关键就是在sub_400606()这个函数,它的伪代码非常复杂,很多个循环语句嵌套,水平实在是不够,分析不了,如果有大牛能分析或者感兴趣,私信我一起学习一下!

上一下sub_400606()函数的伪代码:

__int64 __fastcall sub_400606(signed int *a1)
{
  signed __int64 v1; // rax
  __int64 result; // rax
  int v3; // [rsp+10h] [rbp-10h]
  __int16 v4; // [rsp+14h] [rbp-Ch]

  *a1 = 0;
  do
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          while ( 1 )
          {
            while ( 1 )
            {
              while ( 1 )
              {
                do
                {
                  v1 = *((_QWORD *)a1 + 1) + 6LL * *a1;
                  v3 = *(_DWORD *)v1;
                  v4 = *(_WORD *)(v1 + 4);
                  ++*a1;
                }
                while ( BYTE1(v3) && BYTE1(v3) != a1[1] );
                result = (unsigned __int8)v3;
                if ( (unsigned __int8)v3 != 7 )
                  break;
                *a1 = *(signed __int16 *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2));
              }
              if ( (signed int)result > 7 )
                break;
              if ( (_DWORD)result == 3 )
              {
                if ( *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2)) == *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2)) )
                  a1[1] = 1;
                else
                  a1[1] = 2;
              }
              else if ( (signed int)result > 3 )
              {
                if ( (_DWORD)result == 5 )
                {
                  *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
                }
                else if ( (signed int)result > 5 )
                {
                  *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *a1;
                }
                else
                {
                  *a1 += SHIWORD(v3);
                }
              }
              else if ( (_DWORD)result == 1 )
              {
                *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2))
                                                                    + *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
              }
              else if ( (_DWORD)result == 2 )
              {
                *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2))
                                                                    - *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
              }
            }
            if ( (_DWORD)result != 10 )
              break;
            *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *((_WORD *)a1
                                                                  + *(signed __int16 *)(2LL * v4 + *((_QWORD *)a1 + 2))
                                                                  + 8LL
                                                                  + 4);
          }
          if ( (signed int)result > 10 )
            break;
          if ( (_DWORD)result == 8 )
          {
            *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = v4;
          }
          else if ( (_DWORD)result == 9 )
          {
            puts("err..");
          }
        }
        if ( (_DWORD)result != 12 )
          break;
        *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2)) ^ *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
      }
      if ( (signed int)result >= 12 )
        break;
      *(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *((_WORD *)a1
                                                            + *(signed __int16 *)(2LL * v4 + *((_QWORD *)a1 + 2))
                                                            + 32LL);
    }
  }
  while ( (_DWORD)result != 255 );
  return result;
}

这道题目前网上没有什么分析,只有一个解题脚本,也是通过异或试出来的:

a=[0x003C, 0x0030, 0x003F, 0x0007, 0x0019, 0x0012, 0x0000, 0x001E, 0x0018, 0x001A, 0x001A, 0x0042, 0x0046, 0x0010, 0x0010, 0x0010, 0x0014, 0x001F, 0x000C, 0x00FD]  
x=90  
for i in a:  
    print(chr(i^x),end='')  
    x+=2    

运行后成功获得flag:flag{vfvrvt24dfhncr}

你可能感兴趣的:(我的CTF之路)