-
-
[原创] 京东-看雪-2018 春季赛 第七题 密室逃脱
-
发表于: 2018-6-29 11:17 3212
-
拿到的是一个 win32 程序,跑一下看看
serial 是16byte 长度的字符串,根据题目描述,每个byte对应一个初始密钥
看一下程序逻辑
逻辑不复杂,前面output 一些信息,输入 序列号,然后进入main_logic 函数,main_logic 函数只有一层实现,下面分段看一下
首先会写入一个 16x16 的表
在内存中是这个样子的
这个表在后面会用到,主要是用来确定操作的index 的
先看一下后面的逻辑
首先根据输入的每个byte在一个 table 中找到对应的 index
后面对 变换之后的 index table 进行加密
代码被自己改的有点难看,大概逻辑是:
这么说有点模糊,调试一下,在 0x0401287 这里下个断点,ecx -0x10 就是 table 的位置
这里传入的是 abcdefghijklmnop , 可以看到 index 变换之后变成了 index 0-0xf
接下来在0x0401393, 也就是获取到下一个table 的一个byte回填的时候
找到 三个参数
可以发现是 0 1 2,结合前面的 16x16 的表来看 index 是符合的
但是顺序没搞清楚是怎么变换的,只有 16 个byte,调试看看就行,得到的每次 变换的 三个参数是 对应的 index 是
变换 之后将最后得到的密钥和 一个固定的串进行比较
如果一致就过,还会根据 变换得到的 19 个加密串中间的一个来生成一段字符串
到了这里,整理一下
一开始想到的是 有没有可能反向解密回去回去,但是发现用于变换的table 是 64x64x64 大小的,要变换回去感觉很难, 情况会有很多种
想了很久,后面发现,如果多加密几轮的话就有可能重新得到原来的输入
这就简单了,将 最后密钥多加密几轮,找到重新得到最后密钥的地方,就可以知道他是怎么来的了, 写了一个脚本测试了一下
多循环几次,grep 一下,可以看到重复了,找到重复位置的前19 个密钥,变换一下就可以得到 serial
运行结果
1 2 3 4 5 | Only 'a' - 'z' , 'A' - 'Z' , '0' - '9' accepted. Only 16 chars accepted. Serial:zzzzzzzzzzzzzzzz serial error |
1 2 3 4 5 6 7 8 9 10 | int __cdecl main( int argc, const char * * argv, const char * * envp) { printf( "Only 'a'-'z','A'-'Z','0'-'9' accepted.\n" ); printf( "Only 16 chars accepted.\n" ); printf( "Serial:" ); scanf_s( "%s" , input_450B80, 17 ); main_logic_401050(); system( "PAUSE" ); return 0 ; } |
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 | helpset[ 0 ] = 0x10101 ; helpset[ 1 ] = 0 ; helpset[ 2 ] = 0 ; helpset[ 3 ] = 0 ; helpset[ 4 ] = 0x1000001 ; helpset[ 5 ] = 1 ; helpset[ 6 ] = 0 ; helpset[ 7 ] = 0 ; helpset[ 8 ] = 1 ; helpset[ 9 ] = 0x10100 ; helpset[ 10 ] = 0 ; helpset[ 11 ] = 0 ; helpset[ 12 ] = 0x100 ; helpset[ 13 ] = 0x1000100 ; helpset[ 14 ] = 0 ; helpset[ 15 ] = 0 ; helpset[ 16 ] = 0x100 ; helpset[ 17 ] = 0x10001 ; helpset[ 18 ] = 0 ; helpset[ 19 ] = 0 ; helpset[ 20 ] = 0x1010000 ; helpset[ 21 ] = 0 ; helpset[ 22 ] = 1 ; helpset[ 23 ] = 0 ; helpset[ 24 ] = 0x10000 ; helpset[ 25 ] = 1 ; helpset[ 26 ] = 256 ; helpset[ 27 ] = 0 ; helpset[ 28 ] = 0x1000000 ; helpset[ 29 ] = 0x1000000 ; helpset[ 30 ] = 0x10000 ; helpset[ 31 ] = 0 ; helpset[ 32 ] = 0 ; helpset[ 33 ] = 256 ; helpset[ 34 ] = 1 ; helpset[ 35 ] = 1 ; helpset[ 36 ] = 0 ; helpset[ 37 ] = 0x10000 ; helpset[ 38 ] = 0x1000000 ; helpset[ 39 ] = 256 ; helpset[ 40 ] = 0 ; helpset[ 41 ] = 0x1000000 ; helpset[ 42 ] = 0 ; helpset[ 43 ] = 257 ; helpset[ 44 ] = 0 ; helpset[ 45 ] = 0 ; helpset[ 46 ] = 16777472 ; helpset[ 47 ] = 0x10000 ; helpset[ 48 ] = 0 ; helpset[ 49 ] = 0 ; helpset[ 50 ] = 65537 ; helpset[ 51 ] = 0x10000 ; helpset[ 52 ] = 0 ; helpset[ 53 ] = 0 ; helpset[ 54 ] = 65792 ; helpset[ 55 ] = 0x1000000 ; helpset[ 56 ] = 0 ; helpset[ 57 ] = 0 ; helpset[ 58 ] = 0x1000000 ; helpset[ 59 ] = 16777217 ; helpset[ 60 ] = 0 ; helpset[ 61 ] = 0 ; helpset[ 62 ] = 0 ; helpset[ 63 ] = 16843008 ; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | do { / / 找到每个key 对应的 index for ( offset = 0 ; ; + + offset ) { if ( offset > = 64 ) { printf( "input error\n" ); system( "PAUSE" ); exit( - 1 ); } if ( serial_set_40DA68[offset] = = (unsigned __int8)input_450B80[index] ) break ; } / / 找到每个byte 对应的 offset input_index[index + + ] = offset; } while ( index < 16 ); |
1 | abcdefghijklmnopqrstuvwxyz + - ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 |