REVERSE-PRACTICE-BUUCTF-12

REVERSE-PRACTICE-BUUCTF-12

    • [FlareOn3]Challenge1
    • [GUET-CTF2019]number_game
    • [GWCTF 2019]re3
    • [网鼎杯 2020 青龙组]singal

[FlareOn3]Challenge1

exe程序,运行后提示输入密码,输入错误退出程序,无壳,ida分析
main函数逻辑清晰,读取输入,对输入进行变表base64编码,验证编码结果
REVERSE-PRACTICE-BUUCTF-12_第1张图片
之前遇到过变表base64的题目,见REVERSE-PRACTICE-BUUCTF-7或REVERSE-PRACTICE-BUUCTF-10或base64原理及其编解码的python实现
这道题用一个工具,加密解密小玩具,来解,非常方便
REVERSE-PRACTICE-BUUCTF-12_第2张图片

[GUET-CTF2019]number_game

elf文件,无壳,ida分析
main函数,获取输入,检验输入长度是否为10且均为0~4的数字,先后经过先序遍历和中序遍历改变输入中各个字符的位置,再顺序地放入数独“#”位置,最后检验数独
REVERSE-PRACTICE-BUUCTF-12_第3张图片
sub_400758函数和sub_400807函数先后经过先序遍历和中序遍历改变输入中各个字符的位置,本人一直想不通,于是动调,当输入为0123456789时,sub_400807函数调用结束后的v7为7381940526,于是可以知道输入中字符位置变换的规律
变换前的下标:0 1 2 3 4 5 6 7 8 9
变换后的下标:7 3 8 1 9 4 0 5 2 6
再解数独,在sub_400917函数中可知为5x5的数独
REVERSE-PRACTICE-BUUCTF-12_第4张图片
写代码换成正确的位置即可得到flag
REVERSE-PRACTICE-BUUCTF-12_第5张图片
由于输入长度只有10位,且均为0~4的数字,也可以写脚本爆破得到flag

[GWCTF 2019]re3

elf文件,无壳,ida分析
main函数,读取输入,检验输入长度是否为32,有一段SMC,自修改代码
REVERSE-PRACTICE-BUUCTF-12_第6张图片
ida静态分析,先写idapython脚本完成smc
smc执行前,地址0x402219处是一大段数据
REVERSE-PRACTICE-BUUCTF-12_第7张图片
smc的idapython脚本

from idaapi import *
from idautils import *
start_addr = 0x402219
key = 0x99
for i in range(start_addr,start_addr+224):
    PatchByte(i,Byte(i)^key)

smc执行完成后,按c转换成代码
REVERSE-PRACTICE-BUUCTF-12_第8张图片
在地址0x402219处右键->Edit function,将函数结束地址修改为retn指令所在地址,完成后F5反汇编
用插件Findcrypt发现sub_402219是对输入的AES加密,密钥为unk_603170,密文为res
REVERSE-PRACTICE-BUUCTF-12_第9张图片
远程调试elf,得到密钥unk_603170
REVERSE-PRACTICE-BUUCTF-12_第10张图片
写AES解密脚本即可得到flag
REVERSE-PRACTICE-BUUCTF-12_第11张图片

[网鼎杯 2020 青龙组]singal

exe程序,运行后提示输入string,无壳,ida分析
main函数,分析可知是vm的题目,dword_403040中的数据作为opcode传入vm_operad函数中
REVERSE-PRACTICE-BUUCTF-12_第12张图片
进入vm_operad函数,分析可知
opcode为10时,读取输入,长度为15
opcode为1时,v4被赋值
opcode为7时,v4和下一个opcode比较,于是7后面的opcode为密文
其余的opcode为input的相关运算

int __cdecl vm_operad(int *opcode, int a2)
{
     
  int result; // eax
  char input[100]; // [esp+13h] [ebp-E5h]
  char v4[100]; // [esp+77h] [ebp-81h]
  char v5; // [esp+DBh] [ebp-1Dh]
  int v6; // [esp+DCh] [ebp-1Ch]
  int v7; // [esp+E0h] [ebp-18h]
  int v8; // [esp+E4h] [ebp-14h]
  int v9; // [esp+E8h] [ebp-10h]
  int opcode_index; // [esp+ECh] [ebp-Ch]

  opcode_index = 0;
  v9 = 0;
  v8 = 0;
  v7 = 0;
  v6 = 0;
  while ( 1 )
  {
     
    result = opcode_index;
    if ( opcode_index >= a2 )
      return result;
    switch ( opcode[opcode_index] )
    {
     
      case 1:                                   // 每当opcode为1时,v4被赋值
        v4[v7] = v5;
        ++opcode_index;
        ++v7;
        ++v9;
        break;
      case 2:                                   // 每当opcode为2时,v5被赋值为下一个opcode与input的和
        v5 = opcode[opcode_index + 1] + input[v9];// 由于运算使用了下一个opcode,所以opcode_index加2
        opcode_index += 2;
        break;
      case 3:
        v5 = input[v9] - LOBYTE(opcode[opcode_index + 1]);// 每当opcode为3时,v5被赋值为input与下一个opcode的差
        opcode_index += 2;                      // 由于运算使用了下一个opcode,所以opcode_index加2
        break;
      case 4:
        v5 = opcode[opcode_index + 1] ^ input[v9];// 每当opcode为4时,v5被赋值为input与下一个opcode异或的值
        opcode_index += 2;                      // 由于运算使用了下一个opcode,所以opcode_index加2
        break;
      case 5:
        v5 = opcode[opcode_index + 1] * input[v9];// 每当opcode为5时,v5被赋值为input与下一个opcode乘积的值
        opcode_index += 2;                      // 由于运算使用了下一个opcode,所以opcode_index加2
        break;
      case 6:                                   // 每当opcode为6时,跳到下一个opcode
        ++opcode_index;
        break;
      case 7:                                   // 每当opcode为7时,验证v4和下一个opcode是否相等,意味着opcode等于7的下一个opcode为密文
        if ( v4[v8] != opcode[opcode_index + 1] )
        {
     
          printf("what a shame...");
          exit(0);
        }
        ++v8;
        opcode_index += 2;                      // 由于验证使用了下一个opcode,所以opcode_index加2
        break;
      case 8:                                   // 每当opcode为8时,input的值修改
        input[v6] = v5;
        ++opcode_index;
        ++v6;
        break;
      case 10:                                  // opcode的第一个值为10,所以先读取输入,长度为15
        read(input);
        ++opcode_index;
        break;
      case 11:                                  // 每当opcode为11时,v5被赋值为input与数字1的差
        v5 = input[v9] - 1;
        ++opcode_index;
        break;
      case 12:                                  // 每当opcode为12时,v5被赋值为input与数字1的和
        v5 = input[v9] + 1;
        ++opcode_index;
        break;
      default:
        continue;
    }
  }
}

提取出114个opcode,手动进行分类,并按照操作码得到input[0~14]的变换过程
REVERSE-PRACTICE-BUUCTF-12_第13张图片
写逆运算脚本即可得到flag
REVERSE-PRACTICE-BUUCTF-12_第14张图片
此题目也可以用angr一把梭

你可能感兴趣的:(Reverse-BUUCTF)