首先使用dede查看有多少用户自定函数
由于FormCreate函数是最先被调用的,所以我们在IDA中找到对应函数,并使用F5分析
int __fastcall TForm1_FormCreate(int a1)
{
int v1; // ebx@1
int v2; // edx@1
int v3; // edx@1
v1 = a1;
unknown_libname_28(a1 + 784, &str_____Sun_Bird[1]);
unknown_libname_28(v1 + 788, &str_dseloffc_012_OK[1]);
LOBYTE(v2) = 1;
Controls::TControl::SetVisible(*(_DWORD *)(v1 + 740), v2);
LOBYTE(v3) = 1;
return Controls::TControl::SetVisible(*(_DWORD *)(v1 + 752), v3);
}
上面的函数比较简单也比较直观,就是初始化两个字符串指针成员变量,并且显示两个控件,我们这边记住下两个成员变量的地址分别是784、788,对应的字符串分别为“黑头Sun Bird”、“dseloffc-012-OK”
接下来让我们看下第二个自定义函数KeyUp
int __fastcall TForm1_KeyUp(int a1, int a2, int a3, int a4)
{
int v4; // ebx@1
int v5; // eax@1
int result; // eax@1
v4 = a1;
v5 = Controls::TControl::GetTextLen(*(_DWORD *)(a1 + 724));
*(_DWORD *)(v4 + 760) = v5;
result = abs(v5);
*(_DWORD *)(v4 + 760) = result;
return result;
}
上面的函数也比较简单,主要是获取输入的字符串的长度并且保存到一个成员变量中,这边我们记下成员变量的地址760,至于是记录什么控件的文本长度,我们看下dede中KeyUp是哪个控件上的函数即可
可以看到是TEdit1就是用户名,所以this->760保存的是用户名的长度,接下来看下第三个自定义函数Panel1Click
int __fastcall TForm1_Panel1Click(int a1)
{
int v1; // esi@1
int v2; // ebx@1
int v3; // eax@2
int v4; // ST04_4@2
int v5; // ecx@2
int v6; // ebx@4
int v7; // eax@5
int v8; // ST04_4@5
int v9; // ecx@5
unsigned int v11; // [sp-Ch] [bp-38h]@1
int (*v12)(); // [sp-8h] [bp-34h]@1
int (*v13)(); // [sp-4h] [bp-30h]@1
int v14; // [sp+8h] [bp-24h]@5
int v15; // [sp+Ch] [bp-20h]@5
int v16; // [sp+10h] [bp-1Ch]@5
int v17; // [sp+14h] [bp-18h]@5
int v18; // [sp+18h] [bp-14h]@2
int v19; // [sp+1Ch] [bp-10h]@2
int v20; // [sp+20h] [bp-Ch]@2
int v21; // [sp+24h] [bp-8h]@2
char v22; // [sp+28h] [bp-4h]@2
int v23; // [sp+2Ch] [bp+0h]@1
v1 = a1;
v13 = (int (*)())&v23;
v12 = loc_4580FD;
v11 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v11);
v2 = 0;
do
{
TControl::GetText(*(_DWORD *)(v1 + 724), &v20);
v3 = sub_403B7C(v20);
Sysutils::IntToStr(v3 + 30, &v21);
TControl::GetText(*(_DWORD *)(v1 + 724), &v19);
v4 = v19;
Sysutils::IntToStr(v2, &v18);
System::__linkproc___LStrCatN(&v22, 3, v5, v4, v18);
++v2;
}
while ( v2 != 19 );
if ( *(_DWORD *)(v1 + 780) == 133 )
{
v6 = 0;
do
{
TControl::GetText(*(_DWORD *)(v1 + 724), &v16);
v7 = sub_403B7C(v16);
Sysutils::IntToStr(v7 + 3, &v17);
TControl::GetText(*(_DWORD *)(v1 + 724), &v15);
v8 = v15;
Sysutils::IntToStr(v6, &v14);
System::__linkproc___LStrCatN(&v22, 3, v9, v8, v14);
++v6;
}
while ( v6 != 19 );
Controls::TControl::SetVisible(*(_DWORD *)(v1 + 752), 0);
unknown_libname_28(dword_45B820 + 112, &str________________[1]);
}
__writefsdword(0, v11);
v13 = loc_458104;
unknown_libname_26(&v14);
unknown_libname_27(&v15, 2);
unknown_libname_27(&v17, 2);
unknown_libname_27(&v19, 2);
return unknown_libname_27(&v21, 2);
}
简单的分析上面函数,可得到如下代码
int __fastcall TForm1_Panel1Click(int this)
{
int this; // esi@1
int i; // ebx@1
int iNLen; // eax@2
int v4; // ST04_4@2
int v5; // ecx@2
int j; // ebx@4
int iNLen; // eax@5
int pszName; // [sp+1Ch] [bp-10h]@2
int pszName; // [sp+20h] [bp-Ch]@2
i = 0;
do
{
TControl::GetText(*(_DWORD *)(this + 724), &pszName);
iNLen = strlen(pszName);
Sysutils::IntToStr(iNLen + 30, &v21);
TControl::GetText(*(_DWORD *)(this + 724), &pszName);
System::__linkproc___LStrCatN(&v22, 3, pszName, i);
++i;
}
while ( i != 19 );
if ( *(_DWORD *)(this + 780) == 133 )
{
j = 0;
do
{
TControl::GetText(*(_DWORD *)(this + 724), &pszName);
iNLen = strlen(pszName);
Sysutils::IntToStr(iNLen + 3, &v17);
TControl::GetText(*(_DWORD *)(this + 724), &pszName);
System::__linkproc___LStrCatN(&v22, 3, pszName, j);
++j;
}
while ( j != 19 );
Controls::TControl::SetVisible(*(_DWORD *)(this + 752), 0);
unknown_libname_28(dword_45B820 + 112, "恭喜恭喜!注册成功");
}
}
可以看到两个do-while循环都是迷惑性的,根本不影响最后“注册成功”的提示,真正的判断点在于if ( *(_DWORD *)(this + 780) == 133 ),但是我们发现在当前函数即之前函数都没有发觉对this+780有赋值,所以我们需要看下下一个函数Panel1DbClick
int __fastcall TForm1_Panel1DblClick(int a1)
{
int v1; // esi@1
int v2; // ebx@1
int v3; // eax@2
int v4; // ST04_4@2
int v5; // ecx@2
int v6; // ebx@5
int v7; // eax@6
int v8; // ST04_4@6
int v9; // ecx@6
unsigned int v11; // [sp-Ch] [bp-38h]@1
int (*v12)(); // [sp-8h] [bp-34h]@1
int (*v13)(); // [sp-4h] [bp-30h]@1
int v14; // [sp+8h] [bp-24h]@6
int v15; // [sp+Ch] [bp-20h]@6
int v16; // [sp+10h] [bp-1Ch]@6
int v17; // [sp+14h] [bp-18h]@6
int v18; // [sp+18h] [bp-14h]@2
int v19; // [sp+1Ch] [bp-10h]@2
int v20; // [sp+20h] [bp-Ch]@2
int v21; // [sp+24h] [bp-8h]@2
char v22; // [sp+28h] [bp-4h]@2
int v23; // [sp+2Ch] [bp+0h]@1
v1 = a1;
v13 = (int (*)())&v23;
v12 = loc_457FA9;
v11 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v11);
v2 = 0;
do
{
TControl::GetText(*(_DWORD *)(v1 + 724), &v20);
v3 = sub_403B7C(v20);
Sysutils::IntToStr(v3 + 9, &v21);
TControl::GetText(*(_DWORD *)(v1 + 724), &v19);
v4 = v19;
Sysutils::IntToStr(v2, &v18);
System::__linkproc___LStrCatN(&v22, 3, v5, v4, v18);
++v2;
}
while ( v2 != 19 );
if ( *(_DWORD *)(v1 + 780) == 62 )
*(_DWORD *)(v1 + 780) = 133;
v6 = 0;
do
{
TControl::GetText(*(_DWORD *)(v1 + 724), &v16);
v7 = sub_403B7C(v16);
Sysutils::IntToStr(v7 + 21, &v17);
TControl::GetText(*(_DWORD *)(v1 + 724), &v15);
v8 = v15;
Sysutils::IntToStr(v6, &v14);
System::__linkproc___LStrCatN(&v22, 3, v9, v8, v14);
++v6;
}
while ( v6 != 19 );
__writefsdword(0, v11);
v13 = loc_457FB0;
unknown_libname_26(&v14);
unknown_libname_27(&v15, 2);
unknown_libname_27(&v17, 2);
unknown_libname_27(&v19, 2);
return unknown_libname_27(&v21, 2);
}
可以看到中间有个赋值动作
if ( *(_DWORD *)(v1 + 780) == 62 )
*(_DWORD *)(v1 + 780) = 133;
所以本函数将影响前一个函数,这边也会发现两个do-while也是迷惑性的,根本不会影响上面的赋值表达式,而问题又转移到什么时候*(_DWORD *)(v1 + 780) == 62表达式会成立呢?来看最后一个自定义函数ChkCode
int __fastcall TForm1_chkcode(int a1, int a2, signed __int32 a3, int a4)
{
int v4; // ebx@1
int v5; // ST04_4@1
int v6; // ecx@1
int v7; // esi@1
int v8; // eax@2
int v9; // ST08_4@2
int v10; // ecx@2
char v11; // zf@3
int v12; // eax@5
int v13; // esi@5
int v14; // eax@6
int v15; // ST08_4@6
int v16; // ecx@6
int v17; // eax@7
unsigned int v19; // [sp-Ch] [bp-44h]@1
int (__stdcall *v20)(int); // [sp-8h] [bp-40h]@1
int (__stdcall *v21)(int); // [sp-4h] [bp-3Ch]@1
int v22; // [sp+8h] [bp-30h]@6
int v23; // [sp+Ch] [bp-2Ch]@6
int v24; // [sp+10h] [bp-28h]@6
int v25; // [sp+14h] [bp-24h]@6
int v26; // [sp+18h] [bp-20h]@3
int v27; // [sp+1Ch] [bp-1Ch]@2
int v28; // [sp+20h] [bp-18h]@2
int v29; // [sp+24h] [bp-14h]@2
int v30; // [sp+28h] [bp-10h]@2
int v31; // [sp+2Ch] [bp-Ch]@1
int v32; // [sp+30h] [bp-8h]@1
int v33; // [sp+34h] [bp-4h]@1
int v34; // [sp+38h] [bp+0h]@1
_InterlockedExchange((signed __int32 *)&v33, a3);
v4 = a1;
v21 = (int (__stdcall *)(int))&v34;
v20 = loc_457E3D;
v19 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v19);
Sysutils::IntToStr(*(_DWORD *)(a1 + 760) + 5, &v32);
v5 = *(_DWORD *)(v4 + 788);
TControl::GetText(*(_DWORD *)(v4 + 724), &v31);
System::__linkproc___LStrCatN(v4 + 792, 4, v6, v5, v31);
Controls::TControl::SetVisible(*(_DWORD *)(v4 + 756), 0);
Controls::TControl::SetText(*(_DWORD *)(v4 + 756), *(_DWORD *)(v4 + 792));
v7 = 0;
do
{
TControl::GetText(*(_DWORD *)(v4 + 724), &v29);
v8 = sub_403B7C(v29);
Sysutils::IntToStr(v8 + 3, &v30);
TControl::GetText(*(_DWORD *)(v4 + 724), &v28);
v9 = v28;
Sysutils::IntToStr(v7, &v27);
System::__linkproc___LStrCatN(&v33, 3, v10, v9, v27);
++v7;
}
while ( v7 != 19 );
TControl::GetText(*(_DWORD *)(v4 + 728), &v26);
System::__linkproc___LStrCmp(v26, *(_DWORD *)(v4 + 792));
if ( v11 )
*(_DWORD *)(v4 + 780) = 62;
v12 = *(_DWORD *)(v4 + 780) + 16;
*(_DWORD *)(v4 + 764) = v12;
*(_DWORD *)(v4 + 768) = v12 + 35;
v13 = 0;
do
{
TControl::GetText(*(_DWORD *)(v4 + 724), &v24);
v14 = sub_403B7C(v24);
Sysutils::IntToStr(v14 + 3, &v25);
TControl::GetText(*(_DWORD *)(v4 + 724), &v23);
v15 = v23;
Sysutils::IntToStr(v13, &v22);
System::__linkproc___LStrCatN(&v33, 3, v16, v15, v22);
++v13;
}
while ( v13 != 19 );
v17 = *(_DWORD *)(v4 + 768) + *(_DWORD *)(v4 + 764);
*(_DWORD *)(v4 + 772) = v17;
*(_DWORD *)(v4 + 776) = v17 + *(_DWORD *)(v4 + 764) + 9;
__writefsdword(0, v19);
v21 = loc_457E44;
unknown_libname_26(&v22);
unknown_libname_27(&v23, 2);
unknown_libname_26(&v25);
unknown_libname_26(&v26);
unknown_libname_26(&v27);
unknown_libname_27(&v28, 2);
unknown_libname_26(&v30);
unknown_libname_26(&v31);
return unknown_libname_27(&v32, 2);
}
简单的分析上面的函数,去掉无关代码结果如下:(注意this+784/788我们在第一个自定义函数中已经知道是两个常量字符串,IDA的StrCat漏掉了下面两个参数,分别是this->784以及用户名长度this->760+5)
int __fastcall TForm1_chkcode(int this, int a2, signed __int32 a3, int a4)
{
TControl::GetText(*(_DWORD *)(v4 + 724), &pszName);
System::__linkproc___LStrCatN(v4 + 792, *(_DWORD *)(v4 + 784), *(_DWORD *)(v4 + 760)+5 ,*(_DWORD *)(v4 + 788), pszName);
TControl::GetText(*(_DWORD *)(v4 + 728), &pszSerial);
if (!System::__linkproc___LStrCmp(pszSerial, *(_DWORD *)(v4 + 792)))
*(_DWORD *)(v4 + 780) = 62;
}
根据上面的函数可以推导出注册算法为
void main()
{
char szMagicA[] = "黑头Sun Bird";
char szMagicB[] = "dseloffc-012-OK";
char szName[] = "@@@@";
cout<<"The Serial:"<<szMagicA<<strlen(szName)+5<<szMagicB<<szName<<endl;
}
输入用户名和序列号后,双击画布再单击画布即可完成破解