又是Delphi的程序, 有了上次的经验这次顺利了很多。差不多花了70分钟的样子, 把这个东西逆出来了。
先运行一下, 看看基本的功能, 这个作者一直用dumb或者idiot来称呼破解者(无奈), 着实有点皮
填充不完全会出现如下对话框:
如果serial不对, 会出现如下对话框:
这个crackme会通过Name来计算出Serial1和Serial2两个值, 如果满足要求过了。直接定位到Button的处理函数。
下断点, 输入一些值后F9运行, 断到Button的处理函数
首先它检测了2个DWORD的值是否为0, 如果是0那就跳转到显示没有填完整的弹框(红色框), 接着获取了Name, Serial1, Serial2这3个值的内容(蓝色框), 同样对比是否存在, 不存在就跳转到显示没有填完整的弹框。
接着再次对比2个DWORD值是否为0, 不是0就通过Hex2DecString把第一个DWORD值也就是nNameHash(实际上这是Serial1进行某种运算得到的值)转成了10进制字符串。
在Delphi的反汇编工具里也体现了这一点
马上就是关键的一步了, 把刚生产的nNameHash十进制字符串和serial1字符串作为参数传入了CheckSerial函数里
CheckSerial首先确认传入2个字符串不为空然后分别获取了它们2个的长度取值, 并获取长度差
从2个字符串内分别取出4字节放入ebx和ecx内, 然后进行对比是否相同。
如果不同, 那分别进行对比(之前都对比过不一样了, 不知道这有啥意义)
出来之后如果都相同那又会如法炮制, 把serial2和nSerial1Hash传入CheckSerial函数进行对比, 如果说一致, 那就代表正确。因为我这里输入的是随机值, 所以自然是不对的, 第一个CheckSerial都过不了。
所以可以得到结论, 成功的条件就是生成的2个hash值分别与serial1和serial2相等。现在就是要找这两个hash值的生成过程。于是我重新调试程序发现在按下button, button的处理过程还没开始时, 两个hash值就已经生成了。
而我又发现, 在我输入Name的时候, 这两个值就一直在变动。说明它肯定对按键事件进行捕获并处理。在TForm1中有另一个事件Edit1KeyPress, 很明显就是它了。
到IDA里面一看, 果然如此, 一切都明了了。
注册机编写很简单, 直接把这个函数复制下来改一下就行, 下面是核心代码:
DWORD dwHashA = 0;
DWORD dwHashB = 0;
BOOL CKeyGenDlg::CalcHash(char ch, BOOL fShow)
{
switch (ch)
{
case 8:
dwHashA = 0;
dwHashB = 0;
break;
case 0x41:
dwHashA += 1064;
dwHashB += 5648;
break;
case 0x42:
dwHashA += 726576;
dwHashB += 2;
break;
case 0x43:
dwHashA += 3462;
dwHashB += 9999;
break;
case 0x44:
dwHashA += 4516;
dwHashB += 74445628;
break;
case 0x45:
dwHashA += 73482;
dwHashB += 35644;
break;
case 0x46:
dwHashA += 15554;
dwHashB += 34328;
break;
case 0x47:
dwHashA += 254376;
dwHashB += 444444;
break;
case 0x48:
dwHashA += 37348;
dwHashB += 2615621;
break;
case 0x49:
dwHashA += 27458;
dwHashB += 3131331;
break;
case 0x4A:
dwHashA += 333476;
dwHashB += 12121212;
break;
case 0x4B:
dwHashA += 275546;
dwHashB += 71111;
break;
case 0x4C:
dwHashA += 1834457;
dwHashB += 76628;
break;
case 0x4D:
dwHashA += 10349;
dwHashB += 734348;
break;
case 0x4E:
dwHashA += 1025;
dwHashB += 897376628;
break;
case 0x4F:
dwHashA += 1652;
dwHashB += 3243223;
break;
case 0x50:
dwHashA += 156;
dwHashB += 8247348;
break;
case 0x51:
dwHashA += 342;
dwHashB += 236752;
break;
case 0x52:
dwHashA += 34343;
dwHashB += 783434;
break;
case 0x53:
dwHashA += 7635344;
dwHashB += 8734342;
break;
case 0x54:
dwHashA += 42344;
dwHashB += 78368;
break;
case 0x55:
dwHashA += 87442;
dwHashB += 12334;
break;
case 0x56:
dwHashA += 7641;
dwHashB += 7235;
break;
case 0x57:
dwHashA += 15552;
dwHashB += 323528;
break;
case 0x58:
dwHashA += 9834;
dwHashB += 732523528;
break;
case 0x59:
dwHashA += 33553;
dwHashB += 7238;
break;
case 0x5A:
dwHashA += 52763;
dwHashB += 726628;
break;
case 0x61:
dwHashA += 1063;
dwHashB += 121;
break;
case 0x62:
dwHashA += 1724;
dwHashB += 111;
break;
case 0x63:
dwHashA += 1169;
dwHashB += 738;
break;
case 0x64:
dwHashA += 18253;
dwHashB += 762;
break;
case 0x65:
dwHashA += 1024;
dwHashB += 14;
break;
case 0x66:
dwHashA += 1744;
dwHashB += 13;
break;
case 0x67:
dwHashA += 1661;
dwHashB += 12;
break;
case 0x68:
dwHashA += 1872;
dwHashB += 11;
break;
case 0x69:
dwHashA += 1084;
dwHashB += 99;
break;
case 0x6A:
dwHashA += 1892;
dwHashB += 888;
break;
case 0x6B:
dwHashA += 192;
dwHashB += 77;
break;
case 0x6C:
dwHashA += 10109;
dwHashB += 555;
break;
case 0x6D:
dwHashA += 2078;
dwHashB += 90;
break;
case 0x6E:
dwHashA += 3591;
dwHashB += 98;
break;
case 0x6F:
dwHashA += 142;
dwHashB += 7468;
break;
case 0x70:
dwHashA += 632432;
dwHashB += 575475;
break;
case 0x71:
dwHashA += 3415;
dwHashB += 648;
break;
case 0x72:
dwHashA += 24555;
dwHashB += 538;
break;
case 0x73:
dwHashA += 2224;
++dwHashB;
break;
case 0x74:
dwHashA += 1211;
dwHashB += 64;
break;
case 0x75:
dwHashA += 2242;
dwHashB += 75;
break;
case 0x76:
dwHashA += 7334;
dwHashB += 78;
break;
case 0x77:
dwHashA += 9502;
dwHashB += 5;
break;
case 0x78:
dwHashA += 917;
dwHashB += 38;
break;
case 0x79:
dwHashA += 11539;
dwHashB += 8;
break;
case 0x7A:
dwHashA += 6400;
dwHashB += 456;
break;
default:
dwHashA = 0;
dwHashB = 0;
SetDlgItemText(IDC_EDIT_SERIAL1, "");
SetDlgItemText(IDC_EDIT_SERIAL2, "");
SetDlgItemText(IDC_EDIT_NAME, "");
return(FALSE);
}
if (fShow)
{
SetDlgItemInt(IDC_EDIT_SERIAL1, dwHashA, FALSE);
SetDlgItemInt(IDC_EDIT_SERIAL2, dwHashB, FALSE);
}
return(TRUE);
}
void CKeyGenDlg::OnBnClickedBtnGen()
{
// TODO: 在此添加控件通知处理程序代码
char szBuf[20] = {0};
CString strName;
int iLen = 0;
// 获取输入的name值
GetDlgItemText(IDC_EDIT_NAME, strName);
if (strName.IsEmpty())
{
MessageBox("Name can't be empty!");
return;
}
strcpy_s(szBuf, sizeof(szBuf), strName.GetBuffer());
char* pszName = szBuf;
iLen = strlen(pszName);
RtlZeroMemory(szBuf + iLen, sizeof(szBuf) - iLen);
size_t n = 0;
for (; n < iLen; ++n)
{
if (!CalcHash(pszName[n], ((n == (iLen - 1)) ? TRUE : FALSE)))
{
SetDlgItemText(IDC_STATIC_STATUS, "Status: Failed");
break;
}
}
if (n >= iLen)
{
SetDlgItemText(IDC_STATIC_STATUS, "Status: Success");
}
dwHashA = dwHashB = 0;
}
附上成功截图, 哦, 对了, 记得要输入Name而不是直接复制粘贴, 因为它是根据每次输入进行计算的。还有如果说按了退格(0x8), 那会把Name清空要你重新输。
(完)