首页
社区
课程
招聘
1
[原创]KCTF Q3 第五题:魅影舞姬
发表于: 2019-9-24 03:26 3312

[原创]KCTF Q3 第五题:魅影舞姬

2019-9-24 03:26
3312
IDA载入CM,粗略分析下main函数,如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  _BOOL1 v4; // bl
  __int64 v5; // rax
  void *v6; // rsp
  size_t v7; // rbx
  const char *v8; // rax
  size_t v9; // rbx
  const char *v10; // rax
  size_t v11; // rbx
  const char *v12; // rax
  size_t v13; // rbx
  const char *v14; // rax
  size_t v15; // rbx
  const char *v16; // rax
  __int64 v17; // rax
  __int64 v18; // rax
  unsigned __int8 v20; // [rsp+20h] [rbp-60h]
  char v21; // [rsp+40h] [rbp-40h]
  char v22; // [rsp+50h] [rbp-30h]
  char input8; // [rsp+60h] [rbp-20h]
  char base64de; // [rsp+70h] [rbp-10h]
  unsigned __int64 v25; // [rsp+80h] [rbp+0h]
  unsigned __int64 v26; // [rsp+90h] [rbp+10h]
  char v27; // [rsp+A0h] [rbp+20h]
  char v28; // [rsp+B0h] [rbp+30h]
  char v29; // [rsp+C0h] [rbp+40h]
  char v30; // [rsp+D0h] [rbp+50h]
  char v31; // [rsp+E0h] [rbp+60h]
  char v32; // [rsp+F0h] [rbp+70h]
  char v33; // [rsp+100h] [rbp+80h]
  char v34; // [rsp+110h] [rbp+90h]
  char v35; // [rsp+120h] [rbp+A0h]
  char v36; // [rsp+130h] [rbp+B0h]
  char v37; // [rsp+140h] [rbp+C0h]
  int v38; // [rsp+14Ch] [rbp+CCh]
  char *Str; // [rsp+150h] [rbp+D0h]
  __int64 v40; // [rsp+158h] [rbp+D8h]
 
  _main();
  std::string::string((std::string *)&v26);
  std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "please input your serial:\n");
  std::operator>><char,std::char_traits<char>,std::allocator<char>>(refptr__ZSt3cin, (std::string *)&v26);
  std::string::operator+=(&v26, "Welcome/to/this/very/simple/challenge");
  if ( (unsigned __int64)std::string::length((std::string *)&v26) > 0x55 )// 加上上面的字符串长度不大于0x55
  {
    v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
    std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    system("pause");
  }
  else
  {
    std::string::string((std::string *)&v27, (const std::string *)&v26);
    v4 = !check_fun((__int64)&v27);             // 防多解,调试时可以先跳过
    std::string::~string((std::string *)&v27);
    if ( v4 )
    {
      v5 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
      std::ostream::operator<<(v5, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      system("pause");
    }
    else
    {
      std::string::substr((std::string *)&v28, (const std::string *)&v26, 0i64, 0x24ui64);// 取前36个字符
      base64decode((std::string *)&v25, (std::string *)&v28);// base64解码
      std::string::~string((std::string *)&v28);
      v40 = std::string::length((std::string *)&v26);
      v6 = alloca(16 * ((unsigned __int64)(v40 + 16) >> 4));
      Str = (char *)&v20;
      std::string::substr((std::string *)&v29, (const std::string *)&v25, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
      v7 = std::string::length((std::string *)&v29) + 1;
      std::string::substr((std::string *)&v30, (const std::string *)&v25, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
      v8 = (const char *)std::string::c_str((std::string *)&v30);
      strncpy(&base64de, v8, v7);
      std::string::~string((std::string *)&v30);
      std::string::~string((std::string *)&v29);
      std::string::substr((std::string *)&v31, (const std::string *)&v26, 0i64, 8ui64);
      v9 = std::string::length((std::string *)&v31) + 1;
      std::string::substr((std::string *)&v32, (const std::string *)&v26, 0i64, 8ui64);
      v10 = (const char *)std::string::c_str((std::string *)&v32);
      strncpy(&input8, v10, v9);
      std::string::~string((std::string *)&v32);
      std::string::~string((std::string *)&v31);
      std::string::substr((std::string *)&v33, (const std::string *)&v26, 8ui64, 8ui64);
      v11 = std::string::length((std::string *)&v33) + 1;
      std::string::substr((std::string *)&v34, (const std::string *)&v26, 8ui64, 8ui64);
      v12 = (const char *)std::string::c_str((std::string *)&v34);
      strncpy(&v22, v12, v11);
      std::string::~string((std::string *)&v34);
      std::string::~string((std::string *)&v33);
      std::string::substr((std::string *)&v35, (const std::string *)&v26, 0x10ui64, 8ui64);
      v13 = std::string::length((std::string *)&v35) + 1;
      std::string::substr((std::string *)&v36, (const std::string *)&v26, 0x10ui64, 8ui64);
      v14 = (const char *)std::string::c_str((std::string *)&v36);
      strncpy(&v21, v14, v13);
      std::string::~string((std::string *)&v36);
      std::string::~string((std::string *)&v35);
      v15 = std::string::length((std::string *)&v26) + 1;
      v16 = (const char *)std::string::c_str((std::string *)&v26);
      strncpy(Str, v16, v15);
      desdecrypt(&base64de, &v21, &base64de);   // 用输入字符串的16-23位作为密钥解密
      desencrypt(&base64de, &v22, &base64de);   // 8-15
      v38 = strlen(Str);
      md5(&v20, Str, v38);
      desdecrypt(&base64de, &input8, &base64de);// 0-7
      std::string::replace((std::string *)&v25, 0x12ui64, 8ui64, &base64de);
      std::string::string((std::string *)&v37, (const std::string *)&v25);
      checkgame((const std::string *)&v37);     // 游戏
      std::string::~string((std::string *)&v37);
      if ( (unsigned __int8)std::operator==<char>(&v20, &strmd5) )// 比较输入字符的MD5,防多解
      {
        if ( checkresult == 4 )                 // checkgame函数内检查成功则加1,一共检查4次
          v17 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "correct!");
        else
          v17 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
        std::ostream::operator<<(v17, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      }
      else
      {
        v18 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
        std::ostream::operator<<(v18, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      }
      system("pause");
      std::string::~string((std::string *)&v20);
      std::string::~string((std::string *)&v25);
    }
  }
  std::string::~string((std::string *)&v26);
  return 0;
}
checkgame函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
__int64 __fastcall checkstr(const std::string *a1)
{
  __int64 v2; // [rsp+0h] [rbp-80h]
  char v3; // [rsp+20h] [rbp-60h]
  char v4; // [rsp+30h] [rbp-50h]
  char v5; // [rsp+40h] [rbp-40h]
  char v6; // [rsp+50h] [rbp-30h]
  const std::string *v7; // [rsp+80h] [rbp+0h]
 
  v7 = a1;
  std::string::substr((std::string *)(&v2 + 4), a1, 0i64, 6ui64);// 取base64解码后的6个字节
  checkresult += (unsigned __int8)check((std::string *)&v3);
  std::string::~string((std::string *)&v3);
  replacegame(4, 5);                            // 替换布局,后面都是
  replacegame(9, 10);
  replacegame(10, 11);
  std::string::substr((std::string *)&v4, v7, 6ui64, 6ui64);
  checkresult += (unsigned __int8)check((std::string *)&v4);
  std::string::~string((std::string *)&v4);
  replacegame(5, 7);
  replacegame(9, 12);
  replacegame(11, 12);
  std::string::substr((std::string *)&v5, v7, 0xCui64, 6ui64);
  checkresult += (unsigned __int8)check((std::string *)&v5);
  std::string::~string((std::string *)&v5);
  replacegame(2, 12);
  replace(7, 9);
  replace(5, 3);
  replace(5, 11);
  replace(4, 7);
  replace(4, 8);
  std::string::substr((std::string *)&v6, v7, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
  checkresult += (unsigned __int8)check((std::string *)&v6);
  return std::string::~string((std::string *)&v6);
}
check函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
_BOOL8 __fastcall check(std::string *a1)
{
  int v1; // eax
  _BOOL1 v2; // al
  signed int j; // [rsp+2Ch] [rbp-14h]
  unsigned __int64 i; // [rsp+30h] [rbp-10h]
  int v6; // [rsp+3Ch] [rbp-4h]
  std::string *v7; // [rsp+50h] [rbp+10h]
 
  v7 = a1;
  v6 = std::string::find((std::string *)&str, '@', 0i64);// 从'@'开始
  for ( i = 0i64; std::string::length(v7) > i; ++i )// 一字节可以走4步,每次只有6字节(最后一个不是),所以在24步之内走到终点即可
  {
    for ( j = 6; j >= 0; j -= 2 )
    {
      v1 = ((signed int)*(unsigned __int8 *)std::string::operator[](v7, i) >> j) & 3;
      if ( v1 == 1 )                            // down
      {
        v6 += 13;
      }
      else if ( v1 > 1 )
      {
        if ( v1 == 2 )                          // left
        {
          --v6;
        }
        else if ( v1 == 3 )                     // right
        {
          ++v6;
        }
      }
      else if ( !v1 )                           // up
      {
        v6 -= 13;
      }
      v2 = *(_BYTE *)std::string::operator[](&str, v6) != '-' && *(_BYTE *)std::string::operator[](&str, v6) != '#';// '@'碰到'-'则失败
      if ( v2 )
        return 0i64;                            // '@'到达'#'则成功
    }
  }
  return *(_BYTE *)std::string::operator[](&str, v6) == '#';
}

动态调试抓取到4个游戏布局,如下
*************
*@***********
*-***********
*--**----****
*-***-**-****
*-***#**-****
*--*****-****
**-*****-****
**-------****
**-*-----****
**---**-*****
**-****--****
*************
111113113333330000022211

*************
*@***********
*-***********
*-***-**-****
*--**----****
*-***#**-****
*--*****-****
**-*****-****
**-*-----****
**---**-*****
**-------****
**-****--****
*************
111113111330333300002221

*************
*@***********
*-***********
*-***-**-****
*--*****-****
*-***#**-****
*--**----****
**-*****-****
**-****--****
**---**-*****
**-*-----****
**-------****
*************
111113111331333003002220

*************
**-------****
*--*****-****
*-***-**-****
*--*****-****
*-***#**-****
*-***-**-****
*-***-**-****
*--**----****
**---**-*****
*--*****-****
*@***********
*************
03002000000303333331111111222000
最后一个并不是24步而是32步,将所有步数加起来除以4等于26。
前面用来base64解码的字符串有36个,如果没有"=",解码后的字节数是27个,所以flag有一个等号。
将步骤恢复成6个字节,再base64编码,注意后8个字节需要DES处理一下。
IDA载入CM,粗略分析下main函数,如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  _BOOL1 v4; // bl
  __int64 v5; // rax
  void *v6; // rsp
  size_t v7; // rbx
  const char *v8; // rax
  size_t v9; // rbx
  const char *v10; // rax
  size_t v11; // rbx
  const char *v12; // rax
  size_t v13; // rbx
  const char *v14; // rax
  size_t v15; // rbx
  const char *v16; // rax
  __int64 v17; // rax
  __int64 v18; // rax
  unsigned __int8 v20; // [rsp+20h] [rbp-60h]
  char v21; // [rsp+40h] [rbp-40h]
  char v22; // [rsp+50h] [rbp-30h]
  char input8; // [rsp+60h] [rbp-20h]
  char base64de; // [rsp+70h] [rbp-10h]
  unsigned __int64 v25; // [rsp+80h] [rbp+0h]
  unsigned __int64 v26; // [rsp+90h] [rbp+10h]
  char v27; // [rsp+A0h] [rbp+20h]
  char v28; // [rsp+B0h] [rbp+30h]
  char v29; // [rsp+C0h] [rbp+40h]
  char v30; // [rsp+D0h] [rbp+50h]
  char v31; // [rsp+E0h] [rbp+60h]
  char v32; // [rsp+F0h] [rbp+70h]
  char v33; // [rsp+100h] [rbp+80h]
  char v34; // [rsp+110h] [rbp+90h]
  char v35; // [rsp+120h] [rbp+A0h]
  char v36; // [rsp+130h] [rbp+B0h]
  char v37; // [rsp+140h] [rbp+C0h]
  int v38; // [rsp+14Ch] [rbp+CCh]
  char *Str; // [rsp+150h] [rbp+D0h]
  __int64 v40; // [rsp+158h] [rbp+D8h]
 
  _main();
  std::string::string((std::string *)&v26);
  std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "please input your serial:\n");
  std::operator>><char,std::char_traits<char>,std::allocator<char>>(refptr__ZSt3cin, (std::string *)&v26);
  std::string::operator+=(&v26, "Welcome/to/this/very/simple/challenge");
  if ( (unsigned __int64)std::string::length((std::string *)&v26) > 0x55 )// 加上上面的字符串长度不大于0x55
  {
    v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
    std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    system("pause");
  }
  else
  {
    std::string::string((std::string *)&v27, (const std::string *)&v26);
    v4 = !check_fun((__int64)&v27);             // 防多解,调试时可以先跳过
    std::string::~string((std::string *)&v27);
    if ( v4 )
    {
      v5 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
      std::ostream::operator<<(v5, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      system("pause");
    }
    else
    {
      std::string::substr((std::string *)&v28, (const std::string *)&v26, 0i64, 0x24ui64);// 取前36个字符
      base64decode((std::string *)&v25, (std::string *)&v28);// base64解码
      std::string::~string((std::string *)&v28);
      v40 = std::string::length((std::string *)&v26);
      v6 = alloca(16 * ((unsigned __int64)(v40 + 16) >> 4));
      Str = (char *)&v20;
      std::string::substr((std::string *)&v29, (const std::string *)&v25, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
      v7 = std::string::length((std::string *)&v29) + 1;
      std::string::substr((std::string *)&v30, (const std::string *)&v25, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
      v8 = (const char *)std::string::c_str((std::string *)&v30);
      strncpy(&base64de, v8, v7);
      std::string::~string((std::string *)&v30);
      std::string::~string((std::string *)&v29);
      std::string::substr((std::string *)&v31, (const std::string *)&v26, 0i64, 8ui64);
      v9 = std::string::length((std::string *)&v31) + 1;
      std::string::substr((std::string *)&v32, (const std::string *)&v26, 0i64, 8ui64);
      v10 = (const char *)std::string::c_str((std::string *)&v32);
      strncpy(&input8, v10, v9);
      std::string::~string((std::string *)&v32);
      std::string::~string((std::string *)&v31);
      std::string::substr((std::string *)&v33, (const std::string *)&v26, 8ui64, 8ui64);
      v11 = std::string::length((std::string *)&v33) + 1;
      std::string::substr((std::string *)&v34, (const std::string *)&v26, 8ui64, 8ui64);
      v12 = (const char *)std::string::c_str((std::string *)&v34);
      strncpy(&v22, v12, v11);
      std::string::~string((std::string *)&v34);
      std::string::~string((std::string *)&v33);
      std::string::substr((std::string *)&v35, (const std::string *)&v26, 0x10ui64, 8ui64);
      v13 = std::string::length((std::string *)&v35) + 1;
      std::string::substr((std::string *)&v36, (const std::string *)&v26, 0x10ui64, 8ui64);
      v14 = (const char *)std::string::c_str((std::string *)&v36);
      strncpy(&v21, v14, v13);
      std::string::~string((std::string *)&v36);
      std::string::~string((std::string *)&v35);
      v15 = std::string::length((std::string *)&v26) + 1;
      v16 = (const char *)std::string::c_str((std::string *)&v26);
      strncpy(Str, v16, v15);
      desdecrypt(&base64de, &v21, &base64de);   // 用输入字符串的16-23位作为密钥解密
      desencrypt(&base64de, &v22, &base64de);   // 8-15
      v38 = strlen(Str);
      md5(&v20, Str, v38);
      desdecrypt(&base64de, &input8, &base64de);// 0-7
      std::string::replace((std::string *)&v25, 0x12ui64, 8ui64, &base64de);
      std::string::string((std::string *)&v37, (const std::string *)&v25);
      checkgame((const std::string *)&v37);     // 游戏
      std::string::~string((std::string *)&v37);
      if ( (unsigned __int8)std::operator==<char>(&v20, &strmd5) )// 比较输入字符的MD5,防多解
      {
        if ( checkresult == 4 )                 // checkgame函数内检查成功则加1,一共检查4次
          v17 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "correct!");
        else
          v17 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
        std::ostream::operator<<(v17, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      }
      else
      {
        v18 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
        std::ostream::operator<<(v18, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      }
      system("pause");
      std::string::~string((std::string *)&v20);
      std::string::~string((std::string *)&v25);
    }
  }
  std::string::~string((std::string *)&v26);
  return 0;
}
checkgame函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  _BOOL1 v4; // bl
  __int64 v5; // rax
  void *v6; // rsp
  size_t v7; // rbx
  const char *v8; // rax
  size_t v9; // rbx
  const char *v10; // rax
  size_t v11; // rbx
  const char *v12; // rax
  size_t v13; // rbx
  const char *v14; // rax
  size_t v15; // rbx
  const char *v16; // rax
  __int64 v17; // rax
  __int64 v18; // rax
  unsigned __int8 v20; // [rsp+20h] [rbp-60h]
  char v21; // [rsp+40h] [rbp-40h]
  char v22; // [rsp+50h] [rbp-30h]
  char input8; // [rsp+60h] [rbp-20h]
  char base64de; // [rsp+70h] [rbp-10h]
  unsigned __int64 v25; // [rsp+80h] [rbp+0h]
  unsigned __int64 v26; // [rsp+90h] [rbp+10h]
  char v27; // [rsp+A0h] [rbp+20h]
  char v28; // [rsp+B0h] [rbp+30h]
  char v29; // [rsp+C0h] [rbp+40h]
  char v30; // [rsp+D0h] [rbp+50h]
  char v31; // [rsp+E0h] [rbp+60h]
  char v32; // [rsp+F0h] [rbp+70h]
  char v33; // [rsp+100h] [rbp+80h]
  char v34; // [rsp+110h] [rbp+90h]
  char v35; // [rsp+120h] [rbp+A0h]
  char v36; // [rsp+130h] [rbp+B0h]
  char v37; // [rsp+140h] [rbp+C0h]
  int v38; // [rsp+14Ch] [rbp+CCh]
  char *Str; // [rsp+150h] [rbp+D0h]
  __int64 v40; // [rsp+158h] [rbp+D8h]
 
  _main();
  std::string::string((std::string *)&v26);
  std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "please input your serial:\n");
  std::operator>><char,std::char_traits<char>,std::allocator<char>>(refptr__ZSt3cin, (std::string *)&v26);
  std::string::operator+=(&v26, "Welcome/to/this/very/simple/challenge");
  if ( (unsigned __int64)std::string::length((std::string *)&v26) > 0x55 )// 加上上面的字符串长度不大于0x55
  {
    v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
    std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    system("pause");
  }
  else
  {
    std::string::string((std::string *)&v27, (const std::string *)&v26);
    v4 = !check_fun((__int64)&v27);             // 防多解,调试时可以先跳过
    std::string::~string((std::string *)&v27);
    if ( v4 )
    {
      v5 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
      std::ostream::operator<<(v5, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      system("pause");
    }
    else
    {
      std::string::substr((std::string *)&v28, (const std::string *)&v26, 0i64, 0x24ui64);// 取前36个字符
      base64decode((std::string *)&v25, (std::string *)&v28);// base64解码
      std::string::~string((std::string *)&v28);
      v40 = std::string::length((std::string *)&v26);
      v6 = alloca(16 * ((unsigned __int64)(v40 + 16) >> 4));
      Str = (char *)&v20;
      std::string::substr((std::string *)&v29, (const std::string *)&v25, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
      v7 = std::string::length((std::string *)&v29) + 1;
      std::string::substr((std::string *)&v30, (const std::string *)&v25, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
      v8 = (const char *)std::string::c_str((std::string *)&v30);
      strncpy(&base64de, v8, v7);
      std::string::~string((std::string *)&v30);
      std::string::~string((std::string *)&v29);
      std::string::substr((std::string *)&v31, (const std::string *)&v26, 0i64, 8ui64);
      v9 = std::string::length((std::string *)&v31) + 1;
      std::string::substr((std::string *)&v32, (const std::string *)&v26, 0i64, 8ui64);
      v10 = (const char *)std::string::c_str((std::string *)&v32);
      strncpy(&input8, v10, v9);
      std::string::~string((std::string *)&v32);
      std::string::~string((std::string *)&v31);
      std::string::substr((std::string *)&v33, (const std::string *)&v26, 8ui64, 8ui64);
      v11 = std::string::length((std::string *)&v33) + 1;
      std::string::substr((std::string *)&v34, (const std::string *)&v26, 8ui64, 8ui64);
      v12 = (const char *)std::string::c_str((std::string *)&v34);
      strncpy(&v22, v12, v11);
      std::string::~string((std::string *)&v34);
      std::string::~string((std::string *)&v33);
      std::string::substr((std::string *)&v35, (const std::string *)&v26, 0x10ui64, 8ui64);
      v13 = std::string::length((std::string *)&v35) + 1;
      std::string::substr((std::string *)&v36, (const std::string *)&v26, 0x10ui64, 8ui64);
      v14 = (const char *)std::string::c_str((std::string *)&v36);
      strncpy(&v21, v14, v13);
      std::string::~string((std::string *)&v36);
      std::string::~string((std::string *)&v35);
      v15 = std::string::length((std::string *)&v26) + 1;
      v16 = (const char *)std::string::c_str((std::string *)&v26);
      strncpy(Str, v16, v15);
      desdecrypt(&base64de, &v21, &base64de);   // 用输入字符串的16-23位作为密钥解密
      desencrypt(&base64de, &v22, &base64de);   // 8-15
      v38 = strlen(Str);
      md5(&v20, Str, v38);
      desdecrypt(&base64de, &input8, &base64de);// 0-7
      std::string::replace((std::string *)&v25, 0x12ui64, 8ui64, &base64de);
      std::string::string((std::string *)&v37, (const std::string *)&v25);
      checkgame((const std::string *)&v37);     // 游戏
      std::string::~string((std::string *)&v37);
      if ( (unsigned __int8)std::operator==<char>(&v20, &strmd5) )// 比较输入字符的MD5,防多解
      {
        if ( checkresult == 4 )                 // checkgame函数内检查成功则加1,一共检查4次
          v17 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "correct!");
        else
          v17 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
        std::ostream::operator<<(v17, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      }
      else
      {
        v18 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "incorrect!");
        std::ostream::operator<<(v18, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      }
      system("pause");
      std::string::~string((std::string *)&v20);
      std::string::~string((std::string *)&v25);
    }
  }
  std::string::~string((std::string *)&v26);
  return 0;
}
checkgame函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
__int64 __fastcall checkstr(const std::string *a1)
{
  __int64 v2; // [rsp+0h] [rbp-80h]
  char v3; // [rsp+20h] [rbp-60h]
  char v4; // [rsp+30h] [rbp-50h]
  char v5; // [rsp+40h] [rbp-40h]
  char v6; // [rsp+50h] [rbp-30h]
  const std::string *v7; // [rsp+80h] [rbp+0h]
 
  v7 = a1;
  std::string::substr((std::string *)(&v2 + 4), a1, 0i64, 6ui64);// 取base64解码后的6个字节
  checkresult += (unsigned __int8)check((std::string *)&v3);
  std::string::~string((std::string *)&v3);
  replacegame(4, 5);                            // 替换布局,后面都是
  replacegame(9, 10);
  replacegame(10, 11);
  std::string::substr((std::string *)&v4, v7, 6ui64, 6ui64);
  checkresult += (unsigned __int8)check((std::string *)&v4);
  std::string::~string((std::string *)&v4);
  replacegame(5, 7);
  replacegame(9, 12);
  replacegame(11, 12);
  std::string::substr((std::string *)&v5, v7, 0xCui64, 6ui64);
  checkresult += (unsigned __int8)check((std::string *)&v5);
  std::string::~string((std::string *)&v5);
  replacegame(2, 12);
  replace(7, 9);
  replace(5, 3);
  replace(5, 11);
  replace(4, 7);
  replace(4, 8);
  std::string::substr((std::string *)&v6, v7, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
  checkresult += (unsigned __int8)check((std::string *)&v6);
  return std::string::~string((std::string *)&v6);
}
check函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
__int64 __fastcall checkstr(const std::string *a1)
{
  __int64 v2; // [rsp+0h] [rbp-80h]
  char v3; // [rsp+20h] [rbp-60h]
  char v4; // [rsp+30h] [rbp-50h]
  char v5; // [rsp+40h] [rbp-40h]
  char v6; // [rsp+50h] [rbp-30h]
  const std::string *v7; // [rsp+80h] [rbp+0h]
 
  v7 = a1;
  std::string::substr((std::string *)(&v2 + 4), a1, 0i64, 6ui64);// 取base64解码后的6个字节
  checkresult += (unsigned __int8)check((std::string *)&v3);
  std::string::~string((std::string *)&v3);
  replacegame(4, 5);                            // 替换布局,后面都是
  replacegame(9, 10);
  replacegame(10, 11);
  std::string::substr((std::string *)&v4, v7, 6ui64, 6ui64);
  checkresult += (unsigned __int8)check((std::string *)&v4);
  std::string::~string((std::string *)&v4);
  replacegame(5, 7);
  replacegame(9, 12);
  replacegame(11, 12);
  std::string::substr((std::string *)&v5, v7, 0xCui64, 6ui64);
  checkresult += (unsigned __int8)check((std::string *)&v5);
  std::string::~string((std::string *)&v5);
  replacegame(2, 12);
  replace(7, 9);
  replace(5, 3);
  replace(5, 11);
  replace(4, 7);
  replace(4, 8);
  std::string::substr((std::string *)&v6, v7, 0x12ui64, 0xFFFFFFFFFFFFFFFFui64);
  checkresult += (unsigned __int8)check((std::string *)&v6);
  return std::string::~string((std::string *)&v6);
}
check函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
_BOOL8 __fastcall check(std::string *a1)
{
  int v1; // eax
  _BOOL1 v2; // al
  signed int j; // [rsp+2Ch] [rbp-14h]
  unsigned __int64 i; // [rsp+30h] [rbp-10h]
  int v6; // [rsp+3Ch] [rbp-4h]
  std::string *v7; // [rsp+50h] [rbp+10h]
 
  v7 = a1;
  v6 = std::string::find((std::string *)&str, '@', 0i64);// 从'@'开始
  for ( i = 0i64; std::string::length(v7) > i; ++i )// 一字节可以走4步,每次只有6字节(最后一个不是),所以在24步之内走到终点即可
  {
    for ( j = 6; j >= 0; j -= 2 )
    {
      v1 = ((signed int)*(unsigned __int8 *)std::string::operator[](v7, i) >> j) & 3;
      if ( v1 == 1 )                            // down
      {
        v6 += 13;
      }
      else if ( v1 > 1 )
      {
        if ( v1 == 2 )                          // left
        {
          --v6;
        }
        else if ( v1 == 3 )                     // right
        {
          ++v6;
        }
      }
      else if ( !v1 )                           // up
      {
        v6 -= 13;
      }
      v2 = *(_BYTE *)std::string::operator[](&str, v6) != '-' && *(_BYTE *)std::string::operator[](&str, v6) != '#';// '@'碰到'-'则失败
      if ( v2 )
        return 0i64;                            // '@'到达'#'则成功
    }
  }
  return *(_BYTE *)std::string::operator[](&str, v6) == '#';
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
_BOOL8 __fastcall check(std::string *a1)
{
  int v1; // eax
  _BOOL1 v2; // al
  signed int j; // [rsp+2Ch] [rbp-14h]
  unsigned __int64 i; // [rsp+30h] [rbp-10h]
  int v6; // [rsp+3Ch] [rbp-4h]
  std::string *v7; // [rsp+50h] [rbp+10h]
 
  v7 = a1;
  v6 = std::string::find((std::string *)&str, '@', 0i64);// 从'@'开始
  for ( i = 0i64; std::string::length(v7) > i; ++i )// 一字节可以走4步,每次只有6字节(最后一个不是),所以在24步之内走到终点即可
  {
    for ( j = 6; j >= 0; j -= 2 )
    {
      v1 = ((signed int)*(unsigned __int8 *)std::string::operator[](v7, i) >> j) & 3;
      if ( v1 == 1 )                            // down
      {
        v6 += 13;
      }
      else if ( v1 > 1 )
      {
        if ( v1 == 2 )                          // left
        {
          --v6;
        }
        else if ( v1 == 3 )                     // right
        {
          ++v6;
        }
      }
      else if ( !v1 )                           // up
      {
        v6 -= 13;
      }
      v2 = *(_BYTE *)std::string::operator[](&str, v6) != '-' && *(_BYTE *)std::string::operator[](&str, v6) != '#';// '@'碰到'-'则失败
      if ( v2 )
        return 0i64;                            // '@'到达'#'则成功
    }
  }
  return *(_BYTE *)std::string::operator[](&str, v6) == '#';
}

动态调试抓取到4个游戏布局,如下
*************
*@***********
*-***********
*--**----****
*-***-**-****
*-***#**-****
*--*****-****
**-*****-****
**-------****
**-*-----****
**---**-*****
**-****--****
*************
111113113333330000022211

*************
*@***********
*-***********
*-***-**-****
*--**----****
*-***#**-****
*--*****-****
**-*****-****
**-*-----****
**---**-*****
**-------****
**-****--****
*************
111113111330333300002221

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2023-1-22 04:11
最新回复 (0)
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册