出题战队:野鹿子
设计思路
附件题目是按《5.2.2 Windows方案二》设计的CrackMe,由于是第一次参加防守提交题目,不清楚是否直接在这里提供原始资料,所以附件资料加密了,密码我单独再提供。
解压密码:kx.1111
此题的解题思路:
通过给出的一组user和serial,使用调试工具OD和IDA了解大概的解密过程。
1.将serial字符映射转成字节serial2。
2.使用DictTable字典对serial2做一次卷轴式全异域得到serial3。
3.计算出serial3除最后一个字节的BCC码,这个BCC码与serial3的最后一个字节进行异域,得到BCC2。
再用BCC2与serial3除最后一个字节外的所有字节异域得到serial4。
4.计算user的BCC码,这个BCC码的低半字节的2倍为目标值TargetFlag密文在MaskTable表里的偏移量。
5.通过调试工具可以找到TargetFlag的明文,即也知道了它的长度,且从代码可以判断TargetFlag的明文和密文长度一样。
6.判断MaskTable表里除了TargetFlag密文外的其他字节是否正确。
7.取出TargetFlag密文值,使用DictTable字典对每一个字节做__rol循环左移DictTable[i]%8次。
8.上一步得到的TargetFlag明文与程序内置的固定值做一致性比较,如果一样则成功了。
9.此题的另一个考查点是DictTable字典和MaskTable表,如果分析者在使用动态调试工具断点调试分析时,且断点落在解密函数或main函数内时DictTable字典和MaskTable表的值会变化,会影响解密结果。
如果不清楚动态调试工具的断点原理的情况下会增加难度。
赛题解析
int __cdecl main(int argc, const char **argv, const char **envp)
{
printf_1("Input User:\n");
gets_1(&user);
printf_1("Input Serial:\n");
gets_1(&serial);
off_403FD4(&off_403FD0);
getchar();
return 0;
}
int __cdecl sub_401120(unsigned __int8 **a1) // off_403FD4
{
tmp = hex2bin_401000(::serial);
qmemcpy(serial, tmp, 0x43u);
free(tmp);
v2 = a1[1];
for ( i = 0; i < 0x2B9; ++i )
serial[i % 0x43u] ^= v2[i];
}
off_403FD0
:.data:00403FD0 off_403FD0 dd offset _main ; DATA XREF: _main+2C↑o
.data:00403FD0 ; .data:0040302C↑o
.data:00403FD4 ; _DWORD (__cdecl *off_403FD4)(_DWORD)
.data:00403FD4 off_403FD4 dd offset sub_401120 ; DATA XREF: _main+31↑r
.data:00403FD8 ; int (__cdecl *gets_1)(_DWORD)
.data:00403FD8 gets_1 dd 0 ; DATA XREF: _main+10↑r
.data:00403FD8 ; _main+26↑r ...
a1[1]
应该是指向sub_401120
函数的指针, 其中的数据就是该函数的字节码。bin = open('decode.exe', 'rb').read()
# hexview 00401000 83 EC 18 A1 00 30 40 00 33 C4 89 44 24 14 85 DB
text_base = bin.find(b'\x83\xec\x18\xa1')
code_401120 = bin[text_base+0x120:text_base+0x120+0x2B9]for i in range(697):
serial[i%0x43] ^= code_401120[i]
v4 = serial[0];
for ( j = 1; j < 66; v4 ^= serial[j - 2] ^ serial[j - 1] ^ serial[j - 3] ^ v6 )
{
v6 = serial[j + 1] ^ serial[j];
j += 5;
}
v7 = v4 ^ serial[66];
serial[66] ^= v4;
v8 = serial;
v9 = 66;
do
{
*v8++ ^= v7;
--v9;
}
while ( v9 );
j += 5
和for
里的v4 ^= serial[j - 2] ^ serial[j - 1] ^ serial[j - 3] ^ v6
,j += 5
是先执行的:v4 = serial[0];
for ( j = 1; j < 66; j += 5 )
{
v6 = serial[j + 1] ^ serial[j];
v4 ^= serial[j + 3] ^ serial[j + 4] ^ serial[j + 2] ^ v6;
}
v7 = v4 ^ serial[66];
serial[66] ^= v4;
v8 = serial;
v9 = 66;
do
{
*v8++ ^= v7;
--v9;
}
while ( v9 );
xor_char = 0
for i in range(66):
xor_char ^= serial[i]
serial[66] ^= xor_charxor_char = serial[66]
for i in range(66):
serial[i] ^= xor_char
xor_char = serial[66]
for i in range(66):
serial[i] ^= xor_charxor_char = 0
for i in range(66):
xor_char ^= serial[i]
serial[66] ^= xor_char
xor_char2。
v10 = user;
xor_char2 = 0;
v12 = &user;
if ( user )
{
do
{
++v12;
xor_char2 ^= v10;
v10 = *v12;
}
while ( *v12 );
}
user = b'KCTF'
xor_char2 = 0
for i in range(4):
xor_char2 ^= user[i]
main_code = *a1;
p_serial = serial;
serial_23 = &serial[2 * (xor_char2 & 0xF)];
sep = 2 * (xor_char2 & 0xF);
if ( sep >= 0 && serial_23 != serial )
{
size = sep;
pmain_code = main_code;
if ( (unsigned int)sep < 4 )
{
LABEL_13:
if ( !size )
goto LABEL_22;
}
else
{
while ( *(_DWORD *)pmain_code == *(_DWORD *)p_serial )
{
size -= 4;
p_serial += 4;
pmain_code += 4;
if ( size < 4 )
goto LABEL_13;
}
}
v18 = *pmain_code - *p_serial;
if ( !v18 )
{
if ( size <= 1 )
goto LABEL_22;
v18 = pmain_code[1] - p_serial[1];
if ( !v18 )
{
if ( size <= 2 )
goto LABEL_22;
v18 = pmain_code[2] - p_serial[2];
if ( !v18 )
{
if ( size <= 3 )
goto LABEL_22;
v18 = pmain_code[3] - p_serial[3];
}
}
}
if ( (v18 >> 31) | 1 )
return printf("fail.\n");
}
LABEL_22:
v19 = 44 - sep;
if ( 44 - sep > 0 )
{
v20 = &serial[sep + 23];
v21 = &main_code[sep + 23];
if ( v19 < 4 )
{
LABEL_26:
if ( !v19 )
goto LABEL_35;
}
else
{
while ( *(_DWORD *)v21 == *(_DWORD *)v20 )
{
v19 -= 4;
v20 += 4;
v21 += 4;
if ( v19 < 4 )
goto LABEL_26;
}
}
v22 = *v21 - *v20;
if ( v22 )
goto LABEL_34;
if ( v19 > 1 )
{
v22 = v21[1] - v20[1];
if ( v22 )
goto LABEL_34;
if ( v19 > 2 )
{
v22 = v21[2] - v20[2];
if ( v22 )
goto LABEL_34;
if ( v19 > 3 )
{
v22 = v21[3] - v20[3];
LABEL_34:
if ( (v22 >> 31) | 1 )
return printf("fail.\n");
}
}
}
}
sep(2 * (xor_char2 & 0xF))
,sep+23
将serial
分成三段, 将前后两段与main_code
对应位置内容比较, 需要相同否则就会fail。qmemcpy(&serial_23_1, serial_23, 20u);
v23 = serial_23 + 20;
*((_WORD *)&serial_23_1 + 10) = *((_WORD *)serial_23 + 10);
*((_BYTE *)&serial_23_1 + 22) = v23[2];
10*2=20
继续复制2字节, _BYTE指针复制1字节, 总共从serial_23复制了23字节。code_401120 = a1[1];
p_serial23 = &serial_23_1;
v26 = 23;
do
{
v27 = *p_serial23 >> (8 - (*code_401120 & 7));
v28 = *p_serial23++ << (*code_401120++ & 7);
--v26;
*(p_serial23 - 1) = v28 | v27;
}
while ( v26 );
<<
与>>
以code_401120的数据为基准做一个循环移位操作。for i in range(23):
shn = code_401120[i] & 7
serial_23[i] = ((serial_23[i] >> (8 - shn))&0xff) | ((serial_23[i] << shn)&0xff)
for i in range(23):
shn = code_401120[i] & 7
serial_23[i] = ((serial_23[i] << (8 - shn))&0xff) | ((serial_23[i] >> shn)&0xff)
serial_23
与KCTF-2024-CRACK-SUCCESS
比较:v29 = 23;
v30 = "KCTF-2024-CRACK-SUCCESS";
p_serial_23 = &serial_23_1;
while ( *(_DWORD *)p_serial_23 == *(_DWORD *)v30 )
{
v29 -= 4;
v30 += 4;
p_serial_23 += 4;
if ( v29 < 4 )
{
if ( *v30 == *p_serial_23 && v30[1] == p_serial_23[1] && v30[2] == p_serial_23[2] )
return printf("***success***.\n");
return printf("fail.\n");
}
}
import codecs bin = open('decode.exe', 'rb').read()
# hexview 00401000 83 EC 18 A1 00 30 40 00 33 C4 89 44 24 14 85 DB
text_base = bin.find(b'\x83\xec\x18\xa1')
code_401120 = bin[text_base+0x120:text_base+0x120+697]
code_main = bin[text_base+0xd0:text_base+0xd0+0x43]serial_23 = bytearray(b'KCTF-2024-CRACK-SUCCESS')
for i in range(23):
shn = code_401120[i] & 7
serial_23[i] = ((serial_23[i] << (8 - shn))&0xff) | ((serial_23[i] >> shn)&0xff)serial = bytearray(0x43)
name = b'KCTF'
xor_char = 0
for i in range(4):
xor_char ^= name[i]sep = (xor_char & 0xf) * 2
j = 0
for i in range(0x43):
if i >= sep and i < sep + 23:
serial[i] = serial_23[j]
j += 1
else:
serial[i] = code_main[i]xor_char = serial[66]
for i in range(0, 66):
serial[i] ^= xor_charxor_char = 0
for i in range(66):
xor_char ^= serial[i]
serial[66] ^= xor_charfor i in range(697):
serial[i%0x43] ^= code_401120[i]print(codecs.encode(serial, "hex"))
# d287e2bb87cbda561717c90e08eba2ad13cf09e4eb4428f36cf11cf83cea678dfa19e081bc5d66cdc17d1c2a4121e0d1fd330ed9c21474e364a4e4d6b02c4644b1b5cc
球分享
球点赞
球在看
点击阅读原文查看更多