这个网络电视的补丁以及内存注册机在网上有不少,但听朋友说有部分会被报木马,或是升级版本后又不能用了。因此下了一个看看
安装好后先PEiD->ASPack 2.12 -> Alexey Solodovnikov,简单脱掉后再看Borland Delphi 6.0 - 7.0,游戏开始
分别用IDA及DeDe打开脱壳后的文件(IDA自带的FLIRT库能识别的函数没有DeDe全, 因此双开)
先看一眼用户注册窗口下注册认证按钮的事件处理函数
0051D998 Tfm_reg.Bt_okClick
简单看一下之后发现这个函数只是将加密后的用户名和注册码分别存入注册表中
用户输入的注册码: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\olympic\"pic"
用户输入的用户名: HKEY_CURRENT_USER\SoftWare\Microsoft\Windows\CurrentVersion\patron\"mortal"
具体用户名加密算法暂时先跳过,先找注册校验函数
既然用户名和注册码被写入注册表,程序启动时刻肯定会读出来,所以根据注册表键值找到了注册校验函数
0051777C VerifyRegInfo
首先注意到的是这个函数有一个从Tfm_main.FormCreate过来的代码引用。意料之中,程序在主窗体创建的时进行校验注册信息
先是解密从注册表中读出的用户名,略过。。。
接下来是算法部分,代码不算短,第一感觉是有些烦,难怪有那么多偷懒的补丁和内存注册机。
再看一下,似乎没有那么糟糕,因为校验主函数直接调用的未识别子函数还是比较有限,分别有以下几个地址
00478370 decription
00478F74 encription1
004DCA78 encription2
00478188 encription3
其中decription函数在校验部分没有使用到,跳过。。。
从第二个子函数00478F74 encription1开始
call层次不少,跳进去看一下。。。
哈。。。在其中一个子函数004785FC内有很多醒目的常量。
。。。
CODE:00478674 push 0E8C7B756h
CODE:00478679 mov eax, ebp
CODE:0047867B mov ecx, [esi]
CODE:0047867D mov edx, [ebx]
CODE:0047867F call sub_4784B8
CODE:00478684 mov eax, [esi]
CODE:00478686 push eax
CODE:00478687 mov eax, [esp+68h+var_94]
CODE:0047868B push eax
CODE:0047868C push 11h
CODE:0047868E push 242070DBh
CODE:00478693 mov eax, edi
CODE:00478695 mov ecx, [ebx]
CODE:00478697 mov edx, [ebp+50h+var_50]
CODE:0047869A call sub_4784B8
CODE:0047869F mov eax, [ebx]
CODE:004786A1 push eax
CODE:004786A2 mov eax, [esp+68h+var_90]
CODE:004786A6 push eax
CODE:004786A7 push 16h
CODE:004786A9 push 0C1BDCEEEh
。。。
千万别问我这些常量是什么,我的记性不好,幸运的是有google和baidu。。。我搜。。。
哈。。。rp不错,测试也正常,看来第一个函数分析可以收工了。。。将478F74改名为MD5
再看第二个子函数004DCA78 encription2
嗯,这个看起来不像是什么现成的算法,不过还好不算夸张,把代码逆出来好了。。。
CString Str2Ansi(CString sInput)
{
CString sRet = "";
int nLen = sInput.GetLength();
LPBYTE lpTemp = (LPBYTE)(sInput.GetBuffer());
for (int i=0;i<nLen; i++)
{
char c;
c = (lpTemp[ i ])>>4;
c += (c<=9)?0x30:0x37;
sRet = sRet + c;
c = (lpTemp[ i ])&0x0F;
c += (c<=9)?0x30:0x37;
sRet = sRet + c;
}
return sRet;
}
CString EncryptString(CString sInput, CString sKey)
{
CString sRet = "";
CString sTempStr = sInput;
CString sTempKey = sKey;
int nTempLen = sTempStr.GetLength();
int nKeyLen = sTempKey.GetLength();
for (int i=0; i<nKeyLen; i++)
for (int j=0; j<nTempLen; j++)
{
sTempStr.SetAt(j, sTempStr.GetAt(j)^sTempKey[ i ]);
}
sRet = Str2Ansi(sTempStr);
return sRet;
}
接下来是最后一个子函数00478188 encription3
嗯,层次也不少,不过这个子函数明显是decryption对应的加密函数。作者既然偷懒用了MD5,这样较为复杂的对称加密函数不太可能会自己写。还是先找找线索看。。。似乎没有很适合的搜索关键字。。。继续找。。。
嗯,密钥长度是7个字节,google一下"对称加密算法 密钥7字节"。。。我汗一个。。。果然是蹦出了一堆DES,测试一下却发现网上找到的DES算法和程序计算出的值有偏差。既然算法是一样的,那多半是初始 值有所不同,检查一下如果然不出所料。好了,子函数分析到此告一段落,将00478188改名为DES_Encrypt
接下来再次回到注册信息校验主函数。现在已经非常一目了然了,一连串计算之后最后居然是只比较了注册码中的6个字节,不过在比较前还是多了一次DES加密动作,所以直接比较的是的两个加密过的字符串,这个用来防内存注册机的小手段还是太弱了。
程序根据注册码的不同分为标准版,VIP版以及钻石版,有限制的标准版和VIP版 就不管了,钻石版的注册码是长度为16的字符串,其中第4个字节开始的6个字节必须和根据机器码用户名计算出的结果一致,其余的10个字节随机生成。最后 敲几行代码,结束了吗?再汗一个。。。原来作者在Tfm_main.FormCreate事件中还有一处额外的网络验证,程序会访问如下地址:
http://www.jesen.cn/check/isdaolian.asp?id=机器码
如果返回的结果是"!已注册"则清除注册表中的注册码。这里最简单的办法当然是patch掉代码或数据,不过我还是不喜欢打补丁而且也不希望新版继续补下去。再看一眼程序播放网络电视似乎和这个域名无关,改hosts。。。收工
最后简单总结一下,从逆向分析角度上考虑
●
[*]心态很重要。注册信息校验函数及部分子函数虽然较长或是层次太深,但实际情况可能远没有第一眼看到那么糟糕
[*]不要过分沉迷于细节。其实很多loop,call之类的根本就无需浪费脑细胞。这一点上如果是分析恶意软件更为重要,因为恶意软件通常目的都更为明确,能确定函数功能时就没有必要去详细弄清楚每一个局部变量的作用
[*]google和baidu有可能是最好的帮手。当然如果能熟记各类常见加密解密压缩算法更好,但很遗憾我的记性不够用
[*]有时候直接看汇编会比较累,不妨先用自己习惯的语言描述出正在分析的函数,然后再分析逻辑会更简单
[*]虽然IDA很强大,但还是不要过分依赖某一个工具,例如DeDe分析Delphi的能力就比IDA强
[*]此外能避免调试就尽量避免,熟练之后静态分析的速度通常会比动态调试快从程序设计角度反思一下,程序的作者很明显还是下了一番功夫,但以下几个问题还是不太应该出现的●
[*]如果要自己写注册算法,可以考虑使用公开算法,但绝对不能过分依赖于公开算法。核心算法过分依赖MD5和DES的后果是一旦这两个函数被识别出来写算法注册机就没有什么障碍了
[*]虽然作者希望防止内存注册机,但仅仅在字符串比较前做两次DES加密是远远不够的,现有的内存注册机多半也是利用最后加密前读出的注册码
[*]网络验证如果只是简单的比较一下返回值基本上形同虚设
[*]既然要用壳。。。就还是用个强度高一点的吧备注:●
[*]本文的初衷是探讨逆向分析及安全设计的一些问题,如果有兴趣这方面的问题欢迎讨论
[*]请不要问我这个软件怎么用或是有什么BUG怎么解决之类的问题,我不喜欢看电视也不用此类的软件
[*]如果喜欢这款作品,请支持一下作者购买正版授权
[*]我分析的版本是2.51.3,新版2.53.1算法没有改变
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)