-
-
[原创]2019看雪CTF 晋级赛Q3 签到题:乱世鬼雄 by 心学
-
2019-9-18 19:23
3944
-
[原创]2019看雪CTF 晋级赛Q3 签到题:乱世鬼雄 by 心学
这是一道简单的根据【
用户名
】和【序列号】校验是否符合要求。
其逻辑是:【用户名】与【序列号】异或后,计算MD5值,并与内置的16字节数据进行比较,相等则通过。
知道处理过程后,进行计算
KCTF对应的序列号是:8DA79EF3CED2B8FCCFB2BBB6CBEFBCE1
一、Python计算代码:
# -*- coding: UTF-8 -*-
import binascii
print('输入信息:')
username_Str = 'KCTF'
builtin_HexStr = 'C6E4CAB5CED2B8FCCFB2BBB6CBEFBCE1'
print('username:\t%s'%(username_Str))
print('builtinHex:\t%s'%(builtin_HexStr))
print('\n转换成字节流')
username_Bytes = str.encode(username_Str)
builtin_Bytes = binascii.unhexlify(builtin_HexStr)
print('username:\t%s'%(username_Bytes))
print('builtinHex:\t%s'%(builtin_Bytes))
print('\n转换成整数:小端获取')
username_hex = int.from_bytes(username_Bytes, byteorder = 'little')
builtin_Hex = int.from_bytes(builtin_Bytes, byteorder = 'little')
print('username:\t%02X'%(username_hex))
print('builtinHex:\t%02X'%(builtin_Hex))
print('\n异或操作:此结果是字节反转的。主要是为了进行异或操作的对齐')
xorAB = username_hex^builtin_Hex
print('xor:\t\t%02X'%(xorAB))
print('\n转换成字节流')
SN_Re_HexStr = '%02X'%(xorAB)
SN_Re_Bytes = binascii.unhexlify(SN_Re_HexStr)
print('序列号字节流:\t%s'%(SN_Re_Bytes))
print('\n转换成整数:小端获取')
SN = int.from_bytes(SN_Re_Bytes, byteorder = 'little')
print('序列号:\t\t%02X'%(SN))
#8DA79EF3CED2B8FCCFB2BBB6CBEFBCE1
二、内置一个结构
00000000 MyMD5 struc ; (sizeof=0x58, mappedto_60)
00000000 ; XREF: sub_8819D0/r
00000000 unkownUInt dd ? ; XREF: sub_8819D0+191/w
00000000 ; sub_8819D0+1DB/r ...
00000004 unkownInt dd ? ; XREF: sub_8819D0+19D/w
00000008 vectorOrMD5Value __m128i ? ; XREF: sub_8819D0+1A9/w
00000008 ; sub_8819D0+1B4/w ...
00000018 value __m128i ?
00000028 unkownM128I __m128i 3 dup(?)
00000058 MyMD5 ends
三、主要代码
主函数是sub_8819D0()
int sub_8819D0()
{
unsigned int v0; // kr00_4
signed int i; // esi
unsigned __int8 v2; // cl
char v3; // dl
signed int j; // esi
__int128 *serialNoStrByHexRef; // edi
int v6; // eax
unsigned int v7; // ecx
int v8; // eax
unsigned int v9; // esi
bool v10; // cf
char *v11; // ecx
unsigned int k; // edx
__int8 v13; // al
__int8 *v14; // ecx
unsigned int m; // edx
char v16; // al
__int128 *v17; // ecx
char *v18; // edx
unsigned int v19; // esi
const char *strTips; // esi
MyMD5 myClassA; // [esp+8h] [ebp-E8h]
__m128i dataByusernameXorserialNoHex; // [esp+60h] [ebp-90h]
__int128 v24; // [esp+70h] [ebp-80h]
__int128 serialNoStr; // [esp+80h] [ebp-70h]
__int128 v26; // [esp+90h] [ebp-60h]
char v27; // [esp+A0h] [ebp-50h]
__int128 serialNoStrByHex; // [esp+B0h] [ebp-40h]
__int128 v29; // [esp+C0h] [ebp-30h]
char v30; // [esp+D0h] [ebp-20h]
PrintFunc("【请输入您的用户名与序列号】\n");
PrintFunc("请输入用户名:");
GetInputStr("%16s", &username, 17);
v0 = strlen((const char *)&username);
sub_8829C0((char *)&username + v0, 0, 16 - v0);
PrintFunc("请输入序列号:");
v27 = 0;
serialNoStr = 0i64;
v26 = 0i64;
serialNoStrByHex = 0i64;
v29 = 0i64;
v30 = 0;
serialNoHex = 0i64;
GetInputStr("%33s", &serialNoStr, 33); // serialNoStr:输入的16进制字符,是一个字符串
i = 0;
do
{
v2 = *((_BYTE *)&serialNoStr + 2 * i);
v3 = v2 - 55;
if ( v2 <= 0x39u )
v3 = *((_BYTE *)&serialNoStr + 2 * i);
*((_BYTE *)&serialNoHex + i) = *((_BYTE *)&serialNoStr + 2 * i + 1)
+ 16 * v3
- (*((_BYTE *)&serialNoStr + 2 * i + 1) > 0x39u ? 55 : 48);
++i;
}
while ( i < 16 ); // 将serialNoStr转换成对应的Hex数据,比如字符串"1234",会转换成0x1234
j = 0;
serialNoStrByHexRef = &serialNoStrByHex;
do
{
sub_881990((int)serialNoStrByHexRef, "%02X", *((unsigned __int8 *)&serialNoHex + j++));
serialNoStrByHexRef = (__int128 *)((char *)serialNoStrByHexRef + 2);
}
while ( j < 16 ); // 将serialNoyHex转换成对应的String数据,比如字符串0x1234,会转换成"1234"
v6 = strcmp((const char *)&serialNoStr, (const char *)&serialNoStrByHex);// 检测:输入的序列号,应该是16进制字符
if ( v6 )
v6 = -(v6 < 0) | 1;
if ( v6 )
{
PrintFunc(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
PrintFunc("【请输入合法序列号!】\n\n");
}
else // 计算【用户名】与【序列号】异或后的MD5值,然后与内置的16字节数据进行比较。
{
myClassA.unkownUInt = 0;
myClassA.unkownInt = 0;
myClassA.vectorOrMD5Value.m128i_i64[0] = 0xEFCDAB8967452301i64;// MD5的标记值:初始向量
dataByusernameXorserialNoHex = _mm_xor_si128((__m128i)username, (__m128i)serialNoHex);// 将a和b进行按位异或
myClassA.vectorOrMD5Value.m128i_i64[1] = 0x1032547698BADCFEi64;
v24 = 0i64;
sub_881000((int)&dataByusernameXorserialNoHex, (unsigned int *)&myClassA, 0x10u);
v7 = ((unsigned int)myClassA.unkownUInt >> 3) & 0x3F;
v8 = 0x78 - v7;
v9 = 0x38 - v7;
v10 = v7 < 0x38;
v11 = (char *)&myClassA.unkownUInt + 1;
if ( !v10 )
v9 = v8;
k = 0;
do
{
v13 = *(v11 - 1);
v11 += 4;
dataByusernameXorserialNoHex.m128i_i8[k] = v13;
dataByusernameXorserialNoHex.m128i_i8[k + 1] = *(v11 - 4);
dataByusernameXorserialNoHex.m128i_i8[k + 2] = *(v11 - 3);
dataByusernameXorserialNoHex.m128i_i8[k + 3] = *(v11 - 2);
k += 4;
}
while ( k < 8 );
sub_881000((int)&unk_8A08C0, (unsigned int *)&myClassA, v9);
sub_881000((int)&dataByusernameXorserialNoHex, (unsigned int *)&myClassA, 8u);// 调用MD5进行计算。
v14 = &myClassA.vectorOrMD5Value.m128i_i8[1];// md5Value--->v14
m = 0;
do
{
v16 = *(v14 - 1);
v14 += 4;
*((_BYTE *)&v24 + m) = v16;
*((_BYTE *)&v24 + m + 1) = *(v14 - 4);
*((_BYTE *)&v24 + m + 2) = *(v14 - 3);
*((_BYTE *)&v24 + m + 3) = *(v14 - 2);
m += 4;
}
while ( m < 0x10 ); // 该循环功能是:直接拷贝16字节:V14 ----> v24
v17 = &v24; // v24---->v17:结果就是md5Value--->v17
v18 = &constBuiltinHex; // 这是一个常量
v19 = 12;
while ( *(_DWORD *)v17 == *(_DWORD *)v18 ) // 比较是否相等,不等则退出
{
v17 = (__int128 *)((char *)v17 + 4);
v18 += 4;
v10 = v19 < 4;
v19 -= 4;
if ( v10 )
{
strTips = "【验证正确!】\n\n";
goto LABEL_22;
}
}
strTips = "【验证错误!】\n\n";
LABEL_22:
PrintFunc(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
PrintFunc(strTips);
}
sub_88507E("\npause\n");
return 0;
}
unsigned int __usercall sub_881000@<eax>(int a1@<edx>, unsigned int *a2@<ecx>, unsigned int a3)
{
unsigned int v3; // ebx
#59 *myClassA; // esi
unsigned int v5; // edx
unsigned int v6; // edi
unsigned int v7; // ecx
unsigned int i; // esi
unsigned int *v10; // [esp+Ch] [ebp-8h]
int v11; // [esp+10h] [ebp-4h]
unsigned int v12; // [esp+1Ch] [ebp+8h]
_DWORD *v13; // [esp+1Ch] [ebp+8h]
v3 = a3;
myClassA = (#59 *)a2;
v11 = a1;
v10 = a2;
v5 = (*a2 >> 3) & 0x3F;
v6 = 64 - v5;
v7 = *a2 + 8 * a3;
v12 = v10[1];
*v10 = v7;
if ( v7 < 8 * v3 )
*((_DWORD *)myClassA + 1) = ++v12;
*((_DWORD *)myClassA + 1) = v12 + (v3 >> 29);
if ( v3 < v6 )
{
v6 = 0;
}
else
{
sub_897B30((unsigned int)myClassA + v5 + 24, v11, 64 - v5);
v13 = (_DWORD *)((char *)myClassA + 8);
GetMD5((_DWORD *)myClassA + 2, (int)myClassA + 24);// 计算MD5值。
for ( i = v6 + 64; i <= v3; v6 += 64 )
{
GetMD5(v13, i + v11 - 64);
i += 64;
}
myClassA = (#59 *)v10;
v5 = 0;
}
return sub_897B30((unsigned int)myClassA + v5 + 24, v6 + v11, v3 - v6);
}
【看雪培训】《Adroid高级研修班》2022年夏季班招生中!