这个迷宫题目还是挺有意思的,后来发现可以多解碰撞crc,就觉得更有意思了
这个程序有tls和几处anti,还是要稍微小心一点
401660 CheckRemoteDebuggerPresent
4015E0 NtQueryInformationProcess
401710 GetThreadContext 检查drx之和
401690 setjmp3/SetUnhandledExceptionFilter
输入处理:
.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:
.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:
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解密出明文迷宫数据,方便后面描述:
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解密出明文迷宫数据,方便后面描述:
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道具可以改变密钥
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道具可以改变密钥
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_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编辑
,原因: