-
-
第六题 至暗时刻
-
2023-9-15 11:22 3729
-
1 2 3 4 5 | 下载下来的exe短小精悍,ida打开基本就可以看清楚了,没有找到明显字符串,估计是加密了。调试跟踪一会就发现主程序逻辑在sub_140001630函数内,并成功找到了解密函数DecryStr_1400013B0。 读入的key前期并没有任何处理,只是前后分别拼接了一个字符串 3201382652D139C0E22132DF1BC2212EA0991650A229B36436823D0B13D51E6 和 677116575313142309154604431859253431473963507533496829080645035455771774602058076430276921790210013736267644383505517280 构造成了一个很长的字符串。本来以前是大数,但是看第二个字符串只有 0 - 9 ,又不太一致。最后还在前段加了一个kctf作为标记位。 后面的函数调用采用了直接使用系统调用号的方法,导致与系统挂钩。但在我的win7虚拟机中,NtAllocateVirtualMemory_140002BBA一直调用失败,只好把对应操作手工实现了一遍,浪费了很多时间。 由于后面操作一直不成功,只能采用静态分析的方式,发现程序只是申请了长度为 5500 的空间,把kctf开头的字符串写到起始位置,把unk_140008050开始的 2347 个字节的代码写入偏移为 500 的地方,然后NtQueueApcThread_140002E4E启动线程执行该代码,通过比较返回是否为“ 110 ”还是“ 120 ”来判断是否成功。 因此dump该代码段,重新构造exe执行该代码,发现该shellcode将代码中的所有 0x17 替换为 0x00 后,实现了一个数独矩阵的检测。sub_140001AA3检测数独是否成立。 |
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 | char __fastcall sub_140001AA3(__int64 a1) { unsigned int v2; / / ebx int v3; / / ebx int v4; / / edi v2 = 0 ; while ( (unsigned __int8)sub_14000193B(a1, v2) && (unsigned __int8)sub_1400019A7(a1, v2) ) / / 确保行和列不重复 { if ( ( int ) + + v2 > = 9 ) { v3 = 0 ; LABEL_6: v4 = 0 ; while ( (unsigned __int8)sub_140001A13(a1, (unsigned int )v3, (unsigned int )v4) ) { v4 + = 3 ; if ( v4 > = 9 ) { v3 + = 3 ; if ( v3 < 9 ) goto LABEL_6; return 1 ; } } return 0 ; } } return 0 ; } |
1 | sub_14000193B检测每行,sub_1400019A7检测每列,sub_140001A13检测 9 个 3 * 3 的方阵。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | char __fastcall sub_14000193B(__int64 a1, unsigned int a2) { int v2; / / ebx signed int v5; / / eax __int128 v7[ 2 ]; / / [rsp + 20h ] [rbp - 38h ] BYREF int v8; / / [rsp + 40h ] [rbp - 18h ] memset(v7, 0 , sizeof(v7)); v8 = 0 ; v2 = 0 ; while ( 1 ) { v5 = GetXY_14000163B(a1, a2, (unsigned int )v2) - 1 ; if ( (unsigned int )v5 > 8 || * ((_DWORD * )v7 + v5) ) break ; + + v2; * ((_DWORD * )v7 + v5) = 1 ; if ( v2 > = 9 ) return 1 ; } return 0 ; } |
1 | 其中调用了GetXY_14000163B获取对应矩阵(X,Y)处对应的数字。由于该函数检测不严谨,对大小写的处理不恰当,导致了多解的出现。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | if ( (unsigned __int8)(v19 - '0' ) > 9u ) { if ( (unsigned __int8)(v19 - 'A' ) > 0x19u ) { if ( (unsigned __int8)(v19 - 'a' ) > 0x19u ) break ; v18 = v19 - 87 ; v17 = 0 ; } else { v18 = v19 - 55 ; } } else { v18 = v19 - '0' ; } |
1 | 根据程序逻辑,Key前面的字符串是已经放置的 21 个数字,后面的字符串指示了剩下 60 个数字的填写顺序。解出已经填写的矩阵如下。 |
1 2 3 4 5 6 7 8 9 10 11 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 1 2 3 4 5 6 7 8 0 8 1 3 6 2 7 9 2 3 5 7 4 4 5 7 5 1 3 6 1 6 8 7 8 5 1 8 9 4 |
1 2 | 该矩阵是网上一个比较经典的数独矩阵,很容易就可以搜索出相应的答案。注意到前后下标的转换关系,按照前面字符串的书写规则得到flag为: 11230A2CD3C31CA32E0D707D38E0743531F80F726C1D133B3A914E2F034B1D63BB17F34428E2A31B038C25E0FA2BF2301053752062AA16E20A2FC1971730E90823D01A724B0CA19B0652811541480B80943AE27E13122C30C120 。 按照规则构造的一个多解为: 11230A2CD3C31CA32ED7a07D38E0743531F80F726C1D133B3A914E2F034B1D63BB17F34428E2A31B038C25E0FA2BF2301053752062AA16E20A2FC1971730E90823D01A724B0CA19B0652811541480B80943AE27E13122C30C120 。 |
[培训]科锐逆向工程师培训 48期预科班将于 2023年10月13日 正式开班
赞赏
他的文章