BUUOJ 第二弹

1.Java逆向解密

工具:jd-gui

拖入jd-gui得到加密函数 public static void Encrypt(char[] arr)

易得出是将用户输入加上‘@’^0x20的值再与KEY比较是否相等。

0x20为16进制,异或时要转换为10进制即32

可写出脚本:

key=[180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
a=''
for i in key:
    a += chr(i - ord('@')^32)
print (a)

解得 This_is_the_flag_!

2.[BJDCTF2020]BJD hamburger competition

工具:dnSpy,C#在线ide

下载打开压缩包,发现是以unity为框架的小游戏,直接搜索Assembly-CSharp.dll文件,拖入dnspy进行反编译,找到关键类函数 ButtonSpawnFruit .发现关键代码

找个网站解密哈希值得:

接着就是进行MD5加密,跟进函数。

一开始看不太懂,直接就用c#在线ide把这段代码搬上去。

后来查到是调用系统md5加密函数后将字母全部转换为大写,再取前20个字符作为结果返回.得到md5加密后的结果,注意是用flag{}包上,而不是BJDCTF{} 。

3.[HDCTF2019]Maze

工具:Exeinfo pe,upx,IDA

拖入Exeinfo pe,发现是一个加了upx壳的32位程序,走个流程脱壳。

拖入IDA中寻找start函数,跟进main。

发现main没有被ida识别成函数,看样子是被加花指令了。

注意到_mian中有个jnz跳转,前面有个cmp,且跳转地址和与指令相邻的下一地址相同,所以相当于没跳转,把他nop掉。

因为下面call另一个不是地址的地址,所以将反编译代码转换成机器码来看看。

其中
E8 对应指令为 call
58 对应指令为 pop

当ida把E8识别为call时,58 C7 45 EC便会被看作地址,此地址不存在便会无法反汇编,因此真正的指令应该是pop,所以把db 0E8hnop掉后,IDA就可以自动转换出汇编指令了

接着按p将_mian转换为函数再进行反汇编。跟进 dword_408078和 dword_40807C查看到初始状态:dword_408078=7 dword_40807C=0,然后经过14次移动后要使 dword_408078=5 dword_40807C=-4才能解出答案。

结合代码和题目名字Maze可得是一道迷宫题,但是程序好像没有判断迷宫。只要满足两个a和四个s就可以得到Congratulations!

用ida搜索一下字符串,处理一下得到数据

整理一下

*******+**
******* **
****    **
**   *****
** **F****
**    ****
**********

因为dword_408078=7 dword_40807C=0,所以是+为起点,F为中点,且ad控制左右,ws控制上下。又因为

a --dword_408078
d ++dword_408078
s --dword_40807C
w ++dword_40807C

所以s是上,w是下,a是右,d是左。

若迷宫为正向,则行走路径为wwdddwddwwaaas;若迷宫为反向,则行走路径为ssaaasaassdddw。

先验证一下.

排除正向迷宫,提交一下:flag{ssaaasaassdddw}

4.[GKCTF2020]BabyDriver

工具:IDA

根据题目描述,拖入IDA64中。看来看去没有头绪,搜下字符串,估计是个迷宫题

跟进字符串,发现一共有224个字符,猜测是16*14 或 14*16,写个脚本验证一下

list = '****************o.*..*......*..**.**...**.*.*.***.****.**.*.*.***...**....*.*.*****..***.**.*..**.**.***.**.**.**.**.******.**.**.**....***.**.**.*****.***....**...***.**********..***......#****.***************************** '
a = 0
for i in range(len(list)):
    a = a + 1
    print(list[i], end='')
    if a % 16 == 0:
        print('
', end='')

得到

****************
o.*..*......*..*
*.**...**.*.*.**
*.****.**.*.*.**
*...**....*.*.**
***..***.**.*..*
*.**.***.**.**.*
*.**.******.**.*
*.**....***.**.*
*.*****.***....*
*...***.********
**..***......#**
**.*************
****************

跟进a0,并查看交叉引用列表。

跟进sub_140001380进行反编译。得到关键代码,先分析好分析。

      v9 = aO[v5];
      if ( v9 == '*' )
      {
        v10 = "failed!
";
      }
      else
      {
        if ( v9 != '#' )
        {
LABEL_27:
          aO[v5] = 'o';                   //更新位置
          goto LABEL_28;
        }
        v10 = "success! flag is flag{md5(input)}
";
      }
      dword_1400030E4 = 16;
      DbgPrint(v10);
      v5 = dword_1400030E4;
      goto LABEL_27;
    }
  }

可知当碰到*时结束。碰到#时,你所输入的值md5加密后就是flag。

再来分析输入判断。由于是驱动文件,所以输入比较的是16进制的键盘码

LABEL_28:
        v6 += 6;
        if ( !--v7 )
          goto LABEL_29;
      }
      aO[v5] = 46;
      v8 = *v6;
      if ( *v6 == 0x17 )                 // I
      {
        if ( v5 & 0xFFFFFFF0 )           // 当V5>16,条件成立,因为是向上。所以不用考虑208这倒数第二层的边界
        {
          v5 -= 16;                      //上移
          goto LABEL_21;
        }
        v5 += 208;                       // 当V5<16也就是在第一层,强制碰到最后一层墙壁结束
        dword_1400030E4 = v5;
      }
      if ( v8 == 0x25 )                  // K
      {
        if ( (v5 & 0xFFFFFFF0) != 208 )  // 当V5>16且不等于208,条件成立,因为是向下。所以要考虑208这倒数第二层的边界
        {
          v5 += 16;                      //下移
          goto LABEL_21;
        }
        v5 -= 208;                       // 当v5=208,强制碰到第一层墙壁结束
        dword_1400030E4 = v5;
      }
      if ( v8 == 0x24 )                  // J
      {
        if ( v5 & 15 )                   //当v5不等于16的倍数时,即不在每一层的左边界,条件成立
        {
          --v5;                          //左移
          goto LABEL_21;
        }
        v5 += 15;                        //当v5等于16的倍数时,即在某一层的左边界 ,向右移15位,即移动到这一层的右边界
        dword_1400030E4 = v5;
      }
      if ( v8 != 0x26 )                   // L
        goto LABEL_22;
      if ( (v5 & 15) == 15 )              //当v5等于16的倍数-1时,即在某一层的右边界,条件成立      
        v5 -= 15;                         //向左移15位,即移动到这一层的左边界
      else
        ++v5;                             //右移
LABEL_21:
      dword_1400030E4 = v5;

所以,根据上面的迷宫和代码的分析:
若为正向迷宫,则行走路径为 LKKKLLKLKKKLLLKKKLLLLLL;
若为反向迷宫,则行走路径为 JIIIJJIJIIIJJJIIIJJJJJJ。

然后进行md5 32位小写加密,进行验证,可得到只有正向才是对的,即flag{403950a6f64f7fc4b655dea696997851} 。

原文地址:https://www.cnblogs.com/b1ank/p/13466772.html