游戏题

依旧游戏题目 依旧patch 简单游玩一下发现是一个扫雷吧 然后查看main函数 能发现是一个100格子 然后75个空格 25个雷 全部点开完成后给flag

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  __int64 v4; // rax
  __int64 v5; // rax
  _BYTE *v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rax
  int v14; // [rsp+28h] [rbp-58h] BYREF
  int v15; // [rsp+2Ch] [rbp-54h] BYREF
  int v16; // [rsp+30h] [rbp-50h]
  unsigned int v17; // [rsp+34h] [rbp-4Ch]
  unsigned int v18; // [rsp+38h] [rbp-48h]
  int v19; // [rsp+3Ch] [rbp-44h]
  int v20; // [rsp+40h] [rbp-40h]
  int i1; // [rsp+44h] [rbp-3Ch]
  int nn; // [rsp+48h] [rbp-38h]
  int i3; // [rsp+4Ch] [rbp-34h]
  int i2; // [rsp+50h] [rbp-30h]
  int i4; // [rsp+54h] [rbp-2Ch]
  int mm; // [rsp+58h] [rbp-28h]
  int kk; // [rsp+5Ch] [rbp-24h]
  int jj; // [rsp+60h] [rbp-20h]
  int ii; // [rsp+64h] [rbp-1Ch]
  int n; // [rsp+68h] [rbp-18h]
  int m; // [rsp+6Ch] [rbp-14h]
  int k; // [rsp+70h] [rbp-10h]
  int v33; // [rsp+74h] [rbp-Ch]
  int j; // [rsp+78h] [rbp-8h]
  int i; // [rsp+7Ch] [rbp-4h]

  _main();
  memset_0(grid, 0, 0x190u);
  memset_0(randMark, 0, sizeof(randMark));
  memset_0(vis, 0, sizeof(vis));
  for ( i = 0; i <= 9; ++i )
  {
    for ( j = 0; j <= 9; ++j )
      showUs[100 * i + j] = 42;
  }
  v3 = time(nullptr);
  srand_0(v3);
  v33 = 0;
  do
  {
    v20 = rand_0() % 10;
    v19 = rand_0() % 10;
    if ( randMark[100 * v20 + v19] != 1 )
    {
      randMark[100 * v20 + v19] = 1;
      ++v33;
    }
  }
  while ( v33 != mine_sum );
  res = 0;
  for ( k = 0; k <= 9; ++k )
  {
    for ( m = 0; m <= 9; ++m )
    {
      if ( randMark[100 * k + m] )
        grid[10 * k + m] = -1;
    }
  }
  for ( n = 0; n <= 9; ++n )
  {
    for ( ii = 0; ii <= 9; ++ii )
    {
      if ( grid[10 * n + ii] != -1 )
      {
        for ( jj = 0; jj <= 7; ++jj )
        {
          v18 = *((_DWORD *)&dir + 2 * jj) + n;
          v17 = dword_475044[2 * jj] + ii;
          if ( v18 <= 9 && v17 <= 9 && grid[10 * v18 + v17] == -1 )
            ++grid[10 * n + ii];
        }
      }
    }
  }
  for ( kk = 0; kk <= 9; ++kk )
  {
    for ( mm = 0; mm <= 9; ++mm )
    {
      v4 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, (unsigned int)showUs[100 * kk + mm]);
      std::operator<<<std::char_traits<char>>(v4, &unk_48B000);
    }
    ((void (__fastcall *)(std::ostream *const))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(refptr__ZSt4cout);
  }
  v5 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_48B002);
  ((void (__fastcall *)(__int64))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(v5);
  while ( 100 - mine_sum != res )
  {
    v7 = std::istream::operator>>(refptr__ZSt3cin, &v15);
    std::istream::operator>>(v7, &v14);
    if ( grid[10 * v15 + v14] == -1 )
    {
      v8 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_48B01D);
      ((void (__fastcall *)(__int64))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(v8);
      goto LABEL_67;
    }
    if ( vis[100 * v15 + v14] || grid[10 * v15 + v14] <= 0 )
    {
      if ( !vis[100 * v15 + v14] && !grid[10 * v15 + v14] )
      {
        bfs(v15, v14);
        system_0("cls");
        for ( nn = 0; nn <= 9; ++nn )
        {
          for ( i1 = 0; i1 <= 9; ++i1 )
          {
            v11 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, (unsigned int)showUs[100 * nn + i1]);
            std::operator<<<std::char_traits<char>>(v11, &unk_48B000);
          }
          ((void (__fastcall *)(std::ostream *const))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(refptr__ZSt4cout);
        }
        v12 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_48B002);
        ((void (__fastcall *)(__int64))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(v12);
      }
    }
    else
    {
      ++res;
      vis[100 * v15 + v14] = 1;
      showUs[100 * v15 + v14] = LOBYTE(grid[10 * v15 + v14]) + 48;
      system_0("cls");
      for ( i2 = 0; i2 <= 9; ++i2 )
      {
        for ( i3 = 0; i3 <= 9; ++i3 )
        {
          v9 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, (unsigned int)showUs[100 * i2 + i3]);
          std::operator<<<std::char_traits<char>>(v9, &unk_48B000);
        }
        ((void (__fastcall *)(std::ostream *const))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(refptr__ZSt4cout);
      }
      v10 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_48B002);
      ((void (__fastcall *)(__int64))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(v10);
    }
  }
  v16 = std::string::length((std::string *)&ans);
  for ( i4 = 0; i4 < v16; ++i4 )
  {
    v6 = (_BYTE *)std::string::operator[](&ans, i4);
    std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, (unsigned int)(char)((v16 - i4) ^ *v6));
  }
  ((void (__fastcall *)(std::ostream *const))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(refptr__ZSt4cout);
LABEL_67:
  system_0("pause");
  return 0;
}

然后这里面也能看到flag是如何生成的 因为有一个

v16 = std::string::length((std::string *)&ans);

那么 ans 肯定就是我们要的flag 我们去看看他进行了哪些操作

嗯。。。 先用技巧吧

我们能看到在这里 有一个判断while 而mine_sum初始值又是25 那我们猜测这个是不是就是判断是否为正确的关键点呢 我们patch一下

while ( 100 - mine_sum != res )
  {
    v7 = std::istream::operator>>(refptr__ZSt3cin, &v15);
    std::istream::operator>>(v7, &v14);
    if ( grid[10 * v15 + v14] == -1 )
    {
      v8 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_48B01D);
      ((void (__fastcall *)(__int64))refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)(v8);
      goto LABEL_67;
    }
    if ( vis[100 * v15 + v14] || grid[10 * v15 + v14] <= 0 )

然后保存 出flag的前身了

image

然后我们来说另一种方式 就是直接逆

查看调用能到这里

int __fastcall __static_initialization_and_destruction_0(int a1, int a2)
{
  int result; // eax
  _BYTE v3[17]; // [rsp+2Fh] [rbp-51h] BYREF

  if ( a1 == 1 && a2 == 0xFFFF )
  {
    std::ios_base::Init::Init((std::ios_base::Init *)&std::__ioinit);
    atexit(_tcf_0);
    std::allocator<char>::allocator(v3);
    std::string::string(&ans, "*ur)O}t@r{u!c&|}d\\9m>M4NtsrjL", v3);
    std::allocator<char>::~allocator(v3);
    return atexit(_tcf_1);
  }
  return result;
}

然后拿到数据后回头

v15 = std::string::length((std::string *)&ans);
  for ( i4 = 0; i4 < v15; ++i4 )
  {
    v6 = (_BYTE *)std::string::operator[](&ans, i4);
    std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, (unsigned int)(char)((v15 - i4) ^ *v6));
  }
  refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(refptr__ZSt4cout);

能发现有一个异或 这一段就相当于

for (int i = 0; i < ans.length(); i++)
    cout << char(ans[i] ^ (ans.length() - i));

那我们直接解密就好了

exp

s = b"*ur)O}t@r{u!c&|}d\\9m>M4NtsrjL"
print(bytes([c ^ (len(s) - i) for i, c in enumerate(s)]).decode())

然后为什么解出来的这个是不对的呢 我们看前面头部 是不是base58的flag编码 只不过是Flickr Base58版本 这个版本跟正常的版本有什么区别呢 就是大小写互换

Flickr : 123456789 abcdefghijkmnopqrstuvwxyz ABCDEFGHJKLMNPQRSTUVWXYZ
Bitcoin: 123456789 ABCDEFGHJKLMNPQRSTUVWXYZ abcdefghijkmnopqrstuvwxyz

也可以用网址来解密

image

flag

flag{h4pp4-M1n3-G4m3}