逆向

逆向实战演示

 

实现目标:

贪吃蛇999999分

 

 

使用工具:

1. exeinfo:

简单的查壳软件

2. IDA:

IDA是一款交互式反汇编工具,其功能十分强大,支持多操作系统、多处理器下的二进制程序的反汇编分析,并且可以和使用者进行交互来提升处理效率。

3. Cheat Engine(ce):

CheatEngine一款内存修改软件,功能十分强大,可以轻松实现对单机游戏的数据进行修改.

 

 

首先在网上随便下一个贪吃蛇程序:

 

 

游戏界面:

 

在记录这个选项中.能看见最近几次的最高分数

 

 

那如何得到我们想要的分数呢,(懒狗是不可能手打的)

 

首先打开Cheat Engine这个工具:

 

 

点击左上角的小电脑图标,选择贪吃蛇游戏的进程

 

 

点击Open

 

接下来开始游戏

简单获得一分

 

 

接下来打开Cheat Engine 进行搜索,在Value处输入获得的分数,然后点击First scan,第一次搜索

 

能够看见一共有超级多的搜索结果,接下来继续返回游戏,

 

 

再玩一次游戏,玩到两分:

 

这个时候返回Cheat Engine再搜索:

 

 

这个时候就神奇的发现,只剩一个结果了,这个结果就是我们想要的分数:

 

 

对这个结果双击,结果就会添加到下方的方框中

 

 

这个时候双击红色方框中的2,就可以进行修改值:

 

修改为999999

 

 

修改完成,回到游戏查看:

 

 

分数就修改成功了.

 

 

接下来使用以往新生赛的一道题来演示在CTF中如何得到flag:

 

 

首先看看这个游戏是怎么个玩法:

 

 

 

WASD控制,Enter开始游戏,只要得到60分就可以得到flag

 

使用exeinfo查看程序的位数:

 

 

接下来就可以32位IDA进行反汇编:

 

 

 

在左侧的函数框里,能一眼看见main函数,双击main函数:

 

很清晰的两个函数:开始菜单函数,游戏循环函数.

 

双击循环函数:

 

int gameMainLoop()
{
  void *v0; // eax
  int v1; // edx
  int v2; // ecx
  int v3; // eax
  int v4; // eax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  char v8; // cl
  char v9; // cl
  int result; // eax
  char Buffer[1247]; // [esp+2Dh] [ebp-ECBh] BYREF
  int v12; // [esp+50Ch] [ebp-9ECh]
  int v13[625]; // [esp+510h] [ebp-9E8h] BYREF
  char v14; // [esp+ED7h] [ebp-21h]
  int j; // [esp+ED8h] [ebp-20h]
  char v16; // [esp+EDFh] [ebp-19h]
  int i; // [esp+EE0h] [ebp-18h]
  int v18; // [esp+EE4h] [ebp-14h]
  int v19; // [esp+EE8h] [ebp-10h]
  int v20; // [esp+EECh] [ebp-Ch]

  gameBegin();
  v0 = malloc(1u);
  srand((unsigned int)v0);
  do
  {
    v20 = 12;
    v19 = 12;
    v18 = 4;
    memset(v13, 0, sizeof(v13));
    for ( i = 0; i <= 24; i += 2 )
    {
      v1 = 624 - i;
      v2 = 25 * i;
      v3 = 25 * (i + 1) - 1;
      v13[v3] = -2;
      v13[v2] = v13[v3];
      v13[v1] = v13[v2];
      v13[i] = v13[v1];
    }
    v16 = 100;
    v14 = 3;
    *(_DWORD *)Buffer = 0;
    v12 = 0;
    memset(&Buffer[3], 0, 4 * (((Buffer - &Buffer[3] + 1251) & 0xFFFFFFFC) >> 2));
    sprintf_s(Buffer, 0x20u, "mode con: cols=%d lines=%d", 50, 25);
    system(Buffer);
    for ( j = 2; j; --j )
    {
      do
        i = rand() % 625;
      while ( v13[i] );
      v13[i] = -1;
    }
    system("title GluttonousSnake");
    while ( 1 )
    {
      if ( _kbhit() )
      {
        v14 = _getch();
        if ( v14 )
        {
          switch ( v14 )
          {
            case 27:
              exit(0);
            case 32:
              _getch();
              break;
            case 65:
            case 75:
            case 97:
              if ( v16 != 100 )
                v16 = 97;
              break;
            case 68:
            case 77:
            case 100:
              if ( v16 != 97 )
                v16 = 100;
              break;
            case 72:
            case 87:
            case 119:
              if ( v16 != 115 )
                v16 = 119;
              break;
            case 80:
            case 83:
            case 115:
              if ( v16 != 119 )
                v16 = 115;
              break;
            default:
              break;
          }
        }
      }
      if ( v16 == 100 )
      {
        v5 = v20 > 23 ? -24 : 1;
        v20 += v5;
      }
      else if ( v16 > 100 )
      {
        if ( v16 == 115 )
        {
          v6 = v19 > 23 ? -24 : 1;
          v19 += v6;
        }
        else if ( v16 == 119 )
        {
          if ( v19 <= 0 )
            v7 = -24;
          else
            v7 = 1;
          v19 -= v7;
        }
      }
      else if ( v16 == 97 )
      {
        if ( v20 <= 0 )
          v4 = -24;
        else
          v4 = 1;
        v20 -= v4;
      }
      if ( v13[25 * v19 + v20] > 1 || v13[25 * v19 + v20] == -2 )
        break;
      if ( v13[25 * v19 + v20] == -1 )
      {
        ++v18;
        do
          i = rand() % 625;
        while ( v13[i] );
        v13[i] = -1;
        sprintf_s(Buffer, 0x20u, "title score:%d", v18 - 4);
        system(Buffer);
      }
      else
      {
        for ( i = 0; i <= 624; ++i )
        {
          if ( v13[i] > 0 )
            --v13[i];
        }
      }
      v13[25 * v19 + v20] = v18;
      for ( i = 0; i <= 1249; ++i )
      {
        if ( v13[i / 2] )
        {
          if ( v13[i / 2] <= 0 )
          {
            if ( v13[i / 2] == -2 )
            {
              if ( (i & 1) != 0 )
                v9 = 93;
              else
                v9 = 91;
              Buffer[i] = v9;
            }
            else
            {
              Buffer[i] = 48;
            }
          }
          else
          {
            if ( (i & 1) != 0 )
              v8 = 41;
            else
              v8 = 40;
            Buffer[i] = v8;
          }
        }
        else
        {
          Buffer[i] = 32;
        }
      }
      system("cls");
      printf(Buffer);
      sub_4020C0(v18);
      Sleep(0x64u);
    }
    if ( isFlag )
    {
      decode_flag(&t_flag);
      strcat(s_flag, &t_flag);
      gameEndmenu(v18, s_flag);
    }
    else
    {
      gameEndmenu(v18, flag);
    }
    result = _getch();
  }
  while ( result == 32 );
  return result;
}

 

在这一段中:

 

判断分数是否达到了60,如果达到了isFlag的值为真,然后解密flag并输出flag,如果没有达到,就会输出"so you cant get flag QWQ"

 

这个时候,如果我们可以修改if的判断条件,让他在判断的时候如果分数没有达到60就跳到解密输出flag中去,就可以轻松得到flag

 

做法如下:

 

对着函数的函数名右键:

 

 

点击Copy to assembly

就会跳转至图形界面中

 

在其中找到isFlag所在的位置:

 

 

 

判断时,是通过jz进行判断的:

于是就知道了达到60分isFlag不为0,没有达到60分就为0

 

那反过来没有达到60分就不为0,就会执行解密flag的操作:

只需将jz 修改成jnz即可:

 

 

 

接下来保存修改:

 

点击ok,保存成功

 

接下来再次运行游戏:

 

 

分数是0分但是获得了flag

 

posted @ 2023-08-21 12:20  Luccky  阅读(59)  评论(0编辑  收藏  举报