'); }

虎符_redemption_code


0x1

MIPS架构,可以用能成功反编译的ida版本去反编译,内容的理解实际上不用动调,个人采取了动调,一是正好配置相关环境,二是尝试一下MIPS架构的动调。

之前配置过,但是运行不起来,只能重装

0x2

反汇编后,

image-20211102013115566

pre中(将函数修改成无返回值后):

void __fastcall pre(int a1)
{
  int v1; // $v0
  _BOOL4 v2; // $s0
  int v3; // $v0
  char v5[4]; // [sp+20h] [+20h] BYREF
  char v6[24]; // [sp+24h] [+24h] BYREF
  char v7[24]; // [sp+3Ch] [+3Ch] BYREF

  if ( std::__cxx11::basic_string,std::allocator>::length(a1) != 14 )// len==14
  {
    v1 = std::operator<<>(&std::cout, "redemption code format error");
    std::ostream::operator<<(v1, &std::endl>);
    exit(-1);
  }
  std::allocator::allocator(v5);
  std::__cxx11::basic_string,std::allocator>::basic_string(
    v6,
    "Ninja Must Die 3 Is A Cruel Game, So Hard For Me",
    v5);                                        // 将字符串保存到v6中
  std::__cxx11::basic_string,std::allocator>::basic_string(v7, a1);// 将flag传递给v7
  v2 = server_check_redemption_code((int)v6, (int)v7) == -1;// 不能返回-1,说明有解
  std::__cxx11::basic_string,std::allocator>::~basic_string(v7);
  std::__cxx11::basic_string,std::allocator>::~basic_string(v6);
  std::allocator::~allocator(v5);
  if ( v2 )
  {
    v3 = std::operator<<>(&std::cout, "game error");
    std::ostream::operator<<(v3, &std::endl>);
    exit(-2);
  }
}

server_check_redemption_code内:

int __fastcall server_check_redemption_code(int cmp, int flag)
{
  unsigned int len2; // $v0
  int tmp; // [sp+18h] [+18h]
  int i; // [sp+1Ch] [+1Ch]
  int j; // [sp+20h] [+20h]
  int v7; // [sp+24h] [+24h]
  int k; // [sp+28h] [+28h]
  int len1; // [sp+34h] [+34h]
  int flag_len; // [sp+38h] [+38h]
  void *s; // [sp+3Ch] [+3Ch]

  if ( std::operator==<char>(flag, &unk_401D94) )
    return 0;
  len1 = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(cmp);
  len2 = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(flag);
  flag_len = len2;
  if ( len2 >= 0x200000 )
    _cxa_throw_bad_array_new_length();
  s = (void *)operator new[](len2 << 10);
  memset(s, 0, flag_len << 10);
  *((_DWORD *)s
  + *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](flag, 0)) = 1;// 开拓空间
  tmp = 0;
  for ( i = 1; i < flag_len; ++i )
  {
    for ( j = 0; j < 256; ++j )
    {
      if ( j != *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](
                           flag,
                           i) )                 // j != flag[i]
        *((_DWORD *)s + 256 * i + j) = *((_DWORD *)s + 256 * tmp + j);// s[i][j] = s[tmp][j]
      else
        *((_DWORD *)s + 256 * i + j) = i + 1;   // s[i][j] = i+1
    }
    tmp = *((_DWORD *)s
          + 256 * tmp
          + *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](flag, i));// tmp = s[tmp][flag[i]]
  }
  v7 = 0;
  for ( k = 0; k < len1; ++k )
  {
    v7 = *((_DWORD *)s
         + 256 * v7
         + *(char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[](cmp, k));// v7 = s[v7][cmp[k]]
    if ( v7 == flag_len )                       // 判断s[v7][cmp[k]]位置处的值是否为14
      return k - flag_len + 1;                  
  }
  return -1;
}

两个函数都看完后,确定pre函数功能:判断输入值长度是否为14,输入值其中与指定字符串相同的字符数至少有一个

主函数server_check_redemption_code函数返回值为7,有:

k - flag_len + 1 =7
//flag_len=14
==> k = 20

可以得到如下关系:

flag ∈ "Ninja Must Die 3 Is A Cruel Game, So Hard For Me"
flag ∈ "I Love Ninja Must Die 3. Beautiful Art And Motive Operation Is Creative."[:21]   
len(flag)==14

直接推出flag:

Ninja Must Die

image-20211102020141720

套个壳:

flag{Ninja Must Die}

  目录