GFSJ0213-【leaked-license-64】
猜 ID 应该是比赛的时候有提示ID吧 其他还好
题目简介
I have borrowed this software license(Leaked_License) and library from Big Brother of a friend of a friend! It would be nice if I could have forged a license for the ID of this years competition computer.
题目给了一个dll 一个许可证
能发现许可证是32字节 而且是十六进制 我们能猜到这个是16字节的密文
IDA打开发现只有一个导出函数就是 verify 其他也没有名字一眼看到了 也可以查看字符串能看到secret.key查看调用也能到这里
bool __cdecl verify(
void *a1,
int a2,
int a3,
int a4,
int a5,
unsigned int a6,
void *a7,
int a8,
int a9,
int a10,
int a11,
unsigned int a12)
{
int v12; // eax
bool v13; // zf
int v14; // eax
char *v15; // ecx
int v16; // eax
char *v17; // ecx
int v18; // ecx
bool v19; // bl
char *v20; // ecx
int v21; // eax
int v22; // eax
void *v23; // eax
void *v25; // [esp-30h] [ebp-1F0h]
int v26; // [esp-2Ch] [ebp-1ECh]
int v27; // [esp-28h] [ebp-1E8h]
int v28; // [esp-24h] [ebp-1E4h]
void *v29; // [esp-18h] [ebp-1D8h]
void *v30; // [esp-18h] [ebp-1D8h]
int v31; // [esp-14h] [ebp-1D4h]
int v32; // [esp-14h] [ebp-1D4h]
int v33; // [esp-10h] [ebp-1D0h]
int v34; // [esp-10h] [ebp-1D0h]
int v35; // [esp-Ch] [ebp-1CCh]
int v36; // [esp-Ch] [ebp-1CCh]
int v37; // [esp-Ch] [ebp-1CCh]
int v38; // [esp-8h] [ebp-1C8h]
int v39; // [esp-8h] [ebp-1C8h]
int v40; // [esp-4h] [ebp-1C4h]
int v41; // [esp-4h] [ebp-1C4h]
int v42; // [esp-4h] [ebp-1C4h]
_DWORD v44[4]; // [esp+8h] [ebp-1B8h] BYREF
_BYTE v45[96]; // [esp+18h] [ebp-1A8h] BYREF
void **v46; // [esp+78h] [ebp-148h] BYREF
_DWORD v47[19]; // [esp+128h] [ebp-98h] BYREF
void *v48[5]; // [esp+174h] [ebp-4Ch] BYREF
unsigned int v49; // [esp+188h] [ebp-38h]
void *Block[5]; // [esp+18Ch] [ebp-34h] BYREF
unsigned int v51; // [esp+1A0h] [ebp-20h]
void *v52; // [esp+1A4h] [ebp-1Ch]
unsigned int v53; // [esp+1B8h] [ebp-8h]
v12 = sub_10008DC0();
sub_10009020(v12);
sub_10003930(v40);
v13 = sub_10004FB0(v35, v38, v41) == 0;
v14 = *(_DWORD *)(v44[0] + 4);
if ( v13 )
{
v15 = (char *)v44 + v14;
v16 = *(_DWORD *)((char *)&v44[3] + v14) | 2;
if ( !*((_DWORD *)v15 + 14) )
v16 = *((_DWORD *)v15 + 3) | 6;
}
else
{
v17 = (char *)v44 + v14;
v16 = 0;
if ( !*((_DWORD *)v17 + 14) )
v16 = 4;
}
sub_10001B00(v16, 0);
v18 = v44[0];
if ( (*((_BYTE *)&v44[3] + *(_DWORD *)(v44[0] + 4)) & 6) != 0 )
{
v19 = 0;
}
else
{
sub_10003130(v39, v42);
sub_10002EB0(v45);
sub_10003260(v48);
sub_10002390(v48);
if ( !sub_10005070(v45) )
{
v20 = (char *)v44 + *(_DWORD *)(v44[0] + 4);
v21 = *((_DWORD *)v20 + 3) | 2;
if ( !*((_DWORD *)v20 + 14) )
v21 = *((_DWORD *)v20 + 3) | 6;
sub_10001B00(v21, 0);
}
LOBYTE(v29) = 0;
sub_10004970((int)v48, 0, 0xFFFFFFFF);
v22 = sub_1000A7E0(v29, v31, v33, v36, 0, 15);
v23 = (void *)sub_10001DA0(Block, v22);
sub_100027A0(&dword_100325B0, v23);
if ( v51 >= 0x10 )
j__free(Block[0]);
v51 = 15;
Block[4] = nullptr;
LOBYTE(Block[0]) = 0;
if ( v53 >= 0x10 )
j__free(v52);
LOBYTE(v30) = 0;
sub_10004970((int)&a7, 0, 0xFFFFFFFF);
LOBYTE(v25) = 0;
sub_10004970((int)&a1, 0, 0xFFFFFFFF);
v19 = (unsigned __int8)sub_10002000(v25, v26, v27, v28, 0, 15, v30, v32, v34, v37, 0, 15) != 0;
if ( v49 >= 0x10 )
j__free(v48[0]);
v49 = 15;
v48[4] = nullptr;
LOBYTE(v48[0]) = 0;
sub_100031E0(v47);
v47[0] = &std::ios_base::`vftable';
std::ios_base::_Ios_base_dtor((struct std::ios_base *)v47);
v18 = v44[0];
}
*(_DWORD *)((char *)v44 + *(_DWORD *)(v18 + 4)) = &std::ifstream::`vftable';
*(_DWORD *)((char *)&v44[-1] + *(_DWORD *)(v44[0] + 4)) = *(_DWORD *)(v44[0] + 4) - 112;
sub_10003AE0(v45);
*(_DWORD *)((char *)v44 + *(_DWORD *)(v44[0] + 4)) = &std::istream::`vftable';
*(_DWORD *)((char *)&v44[-1] + *(_DWORD *)(v44[0] + 4)) = *(_DWORD *)(v44[0] + 4) - 24;
v46 = &std::ios_base::`vftable';
std::ios_base::_Ios_base_dtor((struct std::ios_base *)&v46);
if ( a6 >= 0x10 )
j__free(a1);
a6 = 15;
a5 = 0;
LOBYTE(a1) = 0;
if ( a12 >= 0x10 )
j__free(a7);
return v19;
}
open函数 也就是打开许可证的函数
_DWORD *__thiscall sub_10004FB0(_DWORD *this, int a2, int a3, int a4)
{
int v5; // eax
int v6; // eax
int v7; // eax
void (__thiscall ***v8)(_DWORD, int); // eax
int v10; // [esp+8h] [ebp-10h] BYREF
int v11; // [esp+14h] [ebp-4h]
if ( *(this + 20) )
return nullptr;
v5 = sub_1001EFF6("secret.key", 1, 64);
if ( !v5 )
return nullptr;
sub_10005120(v5, 1);
v6 = sub_100069B0(&v10);
v11 = 0;
v7 = sub_10009310(v6);
sub_10005340(v7);
v11 = -1;
if ( v10 )
{
v8 = (void (__thiscall ***)(_DWORD, int))(*(int (__thiscall **)(int))(*(_DWORD *)v10 + 8))(v10);
if ( v8 )
(**v8)(v8, 1);
}
return this;
}
close函数 也就是读取许可证后关闭
int __thiscall sub_10005070(int this)
{
int v2; // edi
if ( *(_DWORD *)(this + 80) )
{
v2 = this;
if ( !(unsigned __int8)sub_100051C0() )
v2 = 0;
if ( fclose(*(FILE **)(this + 80)) )
v2 = 0;
}
else
{
v2 = 0;
}
*(_BYTE *)(this + 76) = 0;
*(_DWORD *)(this + 12) = this + 4;
*(_DWORD *)(this + 16) = this + 8;
*(_DWORD *)(this + 28) = this + 20;
*(_DWORD *)(this + 32) = this + 24;
*(_DWORD *)(this + 44) = this + 36;
*(_DWORD *)(this + 48) = this + 40;
*(_BYTE *)(this + 69) = 0;
*(_DWORD *)(this + 8) = 0;
**(_DWORD **)(this + 32) = 0;
**(_DWORD **)(this + 48) = 0;
**(_DWORD **)(this + 12) = 0;
**(_DWORD **)(this + 28) = 0;
**(_DWORD **)(this + 44) = 0;
*(_DWORD *)(this + 80) = 0;
*(_DWORD *)(this + 72) = dword_10033CE4;
*(_DWORD *)(this + 64) = 0;
return v2;
}
翻翻找找能找到校验函数
bool __cdecl sub_10002000(
void ***Src,
int a2,
int a3,
int a4,
int a5,
unsigned int a6,
void ***a7,
int a8,
int a9,
int a10,
int a11,
unsigned int a12)
{
int *v12; // eax
int v13; // esi
void **v14; // ecx
void ***p_Src; // edx
void ***v16; // ebx
int v17; // eax
void ***v18; // ecx
void **v19; // ecx
void **v20; // edx
void **v21; // ecx
void ***v22; // edi
int v23; // eax
void ***v24; // ecx
void ***v25; // ecx
void **v26; // ecx
void **v27; // edx
int i; // edi
void ***v29; // ecx
void ***v30; // eax
char v31; // al
void **v32; // ecx
int v33; // eax
void **v34; // ecx
int v35; // eax
int *v36; // eax
int *v37; // ecx
void **v38; // esi
unsigned int v39; // ebx
unsigned int v40; // edx
unsigned int v41; // edx
bool v42; // cf
unsigned __int8 v43; // al
unsigned __int8 v44; // al
unsigned __int8 v45; // al
int v46; // eax
bool v47; // zf
int v48; // eax
bool v49; // bl
bool v50; // bl
void **v52[4]; // [esp-18h] [ebp-90h] BYREF
size_t v53; // [esp-8h] [ebp-80h]
unsigned int v54; // [esp-4h] [ebp-7Ch]
int v55; // [esp+Ch] [ebp-6Ch]
int v56; // [esp+10h] [ebp-68h]
void *v57; // [esp+14h] [ebp-64h]
unsigned int v58; // [esp+28h] [ebp-50h]
void *Block[5]; // [esp+2Ch] [ebp-4Ch] BYREF
unsigned int v60; // [esp+40h] [ebp-38h]
void *v61[4]; // [esp+44h] [ebp-34h] BYREF
int v62; // [esp+54h] [ebp-24h]
unsigned int v63; // [esp+58h] [ebp-20h]
void *v64[4]; // [esp+5Ch] [ebp-1Ch] BYREF
int v65; // [esp+6Ch] [ebp-Ch]
unsigned int v66; // [esp+70h] [ebp-8h]
v12 = sub_10001DA0((int *)Block, (int)&a7);
sub_100027A0((void **)&a7, (void **)v12);
if ( v60 >= 0x10 )
j__free(Block[0]);
v13 = a5;
if ( a5 < 32 )
{
v66 = 15;
v65 = 0;
LOBYTE(v64[0]) = 0;
sub_10004970(v64, &Src, 0, 0xFFFFFFFF);
v56 = 32 % v13;
v55 = 32 / v13;
if ( 32 / v13 > 0 )
{
do
{
v14 = v64;
p_Src = (void ***)&Src;
if ( v66 >= 0x10 )
v14 = (void **)v64[0];
v16 = (void ***)&Src;
v17 = (int)v14 + v65;
if ( a6 >= 0x10 )
p_Src = Src;
v18 = (void ***)((char *)p_Src + a5);
if ( a6 >= 0x10 )
v16 = Src;
if ( v16 == v18 )
{
v19 = v64;
if ( v66 >= 0x10 )
v19 = (void **)v64[0];
if ( v17 )
sub_10002850(v64, v17 - (_DWORD)v19, 0);
else
sub_10002850(v64, 0, 0);
}
else
{
v20 = v64;
if ( v66 >= 0x10 )
v20 = (void **)v64[0];
if ( v17 )
v17 -= (int)v20;
sub_10009C00(v17, 0, v16, (char *)v18 - (char *)v16);
}
--v55;
}
while ( v55 );
}
v21 = v64;
v22 = (void ***)&Src;
if ( v66 >= 0x10 )
v21 = (void **)v64[0];
v23 = (int)v21 + v65;
v24 = (void ***)&Src;
if ( a6 >= 0x10 )
v24 = Src;
v25 = (void ***)((char *)v24 + v56);
if ( a6 >= 0x10 )
v22 = Src;
if ( v22 == v25 )
{
v26 = v64;
if ( v66 >= 0x10 )
v26 = (void **)v64[0];
if ( v23 )
sub_10002850(v64, v23 - (_DWORD)v26, 0);
else
sub_10002850(v64, 0, 0);
}
else
{
v27 = v64;
if ( v66 >= 0x10 )
v27 = (void **)v64[0];
if ( v23 )
v23 -= (int)v27;
sub_10009C00(v23, 0, v22, (char *)v25 - (char *)v22);
}
sub_10004970(&Src, v64, 0, 0xFFFFFFFF);
if ( v66 >= 0x10 )
j__free(v64[0]);
}
v63 = 15;
v62 = 0;
LOBYTE(v61[0]) = 0;
sub_10006520((int)v61, &unk_1002D8FF, 0);
for ( i = 0; i < 32; ++i )
{
v29 = (void ***)&Src;
v30 = (void ***)&a7;
if ( a6 >= 0x10 )
v29 = Src;
if ( a12 >= 0x10 )
v30 = a7;
v31 = *((_BYTE *)v29 + i) ^ *((_BYTE *)v30 + i);
v32 = v61;
LOBYTE(v56) = v31;
if ( v63 >= 0x10 )
v32 = (void **)v61[0];
v33 = (int)v32 + v62;
v34 = v61;
if ( v63 >= 0x10 )
v34 = (void **)v61[0];
if ( v33 )
v33 -= (int)v34;
sub_100066F0(v33, 1u, v56);
}
v54 = 15;
v53 = 0;
LOBYTE(v52[0]) = 0;
sub_10004970(v52, v61, 0, 0xFFFFFFFF);
v35 = sub_1000A7E0(v52[0], (int)v52[1], (int)v52[2], (int)v52[3], v53, v54);
v36 = sub_10001DA0((int *)Block, v35);
v37 = v36;
v38 = &dword_100325B0;
if ( (unsigned int)dword_100325C4 >= 0x10 )
v38 = (void **)dword_100325B0;
v39 = v36[4];
if ( (unsigned int)v36[5] >= 0x10 )
v37 = (int *)*v36;
v40 = dword_100325C0;
if ( v39 < dword_100325C0 )
v40 = v36[4];
if ( v40 )
{
v42 = v40 < 4;
v41 = v40 - 4;
if ( v42 )
{
LABEL_64:
if ( v41 == -4 )
goto LABEL_73;
}
else
{
while ( (void *)*v37 == *v38 )
{
++v37;
++v38;
v42 = v41 < 4;
v41 -= 4;
if ( v42 )
goto LABEL_64;
}
}
v42 = *(_BYTE *)v37 < *(_BYTE *)v38;
if ( *(_BYTE *)v37 != *(_BYTE *)v38
|| v41 != -3
&& ((v43 = *((_BYTE *)v37 + 1), v42 = v43 < *((_BYTE *)v38 + 1), v43 != *((_BYTE *)v38 + 1))
|| v41 != -2
&& ((v44 = *((_BYTE *)v37 + 2), v42 = v44 < *((_BYTE *)v38 + 2), v44 != *((_BYTE *)v38 + 2))
|| v41 != -1 && (v45 = *((_BYTE *)v37 + 3), v42 = v45 < *((_BYTE *)v38 + 3), v45 != *((_BYTE *)v38 + 3)))) )
{
v46 = v42 ? -1 : 1;
goto LABEL_74;
}
LABEL_73:
v46 = 0;
LABEL_74:
v47 = v46 == 0;
if ( v46 )
goto LABEL_79;
}
if ( v39 >= dword_100325C0 )
v48 = v39 != dword_100325C0;
else
v48 = -1;
v47 = v48 == 0;
LABEL_79:
v49 = v47;
if ( v60 >= 0x10 )
j__free(Block[0]);
v60 = 15;
Block[4] = nullptr;
LOBYTE(Block[0]) = 0;
if ( v58 >= 0x10 )
j__free(v57);
v50 = v49;
if ( v63 >= 0x10 )
j__free(v61[0]);
v63 = 15;
v62 = 0;
LOBYTE(v61[0]) = 0;
if ( a6 >= 0x10 )
j__free(Src);
a6 = 15;
a5 = 0;
LOBYTE(Src) = 0;
if ( a12 >= 0x10 )
j__free(a7);
return v50;
}
能看到里面有很多0x10 看着特别像是一个取字符串真实地址 里面还有一个异或操作
for ( i = 0; i < 32; ++i )
{
v29 = (void ***)&Src;
v30 = (void ***)&a7;
if ( a6 >= 0x10 )
v29 = Src;
if ( a12 >= 0x10 )
v30 = a7;
v31 = *((_BYTE *)v29 + i) ^ *((_BYTE *)v30 + i);
v32 = v61;
LOBYTE(v56) = v31;
从verify调用的sub_100002000的位置能看到 我们能知道这个是C++ 所以它是传入两个 std::string 因为 32 位 MSVC 的 std::string 会被 IDA 拆成多个参数
32 位 MSVC 的 std::string 结构
struct string {
char buf_or_ptr[16]; // 前 16 字节,短字符串直接存在这里
int size; // +0x10,字符串长度
int capacity; // +0x14,容量
};
sub_10002000(
v25, v26, v27, v28, 0, 15,
v30, v32, v34, v37, 0, 15
)
也就是
Src, a2, a3, a4, a5, a6 第一个 string
a7, a8, a9, a10, a11, a12 第二个 string
所以我们能知道他是对于两个字符串来进行相对异或操作 然后我们能想到许可证是一个32字节的 那肯定就是第二个strings 因为第一个strings进行了很多的操作
v13 = a5;
if ( a5 < 32 )
{
v66 = 15;
v65 = 0;
LOBYTE(v64[0]) = 0;
sub_10004970(v64, &Src, 0, 0xFFFFFFFF);
v56 = 32 % v13;
v55 = 32 / v13;
if ( 32 / v13 > 0 )
{
do
{
v14 = v64;
p_Src = (void ***)&Src;
if ( v66 >= 0x10 )
v14 = (void **)v64[0];
v16 = (void ***)&Src;
v17 = (int)v14 + v65;
if ( a6 >= 0x10 )
p_Src = Src;
v18 = (void ***)((char *)p_Src + a5);
if ( a6 >= 0x10 )
v16 = Src;
if ( v16 == v18 )
{
v19 = v64;
if ( v66 >= 0x10 )
v19 = (void **)v64[0];
if ( v17 )
sub_10002850(v64, v17 - (_DWORD)v19, 0);
else
sub_10002850(v64, 0, 0);
}
else
{
v20 = v64;
if ( v66 >= 0x10 )
v20 = (void **)v64[0];
if ( v17 )
v17 -= (int)v20;
sub_10009C00(v17, 0, v16, (char *)v18 - (char *)v16);
}
--v55;
}
while ( v55 );
}
能看到这是一个完美的字符串拼接操作 由上方的结构体能看出来 因为题目简介要的就是id伪装 然后文件名字就是他的id嘛 admin@nsa.gov.us 正正好好16字节 然后要补充到32字节 当然运行的时候a5肯定不是一个0 而是真实的长度 静态和动态是不一样的
a5 = id.length()
所以我们能看出来是一个将字符串追加到屁股后头到32字节 所以
exp
old_id = b"admin@nsa.gov.us"
old_license = bytes.fromhex(
"7e43ecf0b4e27dacfb5e613437b17acb46e8deab2c70510dc71844b492a691ec"
)
target_id = b"quals2016@asis-ctf.ir"
def pad32(x):
return (x * (32 // len(x) + 1))[:32]
old_id_pad = pad32(old_id)
target_id_pad = pad32(target_id)
secret = bytes(a ^ b for a, b in zip(old_license, old_id_pad))
new_license = bytes(a ^ b for a, b in zip(secret, target_id_pad))
print("secret =", secret.hex())
print("license =", new_license.hex())
print("flag = ASIS{" + new_license.hex() + "}")
当然 你要问我这个target_id 怎么来的 那我只能说 我看wp出来的 这谁能猜出来啊 哈哈哈哈
评论