一道简单的MIPS逆向题

Author Avatar
ciaoly 2021年09月07日
  • 在其它设备中阅读本文章

这是第七届职业技能竞赛山东省赛的一道赛题, 价值2分.

题目附件


附件中有两个文件, 使用file命令查看, secret是MIPSel指令集的ELF文件, enc是文本文件.

image-20210907213152993

符号表:

objdump -T

# secret:     file format elf32-little
# 
# DYNAMIC SYMBOL TABLE:
# 00000714 l    d  .init  00000000              .init
# 00000c54 g    DF .text  00000008  Base        __libc_csu_fini
# 00000001 g    d  *ABS*  00000000  Base        _DYNAMIC_LINKING
# 00010da0 g    DO .data  00000004  Base        king
# 00010e50 g    DO .bss   00000020  Base        key
# 00000a54 g    DF .text  00000088  Base        readkey
# 00000d10 g    DO .rodata        00000004  Base        _IO_stdin_used
# 00010db0 g    DO .rld_map       00000000  Base        __RLD_MAP
# 00000bb0 g    DF .text  000000a4  Base        __libc_csu_init
# 00000adc g    DF .text  000000c8  Base        main
# 00000910 g    DF .text  00000144  Base        check
# 00000714 g    DF .init  00000000  Base        _init
# 00000000  w   D  *UND*  00000000              _ITM_registerTMCloneTable
# 00000cc0      DF *UND*  00000000  GLIBC_2.7   __isoc99_scanf
# 00000000  w   D  *UND*  00000000              _Jv_RegisterClasses
# 00000cb0      DF *UND*  00000000  GLIBC_2.0   __libc_start_main
# 00000ca0      DF *UND*  00000000  GLIBC_2.0   strlen
# 00000c90      DF *UND*  00000000  GLIBC_2.0   exit
# 00000000  w   DF *UND*  00000000              __gmon_start__
# 00000c80      DF *UND*  00000000  GLIBC_2.0   puts
# 00000c70      DF *UND*  00000000  GLIBC_2.0   fread
# 00000c60      DF *UND*  00000000  GLIBC_2.2   fopen
# 00000000  w   D  *UND*  00000000              _ITM_deregisterTMCloneTable
# 00000000  w   DF *UND*  00000000  GLIBC_2.2   __cxa_finalize

加密过程

直接使用Ghidra加载ELF文件, 代码比较简单, 主函数如下:

undefined4 main(void) {
  undefined auStack40 [32];
  puts((char *)0xd50); //"Tell me my secret !!"
  readkey();
  __isoc99_scanf(0xd68,auStack40); //"%32s"
  check(auStack40);
  puts((char *)0xd70); //"Bingo!"
  return 0;
}

直接定位到check函数看看

void check(char *param_1) {
  size_t sVar1;
  uint local_10;
  sVar1 = strlen(param_1);
  if (sVar1 != 0x20) {
    puts((char *)0xd20); // "Never lost yourself"
    exit(0);
  }
  local_10 = 0;
  while( true ) {
    sVar1 = strlen(param_1);
    if (sVar1 <= local_10) {
      return;
    }
    if (((int)param_1[local_10] ^ king) != (int)(char)key[local_10]) break;
    local_10 = local_10 + 1;
  }
  puts((char *)0xd34); //"Have nothing at all"
  exit(0);
}

关键代码在第15行, 可以看到, 只要找到key数组和king变量, 再进行异或运算即可得到flag.

重新审计main函数, 发现函数readkey在文件中加载了key:

void readkey(void) {
  FILE *__stream;
  __stream = fopen((char *)0xd4c,(char *)0xd48); //"enc", "r+"
  fread(key,0x20,1,__stream);
  return;
}

Ghidra中跳转到king地址, 得到king = 0x44(在ida里显示的是dword_44, 注意不要再双击它了, 双击就会跳转到0x44的地址上去)

image-20210907220059355

解密

直接编写脚本解密

$key = [System.IO.File]::ReadAllBytes(".\enc");
$flag = $key | % {
    $_ -bxor 0x44;
}
[System.IO.File]::WriteAllBytes("./flag.txt", $flag);

qemu-mipsel加载可执行文件运行一下, 输入得到的flag, 校验通过:

image-20210907221031189

图中用的是docker容器, root密码是mipsel

得到flag: 845242223606e4746c757306f8563dcb


这道题还是挺简单的, 但是比赛现场由于是线下赛且不允许用自己的电脑, 当时现场的电脑里只有ida, 但是ida不支持mipsel的反汇编, 因此根本就看不懂这个程序......I am so vegetable.

另附两个mips指令集的简单资料