攻防世界 game RE

尝试打开
img
大意是说有八个灯,初始全为关闭,须将其全部开启才能得到flag
输入n(1-8)会改变序号为(n-1),n,(n+1)的灯的状态
试了一下,依次输入12345678就能得到flag
img
flagzsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}
好了这题解完了

法一 静态分析

32位无壳 IDA32 打开,搜索main函数

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  int i; // [esp+DCh] [ebp-20h]
  int v5; // [esp+F4h] [ebp-8h] BYREF

  sub_45A7BE(&unk_50B110);
  sub_45A7BE(&unk_50B158);
  sub_45A7BE(&unk_50B1A0);
  sub_45A7BE(&unk_50B1E8);
  sub_45A7BE(&unk_50B230);
  sub_45A7BE(&unk_50B278);
  sub_45A7BE(&unk_50B2C0);
  sub_45A7BE(&unk_50B308);
  sub_45A7BE("二                                                     |\n");
  sub_45A7BE("|              by 0x61                                 |\n");
  sub_45A7BE("|                                                      |\n");
  sub_45A7BE("|------------------------------------------------------|\n");
  sub_45A7BE(
    "Play a game\n"
    "The n is the serial number of the lamp,and m is the state of the lamp\n"
    "If m of the Nth lamp is 1,it's on ,if not it's off\n"
    "At first all the lights were closed\n");
  sub_45A7BE("Now you can input n to change its state\n");
  sub_45A7BE(
    "But you should pay attention to one thing,if you change the state of the Nth lamp,the state of (N-1)th and (N+1)th w"
    "ill be changed too\n");
  sub_45A7BE("When all lamps are on,flag will appear\n");
  sub_45A7BE("Now,input n \n");
  while ( 1 )
  {
    while ( 1 )
    {
      sub_45A7BE("input n,n(1-8)\n");
      sub_459418();
      sub_45A7BE("n=");
      sub_4596D4("%d", &v5);
      sub_45A7BE("\n");
      if ( v5 >= 0 && v5 <= 8 )
        break;
      sub_45A7BE("sorry,n error,try again\n");
    }
    if ( v5 )
    {
      sub_4576D6(v5 - 1);
    }
    else
    {
      for ( i = 0; i < 8; ++i )
      {
        if ( (unsigned int)i >= 9 )
          j____report_rangecheckfailure();
        byte_532E28[i] = 0;
      }
    }
    j__system("CLS");
    sub_458054();
    if ( byte_532E28[0] == 1
      && byte_532E28[1] == 1
      && byte_532E28[2] == 1
      && byte_532E28[3] == 1
      && byte_532E28[4] == 1
      && byte_532E28[5] == 1
      && byte_532E28[6] == 1
      && byte_532E28[7] == 1 )
    {
      sub_457AB4();
    }
  }
}

根据题目意思,很容易定位到最后一个if语句即为判断八个灯是否全开,
从之前调用了'CLS'指令清屏也能大致猜测出来。
那么flag应该就在sub_457AB4这个函数里面,跟进一下

int sub_45E940()
{
  int i; // [esp+D0h] [ebp-94h]
  char v2[22]; // [esp+DCh] [ebp-88h]
  char v3[32]; // [esp+F2h] [ebp-72h] BYREF
  char v4[4]; // [esp+112h] [ebp-52h] BYREF
  char v5[64]; // [esp+120h] [ebp-44h]

  sub_45A7BE("done!!! the flag is ");
  v5[0] = 18;
  v5[1] = 64;
  v5[2] = 98;
  v5[3] = 5;
  v5[4] = 2;
  v5[5] = 4;
  v5[6] = 6;
  v5[7] = 3;
  v5[8] = 6;
  v5[9] = 48;
  v5[10] = 49;
  v5[11] = 65;
  v5[12] = 32;
  v5[13] = 12;
  v5[14] = 48;
  v5[15] = 65;
  v5[16] = 31;
  v5[17] = 78;
  v5[18] = 62;
  v5[19] = 32;
  v5[20] = 49;
  v5[21] = 32;
  v5[22] = 1;
  v5[23] = 57;
  v5[24] = 96;
  v5[25] = 3;
  v5[26] = 21;
  v5[27] = 9;
  v5[28] = 4;
  v5[29] = 62;
  v5[30] = 3;
  v5[31] = 5;
  v5[32] = 4;
  v5[33] = 1;
  v5[34] = 2;
  v5[35] = 3;
  v5[36] = 44;
  v5[37] = 65;
  v5[38] = 78;
  v5[39] = 32;
  v5[40] = 16;
  v5[41] = 97;
  v5[42] = 54;
  v5[43] = 16;
  v5[44] = 44;
  v5[45] = 52;
  v5[46] = 32;
  v5[47] = 64;
  v5[48] = 89;
  v5[49] = 45;
  v5[50] = 32;
  v5[51] = 65;
  v5[52] = 15;
  v5[53] = 34;
  v5[54] = 18;
  v5[55] = 16;
  v5[56] = 0;
  v2[0] = 123;
  v2[1] = 32;
  v2[2] = 18;
  v2[3] = 98;
  v2[4] = 119;
  v2[5] = 108;
  v2[6] = 65;
  v2[7] = 41;
  v2[8] = 124;
  v2[9] = 80;
  v2[10] = 125;
  v2[11] = 38;
  v2[12] = 124;
  v2[13] = 111;
  v2[14] = 74;
  v2[15] = 49;
  v2[16] = 83;
  v2[17] = 108;
  v2[18] = 94;
  v2[19] = 108;
  v2[20] = 84;
  v2[21] = 6;
  qmemcpy(v3, "`S,yhn _uec{", 12);
  v3[12] = 127;
  v3[13] = 119;
  v3[14] = 96;
  v3[15] = 48;
  v3[16] = 107;
  v3[17] = 71;
  v3[18] = 92;
  v3[19] = 29;
  v3[20] = 81;
  v3[21] = 107;
  v3[22] = 90;
  v3[23] = 85;
  v3[24] = 64;
  v3[25] = 12;
  v3[26] = 43;
  v3[27] = 76;
  v3[28] = 86;
  v3[29] = 13;
  v3[30] = 114;
  v3[31] = 1;
  strcpy(v4, "u~");
  for ( i = 0; i < 56; ++i )
  {
    v2[i] ^= v5[i];
    v2[i] ^= 0x13u;
  }
  return sub_45A7BE("%s\n");
}

简单的v2和v5异或,再异或0x13
脚本如下

v5=[18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32,1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44,52,32,64,89,45,32,65,15,34,18,16,0]
v2=[123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49,83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99,123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86,13,114,1,117,126,0]
flag=""
for i in range(56):
    v2[i]^=v5[i]
    v2[i]^=0x13
    flag+=chr(v2[i])
print(flag)

运行结果zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}

法二 广度优先搜索BFS

题目可以转化成相当于一个初始全为0的长度为8的数组,每次操作选一个位置,将其与其相邻共3个数取反(首尾相邻,可看做一个环),一直操作到全部为1。求操作方案。可以采用BFS算法。求出操作方法,然后在程序中依次输入即可。

#include<bits/stdc++.h>
using namespace std;
struct node{
    string s;
    string step;
    node(string s1,string step1){
        s=s1; step=step1;
    }
};
string s="00000000";
map<string,int> f;
queue<node>a;
int main(){
    a.push(node(s,""));
    while(!a.empty()){
        node now=a.front(); a.pop();
        if(f[now.s]==1)continue;
        f[now.s]=1;
        if(now.s=="11111111"){
            cout<<now.step<<endl;
            break;
        }
        for(int i=0; i<8; i++){
            string lamp=now.s;
            if(i!=0) lamp[i-1]=lamp[i-1]=='1'?'0':'1';
            else lamp[7]=lamp[7]=='1'?'0':'1';
            if(i!=7) lamp[i+1]=lamp[i+1]=='1'?'0':'1';
            else lamp[0]=lamp[0]=='1'?'0':'1';
            lamp[i]=lamp[i]=='1'?'0':'1';
            a.push(node(lamp,now.step+(char)(i+49)));
        }
    }
    return 0;
}

最后求出结果是12345678

法三 动态调试

看了别人的wp才知道也可以动调解决,学了一下。
用X32dbg打开
img
右键-搜索-所有用户模块-字符串
img
定位到关键指令'CLS'(因为之前分析过'CLS'后有个关键判断),双击点进去
img
接下来由八个jne指令
这里讲一下jne,je指令

  • je或jz若相等则跳(机器码74或0F84)
  • jne或jnz若不相等则跳(机器码75或0F85)
    则这八个jne指令就是判断灯是否打开
    我们只需修改这里的指令即可
    img
    将jne指令改成jz或直接nop掉
    选中后空格修改两种选一种修改就行
    img
    img
    之后直接F9运行,随便输入数字,就会出现flag
    img
posted @ 2023-02-24 12:23  Tree_24  阅读(118)  评论(0编辑  收藏  举报