BUUCTF逆向1-10题wp

easyre

载入 IDA 就能看到 flag

flag{this_Is_a_EaSyRe}

reverse1

IDA 载入,shift+F12 打开字符串窗口,找到可能与 flag 有关的字符串双击进入

按 x 查看引用,双击进入

可以看到其所在的函数的一个流程图

F5 查看伪代码

可以发现,它对我们输入的 str1 与程序里的 str2 做比较,str2 是{hello_world},而在开始前会将 str2 中的字母 o 替换为数字 0,于是得到 flag

flag{hell0_w0rld}

reverse2

IDA 载入,找到 main 函数,F5 查看伪代码

可以看到程序将我们输入的 s2 与 &flag 进行比较,查看 &flag

&flag 为 "hacking_for_fun}",再往上看有一段对 &flag 变换的操作

是将其中的 i 和 r 换成 1,于是得到 flag

flag{hack1ng_fo1_fun}

内涵的软件

载入 IDA 找到 main0 就能看见 flag

flag{49d3c93df25caad81232130f3d2ebfad}

新年快乐

用 exeinfo 查看一下发现加了 upx 壳

脱壳后载入 IDA 找到主函数,F5 查看伪代码,发现它将输入内容与 HappyNewYear! 对比,得到 flag 了

flag{HappyNewYear!}

helloword

载入 IDA 查看 main 函数

可以发现用户输入 __b,并且规定 __b 的长度为 33,然后与自身的前一位异或,再与 global 进行比较

查看 global 的值

输入的内容进行一顿异或之后得到 f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv"M,其中第一个 f 是没有被处理的

双击前面的 aFKW0XZUPFVMDGH 跳转过去

写脚本拿到 flag(脚本来源:套神博客)

tmp = ['f', 0x0A, 'k', 0x0C, 'w', '&', 'O', '.', '@', 0x11, 'x', 0x0D, 'Z', ';', 'U', 0x11, 'p', 0x19, 'F', 0x1F, 'v',
        '"', 'M', '#', 'D', 0x0E, 'g', 6, 'h', 0x0F, 'G', '2', 'O']
flag = 'f'
for i in range(1, len(tmp)):
    if (isinstance(tmp[i], str)):
        if (isinstance(tmp[i - 1], str)):
            flag += chr(ord(tmp[i]) ^ ord(tmp[i - 1]))#如果都是字符串
        else:#tmp[i]为字符串,tmp[i-1]不是字符串
            flag += chr(ord(tmp[i]) ^ tmp[i- 1])
    else:#tmp[i]和tmp[i-1]都不是字符串
        flag += chr(tmp[i] ^ ord(tmp[i - 1]))
print(flag)

flag{QianQiuWanDai_YiTongJiangHu}

helloword

Androidkiller 打开,就可以看到 flag 了

flag{7631a988259a00816deda84afb29430a}

reverse3

这题在 bugku 做过,之前写过 wp,传送门:Bugku-Rev-Love

不一样的flag

拖入 IDA,查看 main 函数

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char v3[29]; // [esp+17h] [ebp-35h] BYREF
  int v4; // [esp+34h] [ebp-18h]
  int v5; // [esp+38h] [ebp-14h] BYREF
  int i; // [esp+3Ch] [ebp-10h]
  _BYTE v7[12]; // [esp+40h] [ebp-Ch] BYREF

  __main();
  v4 = 0;
  strcpy(v3, "*11110100001010000101111#");
  while ( 1 )
  {
    puts("you can choose one action to execute");
    puts("1 up");
    puts("2 down");
    puts("3 left");
    printf("4 right\n:");
    scanf("%d", &v5);
    if ( v5 == 2 )
    {
      ++*(_DWORD *)&v3[25];
    }
    else if ( v5 > 2 )
    {
      if ( v5 == 3 )
      {
        --v4;
      }
      else
      {
        if ( v5 != 4 )
LABEL_13:
          exit(1);
        ++v4;
      }
    }
    else
    {
      if ( v5 != 1 )
        goto LABEL_13;
      --*(_DWORD *)&v3[25];
    }
    for ( i = 0; i <= 1; ++i )
    {
      if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 )
        exit(1);
    }
    if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' )
      exit(1);
    if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' )
    {
      puts("\nok, the order you enter is the flag!");
      exit(0);
    }
  }
}

看到有一串字符串"*11110100001010000101111#",然后有上下左右四个方向,再往下看可以发现程序碰到 1 退出,碰到 # 输出 flag,应该是一个迷宫,再查看那串字符串的长度正好是 25

得到 222441144222

flag{222441144222}

SimpleRev

IDA 载入找到主函数

输入 d 进入游戏,跟进函数 Decry()

unsigned __int64 Decry()
{
  char v1; // [rsp+Fh] [rbp-51h]
  int v2; // [rsp+10h] [rbp-50h]
  int v3; // [rsp+14h] [rbp-4Ch]
  int i; // [rsp+18h] [rbp-48h]
  int v5; // [rsp+1Ch] [rbp-44h]
  char src[8]; // [rsp+20h] [rbp-40h] BYREF
  __int64 v7; // [rsp+28h] [rbp-38h]
  int v8; // [rsp+30h] [rbp-30h]
  __int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
  int v10; // [rsp+50h] [rbp-10h]
  unsigned __int64 v11; // [rsp+58h] [rbp-8h]

  v11 = __readfsqword(0x28u);
  *(_QWORD *)src = 'SLCDN';
  v7 = 0LL;
  v8 = 0;
  v9[0] = 'wodah';
  v9[1] = 0LL;
  v10 = 0;
  text = (char *)join(key3, v9);
  strcpy(key, key1);
  strcat(key, src);
  v2 = 0;
  v3 = 0;
  getchar();
  v5 = strlen(key);
  for ( i = 0; i < v5; ++i )
  {
    if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
      key[i] = key[v3 % v5] + 32;
    ++v3;
  }
  printf("Please input your flag:");
  while ( 1 )
  {
    v1 = getchar();
    if ( v1 == '\n' )
      break;
    if ( v1 == ' ' )
    {
      ++v2;
    }
    else
    {
      if ( v1 <= '`' || v1 > 'z' )
      {
        if ( v1 > '@' && v1 <= 'Z' )
        {
          str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
          ++v3;
        }
      }
      else
      {
        str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
        ++v3;
      }
      if ( !(v3 % v5) )
        putchar(32);
      ++v2;
    }
  }
  if ( !strcmp(text, str2) )
    puts("Congratulation!\n");
  else
    puts("Try again!\n");
  return __readfsqword(0x28u) ^ v11;
}

先看这一部分

其中 text=key3+v9,key3 为 kills,v9 为 wodah,因为是小端序存储,所以 text 为 killshadow

key 为 key1+src,key1 为 ADSFK,src 为SLCDN,所以 key 为 ADSFKNDCLS

然后看加密过程

可以看到上图先将 key 每一位 +32,也就是变成了小写

然后用户输入,对输入内容进行操作后储存在 str2 里,最后将 str2 与 text 作比较,相同则为 flag

于是可以逆向得到脚本

#include <bits/stdc++.h>
using namespace std;
char text[11] = "killshadow";
char key[11] = "adsfkndcls";
char flag[11] = {0};
char str[11] = {0};
int main() {
  for (int i = 0; i < 10; i++)
    for (int j = 0; j < 128; j++) {
      if (j < 'A' || j > 'z' || j > 'Z' && j < 'a') continue;
      if ((j - 39 - key[i] + 97) % 26 + 97 == text[i]) {
  	str[i] = (j - 39 - key[i] + 97) % 26 + 97;
  	flag[i] = j;
  	printf("%s    ", flag);
  	printf("%s\n", str);
  	break;   //这里很重要,原因下面说
      }
  }
  printf("flag{%s}\n", flag);
  return 0;
}

其实我个人认为这题是有问题的,题目没有规定输入内容必须为大写字母,我们上文提到的代码之所以能得到正确的 flag 是因为那句关键的 break,但是如果将 break 去掉就会出现如下情况

可以看到出现了多解的情况,有小写字母的 flag 也有大小写字母混合的 flag,十分费解,不知道是不是题目本身的锅,如有师傅知道原因还请在评论区留言交流一下

flag{KLDQCUDFZO}

posted @ 2021-07-28 17:02  Moominn  阅读(1329)  评论(0编辑  收藏  举报