运行分析
- 输入User Name和SN,返回要重启注册码,并且文件夹出现了一个reg.dll,猜测需要先注册
PE分析
- Delphi程序,32位,无壳
- Delphi是Windows平台下著名的快速应用程序开发工具
静态分析
- 查看reg.dll,发现是刚才的输入
- ida找到关键字符串并进入分析主函数
int __usercall TFmReg_FormCreate@<eax>(int a1@<eax>, int a2@<ebx>, int a3@<esi>)
{
int v4; // edx
Classes::TStrings *v5; // ebx
unsigned __int64 v6; // st7
Classes::TCollectionItem *v7; // eax
unsigned int v9[2]; // [esp+8h] [ebp-2Ch] BYREF
int *v10; // [esp+10h] [ebp-24h]
int v11; // [esp+14h] [ebp-20h]
int v12; // [esp+18h] [ebp-1Ch]
void *v13; // [esp+1Ch] [ebp-18h] BYREF
int v14; // [esp+20h] [ebp-14h] BYREF
int v15; // [esp+24h] [ebp-10h]
int v16; // [esp+28h] [ebp-Ch]
int str_unreg; // [esp+2Ch] [ebp-8h] BYREF
void *str_reg_success; // [esp+30h] [ebp-4h] BYREF
int savedregs; // [esp+34h] [ebp+0h] BYREF
v16 = 0;
v15 = 0;
v14 = 0;
v13 = 0;
v12 = a2;
v11 = a3;
v10 = &savedregs;
v9[1] = (unsigned int)&loc_45D5A9;
v9[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v9);
System::__linkproc__ LStrLAsg(&str_reg_success, ®_success[1]);// 已注册变量赋值
System::__linkproc__ LStrLAsg(&str_unreg, &unreg[1]);// 未注册变量赋值
if ( (unsigned __int8)Sysutils::FileExists((const int)&str_reg_dll_0[1]) )// 判断reg.dll是否存在
{
LOBYTE(v4) = 1;
v5 = (Classes::TStrings *)unknown_libname_51(cls_Classes_TStringList, v4);
(*(void (__fastcall **)(Classes::TStrings *, _strings *))(*(_DWORD *)v5 + 104))(v5, &str_reg_dll_0[1]);
Classes::TStrings::GetValue(v5, (const int)&str_UserName[1]);// Username字符串复制
Classes::TStrings::GetValue(v5, (const int)&str_SN[1]);// SN字符串复制
System::TObject::Free(v5);
if ( (unsigned __int8)sub_45D0F4(v16, v15) )// 判断是否注册
{
*(double *)&v6 = sub_45CC34(v15);
unknown_libname_136(v6, HIDWORD(v6));
System::__linkproc__ LStrCat3((int)&v14, str_reg_success, v13);// 拼接注册成功字符串
}
v7 = (Classes::TCollectionItem *)sub_42E7BC(*(Webcomp::TWebComponentList **)(*(_DWORD *)(a1 + 792) + 520), 0);
unknown_libname_522(v7);
}
__writefsdword(0, v9[0]);
v10 = (int *)&loc_45D5B0;
return System::__linkproc__ LStrArrayClr(&v13, 6);
}
- 进入sub_45D0F4查找注册信息
int __usercall sub_45D0F4@<eax>(int UserName@<eax>, int a2@<edx>, unsigned __int64 a3@<st0>)
{
int v3; // ebx
int v4; // eax
char v5; // zf
double v7; // [esp+0h] [ebp-5Ch]
unsigned int v8[2]; // [esp+8h] [ebp-54h] BYREF
int *v9; // [esp+10h] [ebp-4Ch]
unsigned int v10[2]; // [esp+14h] [ebp-48h] BYREF
int *v11; // [esp+1Ch] [ebp-40h]
int v12; // [esp+2Ch] [ebp-30h] BYREF
int v13; // [esp+30h] [ebp-2Ch] BYREF
int v14; // [esp+34h] [ebp-28h] BYREF
char v15[16]; // [esp+38h] [ebp-24h] BYREF
int *v16; // [esp+48h] [ebp-14h] BYREF
int v17; // [esp+4Ch] [ebp-10h] BYREF
int v18; // [esp+50h] [ebp-Ch]
int SN; // [esp+54h] [ebp-8h]
int UerName; // [esp+58h] [ebp-4h]
int savedregs; // [esp+5Ch] [ebp+0h] BYREF
v16 = 0;
v13 = 0;
v12 = 0;
v14 = 0;
v18 = 0;
v17 = 0;
SN = a2;
UerName = UserName;
System::__linkproc__ LStrAddRef(UserName);
System::__linkproc__ LStrAddRef(SN);
v11 = &savedregs;
v10[1] = (unsigned int)&loc_45D253;
v10[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v10);
v3 = 0;
if ( unknown_libname_78(SN) == 16 ) // SN长度要等于16
{
v4 = 1;
while ( (unsigned __int8)(*(_BYTE *)(SN + v4 - 1) - 48) < 10u// SN每个字符要小于65+6=71,70的ascii是F,即SN为[0-9][A-F]
|| (unsigned __int8)(*(_BYTE *)(SN + v4 - 1) - 65) < 6u )
{
if ( ++v4 == 17 )
{
v9 = &savedregs;
v8[1] = (unsigned int)&loc_45D1B0;
v8[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v8);
sub_45CC34(SN, a3);
__asm { fstp [esp+5Ch+var_5C] }
unknown_libname_138(LODWORD(v7), HIDWORD(v7));
sub_45C5E0(UerName, v18, &v17); // 这里出现了SN明文v17
__writefsdword(0, v8[0]);
sub_45BE3C(v17, v15);
sub_45BEB0(v15, &v14);
sub_45BE3C(v14, v15);
sub_45BEB0(v15, &v16); // 以上操作猜测为UserName加密算法,最终得出值为v16
v9 = v16;
sub_45BE3C(SN, v15);
sub_45BEB0(v15, &v12);
sub_45BE3C(v12, v15);
sub_45BEB0(v15, &v13); // 以上操作猜测为SN加密算法,最终得出值为v13
System::__linkproc__ LStrCmp(v9, v13); // 关键比较,相等则返回成功
LOBYTE(v3) = v5;
break;
}
}
}
__writefsdword(0, v10[0]);
v11 = (int *)&loc_45D25A;
System::__linkproc__ LStrArrayClr(&v12, 3);
System::__linkproc__ LStrArrayClr(&v16, 5);
return v3;
}
- 分析注册函数,发现SN必须满足长度为16,且每一位都要是数字或[A-F]字母
- 猜测UserName加密和SN加密后进行比较,相等返回注册成功
动态调试
- 使用x32dbg下断点调试,发现函数reg.0045C5E0执行后,弹出疑似注册码明文C6AAAB056E726C41,正好是16位长度
- 将reg.dll的SN改为C6AAAB056E726C41,重新运行发现破解成功