首页
社区
课程
招聘
5
[原创]KCTF2019_q4_第十题_幕后之王
发表于: 2019-12-30 16:12 7817

[原创]KCTF2019_q4_第十题_幕后之王

ccfer 活跃值
16
2019-12-30 16:12
7817
这个迷宫题目还是挺有意思的,后来发现可以多解碰撞crc,就觉得更有意思了

这个程序有tls和几处anti,还是要稍微小心一点
401660  CheckRemoteDebuggerPresent
4015E0  NtQueryInformationProcess
401710  GetThreadContext 检查drx之和
401690  setjmp3/SetUnhandledExceptionFilter

输入处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.text:004B5370                 sub     eax, 004BA040h           //"6GxRI4XlsLDQoVfb7pgE8hcYHaUtWZwKBPyNvuCSF3d0e2JA9q5jrTMOzknim1"
.text:004B5375                 test    al, al
.text:004B5377                 mov     [ebp+ebx+var_264], al    //base64 decode
...
.text:004B539E                 sub     eax, 12h                 //前18个字符
.text:004B53A1                 cmp     eax, 5Dh                 //后93个字符
.text:004B53A4                 ja      loc_4B55EC               //输入总长度不超过112
...
.text:004B53AA                 lea     ecx, [ebp+var_1E4]
.text:004B53B0                 mov     [ebp+var_298], 1
.text:004B53BA                 call    sub_4017A0               //初始化迷宫数据
.text:004B53BF                 lea     eax, [ebp+var_25B]
.text:004B53C5                 lea     ecx, [ebp+var_1E4]
.text:004B53CB                 mov     [esp+2C8h+var_2C4], eax
.text:004B53CF                 lea     eax, [ebp+var_264]
.text:004B53D5                 mov     [esp+2C8h+var_2C8], eax
.text:004B53D8                 call    sub_401BD0               //初始化几个大数,主要的是把输入的前18个字符拆分成两个大数x,y,还有一个固定的常数z
加密的迷宫初始数据,四个关卡,每关地图大小是6x5:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.text:004B5370                 sub     eax, 004BA040h           //"6GxRI4XlsLDQoVfb7pgE8hcYHaUtWZwKBPyNvuCSF3d0e2JA9q5jrTMOzknim1"
.text:004B5375                 test    al, al
.text:004B5377                 mov     [ebp+ebx+var_264], al    //base64 decode
...
.text:004B539E                 sub     eax, 12h                 //前18个字符
.text:004B53A1                 cmp     eax, 5Dh                 //后93个字符
.text:004B53A4                 ja      loc_4B55EC               //输入总长度不超过112
...
.text:004B53AA                 lea     ecx, [ebp+var_1E4]
.text:004B53B0                 mov     [ebp+var_298], 1
.text:004B53BA                 call    sub_4017A0               //初始化迷宫数据
.text:004B53BF                 lea     eax, [ebp+var_25B]
.text:004B53C5                 lea     ecx, [ebp+var_1E4]
.text:004B53CB                 mov     [esp+2C8h+var_2C4], eax
.text:004B53CF                 lea     eax, [ebp+var_264]
.text:004B53D5                 mov     [esp+2C8h+var_2C8], eax
.text:004B53D8                 call    sub_401BD0               //初始化几个大数,主要的是把输入的前18个字符拆分成两个大数x,y,还有一个固定的常数z
加密的迷宫初始数据,四个关卡,每关地图大小是6x5:
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
02 13 00 00 07 
07 04 05 0B 0A 
09 08 0E 0E 0C 
0C 12 13 11 01 
36 16 15 15 1B 
2B 19 18 1E 1C 
 
1E 1D 32 23 20 
20 27 26 24 24 
2B 3B 29 29 2F 
2F 2D 2C 33 32 
31 30 37 36 34 
34 2A 3B 39 3A 
 
3C 2F 1C 3C 43 
43 40 40 47 77 
44 44 4B 4A 49 
49 4F 4E 4D 4C 
53 43 50 50 56 
47 54 55 5B 58 
 
5A 58 5F 5E 6C 
4D 63 73 61 60 
66 66 64 65 6A 
6A 69 68 7E 6E 
6D 6C 72 72 71 
41 76 76 75 76
几个关键函数:
sub_401DE0 会被多处调用的函数,调试分析得知是个寻路判断函数,返回值表示两个点之间是可到达,同时也可看到迷宫数据解密算法,算法比较简单xor个密钥再xor个索引序号
先用初始迷宫密钥3解密出明文迷宫数据,方便后面描述:
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
02 13 00 00 07 
07 04 05 0B 0A 
09 08 0E 0E 0C 
0C 12 13 11 01 
36 16 15 15 1B 
2B 19 18 1E 1C 
 
1E 1D 32 23 20 
20 27 26 24 24 
2B 3B 29 29 2F 
2F 2D 2C 33 32 
31 30 37 36 34 
34 2A 3B 39 3A 
 
3C 2F 1C 3C 43 
43 40 40 47 77 
44 44 4B 4A 49 
49 4F 4E 4D 4C 
53 43 50 50 56 
47 54 55 5B 58 
 
5A 58 5F 5E 6C 
4D 63 73 61 60 
66 66 64 65 6A 
6A 69 68 7E 6E 
6D 6C 72 72 71 
41 76 76 75 76
几个关键函数:
sub_401DE0 会被多处调用的函数,调试分析得知是个寻路判断函数,返回值表示两个点之间是可到达,同时也可看到迷宫数据解密算法,算法比较简单xor个密钥再xor个索引序号
先用初始迷宫密钥3解密出明文迷宫数据,方便后面描述:
几个关键函数:
sub_401DE0 会被多处调用的函数,调试分析得知是个寻路判断函数,返回值表示两个点之间是可到达,同时也可看到迷宫数据解密算法,算法比较简单xor个密钥再xor个索引序号
先用初始迷宫密钥3解密出明文迷宫数据,方便后面描述:
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
01 11 01 00 00 
01 01 01 00 00 
00 00 01 00 01 
00 01 01 00 11 
21 00 00 01 00 
31 00 00 01 02 
 
03 01 11 01 01 
00 00 00 01 00 
00 11 00 01 00 
01 00 00 00 00 
00 00 00 00 01 
00 11 01 00 02 
 
03 11 21 00 00 
01 01 00 00 31 
01 00 00 00 00 
01 00 00 00 00 
00 11 01 00 01 
11 01 01 00 02 
 
03 00 00 00 31
11 00 11 00 00
01 00 01 01 01
00 00 00 11 00
00 00 01 00 00
31 01 00 00 02
从上面寻路判断函数中可以分析出:地图中的数值低4位是1表示该点可走,如果是0且下一层是1x表示空洞下面被垫高了也可同样可走

sub_402460 走到指定位置,如遇到道具会自动拾取,0x31道具可以改变密钥
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
01 11 01 00 00 
01 01 01 00 00 
00 00 01 00 01 
00 01 01 00 11 
21 00 00 01 00 
31 00 00 01 02 
 
03 01 11 01 01 
00 00 00 01 00 
00 11 00 01 00 
01 00 00 00 00 
00 00 00 00 01 
00 11 01 00 02 
 
03 11 21 00 00 
01 01 00 00 31 
01 00 00 00 00 
01 00 00 00 00 
00 11 01 00 01 
11 01 01 00 02 
 
03 00 00 00 31
11 00 11 00 00
01 00 01 01 01
00 00 00 11 00
00 00 01 00 00
31 01 00 00 02
从上面寻路判断函数中可以分析出:地图中的数值低4位是1表示该点可走,如果是0且下一层是1x表示空洞下面被垫高了也可同样可走

sub_402460 走到指定位置,如遇到道具会自动拾取,0x31道具可以改变密钥
从上面寻路判断函数中可以分析出:地图中的数值低4位是1表示该点可走,如果是0且下一层是1x表示空洞下面被垫高了也可同样可走

sub_402460 走到指定位置,如遇到道具会自动拾取,0x31道具可以改变密钥
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
sub_402460()
{
  ...
  if ( (v10 & 0xF) == 1 )
  {
    *((_DWORD *)v2 + 2) = x;
    *((_DWORD *)v2 + 3) = y;
    if ( (signed int)v10 >> 4 == 3 )                                    //0x31类型道具
    {
      v23[20] = v19 ^ (v22 + y) ^ ((v22 + y) ^ v9) & 0xF;
      v12 = *((_DWORD *)v2 + 0x65) == 1;
      *((_DWORD *)v2 + 4) = 3 * ((*((_DWORD *)v2 + 4) + 2) >> 1);       //w = (w+2)/2*3,w初始值是3,经过3次迭代会等于十进制的33
      if ( v12 && v19 == 3 )
      {
        v2[0x198] = 0x37;                                               //第一次拾取0x31道具,修改迷宫密钥为k = 0x37
        v13 = 0x37;
      }
      else
      {
        sub_401AB0(v2 + 0x110, v2 + 0x110, v2 + 0x8C);                  //大数乘法 a *= x
        sub_401AB0(v2 + 0x13C, v2 + 0x13C, v2 + 0xB8);                  //大数乘法 b *= y
        sub_401AB0(v2 + 0x168, v2 + 0x168, v2 + 0xE4);                  //大数乘法 c *= z
        sub_4019F0(v2 + 0x194, v2 + 0x110, v2 + 0x13C, v2 + 0x168);     //修改密钥 k = a - b - c
        v13 = v2[0x198];
      }
      //变更密钥后,需要对数据用新密钥重新加密
      v14 = v2 + 0x32;
      v15 = v2 + 0xAA;
      v16 = v13 ^ v19;
      do
      {
        v17 = v14 - 30;
        do
        {
          v18 = (int)(v17 + 5);
          do
            *v17++ ^= v16;
          while ( v17 != (_BYTE *)v18 );
        }
        while ( v17 != v14 );
        v14 += 30;
      }
      while ( v14 != v15 );
    }
  }
  return 0;
}
sub_4026A0 指定位置使用道具,从使用道具的函数里可以分析出:迷宫是逐个关卡从低到高立体层叠的,0x11道具可以从空洞掉落到下一层,下一层是空洞会继续掉落下去

sub_402400 判断是否可进入上一关,如果可到达,则会来到上一关的右下角坐标(5,4)

sub_402380 判断是否可进入下一关,如果可到达,则会来到下一关的左上角坐标(0,0)
.text:004023CE                 movzx   eax, byte ptr [ebx+198h]
.text:004023D5                 cmp     [ebx+10h], eax                   //检查最终密钥 if (k == w)
.text:004023D8                 jnz     short loc_4023F0
这个检查的含义是输入的前18个字符组成的大数需要特定的值

所有游戏的主体就用输入的key控制走路过程,从每层的左上角走到右下角进入下一关,直到第4关通关
单独看每一关的话,6x5的地图,似乎也并不复杂,就手动走着玩玩
因为高层的道具会掉落下去的原因,有时需要返回前面低级关卡,处理给适当的位置垫高的问题
开始也是拾取过第一关的道具,走到第三关后没路走不下去了

多次尝试后,发现拾取道具是个负担,无视道具反而容易看清路线,就想到了试试不拾取0x31道具能不能走通,
竟然真的走通了,路线步骤,如下:
01 12 13 06 3B 0B 0D 1E 06 17 3B 02 12 3B 01 10 1E 1E 10 06 3B 0D 0B 1E 06 10 17 0C 3B 0B 10 1E 10 1C 0C 17 3B 1A 12 1E 1C 11 3B 12 10 3B 19 17 15 17 3B 05 06 07 17 12 18 3B
每个步骤转成平面坐标表示是(v/5,v%5)
其中那些小于0x1E步骤都是两个一组,从一个位置拿到0x11类型的箱子,扔到另一个位置的0x00空洞里
0x1E是回到上一关,0x3B是进入下一关

迷宫虽然走通了,但是后面却有个crc判断:
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
sub_402460()
{
  ...
  if ( (v10 & 0xF) == 1 )
  {
    *((_DWORD *)v2 + 2) = x;
    *((_DWORD *)v2 + 3) = y;
    if ( (signed int)v10 >> 4 == 3 )                                    //0x31类型道具
    {
      v23[20] = v19 ^ (v22 + y) ^ ((v22 + y) ^ v9) & 0xF;
      v12 = *((_DWORD *)v2 + 0x65) == 1;
      *((_DWORD *)v2 + 4) = 3 * ((*((_DWORD *)v2 + 4) + 2) >> 1);       //w = (w+2)/2*3,w初始值是3,经过3次迭代会等于十进制的33
      if ( v12 && v19 == 3 )
      {
        v2[0x198] = 0x37;                                               //第一次拾取0x31道具,修改迷宫密钥为k = 0x37
        v13 = 0x37;
      }
      else
      {
        sub_401AB0(v2 + 0x110, v2 + 0x110, v2 + 0x8C);                  //大数乘法 a *= x
        sub_401AB0(v2 + 0x13C, v2 + 0x13C, v2 + 0xB8);                  //大数乘法 b *= y
        sub_401AB0(v2 + 0x168, v2 + 0x168, v2 + 0xE4);                  //大数乘法 c *= z
        sub_4019F0(v2 + 0x194, v2 + 0x110, v2 + 0x13C, v2 + 0x168);     //修改密钥 k = a - b - c
        v13 = v2[0x198];
      }
      //变更密钥后,需要对数据用新密钥重新加密
      v14 = v2 + 0x32;
      v15 = v2 + 0xAA;
      v16 = v13 ^ v19;
      do
      {
        v17 = v14 - 30;
        do
        {
          v18 = (int)(v17 + 5);
          do
            *v17++ ^= v16;
          while ( v17 != (_BYTE *)v18 );
        }
        while ( v17 != v14 );
        v14 += 30;
      }
      while ( v14 != v15 );
    }
  }
  return 0;
}
sub_4026A0 指定位置使用道具,从使用道具的函数里可以分析出:迷宫是逐个关卡从低到高立体层叠的,0x11道具可以从空洞掉落到下一层,下一层是空洞会继续掉落下去

sub_402400 判断是否可进入上一关,如果可到达,则会来到上一关的右下角坐标(5,4)

sub_402380 判断是否可进入下一关,如果可到达,则会来到下一关的左上角坐标(0,0)
.text:004023CE                 movzx   eax, byte ptr [ebx+198h]
.text:004023D5                 cmp     [ebx+10h], eax                   //检查最终密钥 if (k == w)
.text:004023D8                 jnz     short loc_4023F0
这个检查的含义是输入的前18个字符组成的大数需要特定的值

所有游戏的主体就用输入的key控制走路过程,从每层的左上角走到右下角进入下一关,直到第4关通关
单独看每一关的话,6x5的地图,似乎也并不复杂,就手动走着玩玩
因为高层的道具会掉落下去的原因,有时需要返回前面低级关卡,处理给适当的位置垫高的问题
开始也是拾取过第一关的道具,走到第三关后没路走不下去了

多次尝试后,发现拾取道具是个负担,无视道具反而容易看清路线,就想到了试试不拾取0x31道具能不能走通,
竟然真的走通了,路线步骤,如下:
01 12 13 06 3B 0B 0D 1E 06 17 3B 02 12 3B 01 10 1E 1E 10 06 3B 0D 0B 1E 06 10 17 0C 3B 0B 10 1E 10 1C 0C 17 3B 1A 12 1E 1C 11 3B 12 10 3B 19 17 15 17 3B 05 06 07 17 12 18 3B
每个步骤转成平面坐标表示是(v/5,v%5)
其中那些小于0x1E步骤都是两个一组,从一个位置拿到0x11类型的箱子,扔到另一个位置的0x00空洞里
0x1E是回到上一关,0x3B是进入下一关

迷宫虽然走通了,但是后面却有个crc判断:
sub_4026A0 指定位置使用道具,从使用道具的函数里可以分析出:迷宫是逐个关卡从低到高立体层叠的,0x11道具可以从空洞掉落到下一层,下一层是空洞会继续掉落下去

sub_402400 判断是否可进入上一关,如果可到达,则会来到上一关的右下角坐标(5,4)

sub_402380 判断是否可进入下一关,如果可到达,则会来到下一关的左上角坐标(0,0)
.text:004023CE                 movzx   eax, byte ptr [ebx+198h]
.text:004023D5                 cmp     [ebx+10h], eax                   //检查最终密钥 if (k == w)
.text:004023D8                 jnz     short loc_4023F0
这个检查的含义是输入的前18个字符组成的大数需要特定的值

所有游戏的主体就用输入的key控制走路过程,从每层的左上角走到右下角进入下一关,直到第4关通关
单独看每一关的话,6x5的地图,似乎也并不复杂,就手动走着玩玩
因为高层的道具会掉落下去的原因,有时需要返回前面低级关卡,处理给适当的位置垫高的问题
开始也是拾取过第一关的道具,走到第三关后没路走不下去了


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

最后于 2019-12-30 20:46 被ccfer编辑 ,原因:
收藏
免费 5
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2022-7-27 01:29
心游尘世外
为你点赞~
2022-7-26 23:19
飘零丶
为你点赞~
2022-7-17 02:48
readyu
为你点赞~
2019-12-30 20:48
phiz
为你点赞~
2019-12-30 20:48
最新回复 (3)
雪    币: 23352
活跃值: (3482)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
2
感觉这道题的作者要女装一下才能补偿你呀
2019-12-30 18:17
0
雪    币: 11705
活跃值: (975)
能力值: ( LV12,RANK:779 )
在线值:
发帖
回帖
粉丝
3
很强大,膜拜
2019-12-30 23:02
0
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
4
对ccfer的膜拜有如涛涛江水
2019-12-31 13:47
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

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