📄 qq 2005贺岁版登录口令加密算法及其源代码.txt
字号:
1000B952 50 push eax
1000B953 E8 B4FCFFFF call BasicCtr.1000B60C call 1000B60C(CString,Flag,CString)
1000B958 85FF test edi,edi
1000B95A 74 18 je short BasicCtr.1000B974
1000B95C 8B45 E0 mov eax,dword ptr ss:[ebp-20] 局部变量[ebp-28]第一次为0,为一个计数器
1000B95F 8B4B 64 mov ecx,dword ptr ds:[ebx+64] 存在于标志结构中,为一个全局地址
1000B962 8B55 F0 mov edx,dword ptr ss:[ebp-10] 局部变量[ebp-10]保存拷贝后的数据,即没有经过处理的。例如040300BDAF……
1000B965 C1E0 02 shl eax,2 EAX=EAX*2
1000B968 891401 mov dword ptr ds:[ecx+eax],edx 将未做解调的原始数据放到全局结构中某个指针指示的内存中
1000B96B 8B4B 78 mov ecx,dword ptr ds:[ebx+78] 存在于标志结构中,为一个全局地址
1000B96E 8B55 CC mov edx,dword ptr ss:[ebp-34] 局部变量[ebp-34]保存本数据段的总长度
1000B971 891401 mov dword ptr ds:[ecx+eax],edx 将数据长度放到全局结构中某个指针指示的内存中
1000B974 8065 FC 00 and byte ptr ss:[ebp-4],0 局部布尔型变量[ebp-4]=0
1000B978 8D4D EC lea ecx,dword ptr ss:[ebp-14]
1000B97B E8 1C400000 call <MFC42.CString::~CString> 清除数据段中的数据部分CString
1000B980 834D FC FF or dword ptr ss:[ebp-4],FFFFFFFF 局部布尔型变量[ebp-4]=-1,为True
1000B984 8D4D E8 lea ecx,dword ptr ss:[ebp-18]
1000B987 E8 10400000 call <MFC42.CString::~CString> 清除数据段中的标志部分CString,例如AST
1000B98C FF45 E0 inc dword ptr ss:[ebp-20] 局部变量[ebp-28]计数器加一
1000B98F 8B45 E0 mov eax,dword ptr ss:[ebp-20]
1000B992 3B45 B8 cmp eax,dword ptr ss:[ebp-48] 局部变量[ebp-48]保存数据的段数
1000B995 0F8C DFFDFFFF jl BasicCtr.1000B77A 循环解调每个数据段
1000B99B 8B45 08 mov eax,dword ptr ss:[ebp+8] 最后剩余的长度
1000B99E F7D8 neg eax
1000B9A0 1BC0 sbb eax,eax
1000B9A2 83E0 04 and eax,4
1000B9A5 EB 1E jmp short BasicCtr.1000B9C5
1000B9A7 837D F0 00 cmp dword ptr ss:[ebp-10],0
1000B9AB 74 09 je short BasicCtr.1000B9B6
1000B9AD FF75 F0 push dword ptr ss:[ebp-10]
1000B9B0 E8 FF3F0000 call <MFC42.operator delete>
1000B9B5 59 pop ecx
1000B9B6 834D FC FF or dword ptr ss:[ebp-4],FFFFFFFF
1000B9BA 8D4D E8 lea ecx,dword ptr ss:[ebp-18]
1000B9BD E8 DA3F0000 call <MFC42.CString::~CString>
1000B9C2 6A 04 push 4
1000B9C4 58 pop eax
1000B9C5 8B4D F4 mov ecx,dword ptr ss:[ebp-C]
1000B9C8 5F pop edi
1000B9C9 5E pop esi
1000B9CA 5B pop ebx
1000B9CB 64:890D 000000 mov dword ptr fs:[0],ecx
1000B9D2 C9 leave
1000B9D3 C2 0400 retn 4
1000B9D6 837D F0 00 cmp dword ptr ss:[ebp-10],0
1000B9DA 74 09 je short BasicCtr.1000B9E5
1000B9DC FF75 F0 push dword ptr ss:[ebp-10]
1000B9DF E8 D03F0000 call <MFC42.operator delete>
1000B9E4 59 pop ecx
1000B9E5 8B45 D4 mov eax,dword ptr ss:[ebp-2C]
1000B9E8 EB 12 jmp short BasicCtr.1000B9FC
1000B9EA 837D F0 00 cmp dword ptr ss:[ebp-10],0
1000B9EE 74 09 je short BasicCtr.1000B9F9
1000B9F0 FF75 F0 push dword ptr ss:[ebp-10]
1000B9F3 E8 BC3F0000 call <MFC42.operator delete>
1000B9F8 59 pop ecx
1000B9F9 8B45 D0 mov eax,dword ptr ss:[ebp-30]
1000B9FC 8B08 mov ecx,dword ptr ds:[eax]
1000B9FE 50 push eax
1000B9FF FF51 08 call dword ptr ds:[ecx+8]
1000BA02 8BF3 mov esi,ebx
1000BA04 EB 03 jmp short BasicCtr.1000BA09
1000BA06 6A 04 push 4
1000BA08 5E pop esi
1000BA09 8065 FC 00 and byte ptr ss:[ebp-4],0
1000BA0D 8D4D EC lea ecx,dword ptr ss:[ebp-14]
1000BA10 E8 873F0000 call <MFC42.CString::~CString>
1000BA15 834D FC FF or dword ptr ss:[ebp-4],FFFFFFFF
1000BA19 8D4D E8 lea ecx,dword ptr ss:[ebp-18]
1000BA1C E8 7B3F0000 call <MFC42.CString::~CString>
1000BA21 8BC6 mov eax,esi
1000BA23 EB A0 jmp short BasicCtr.1000B9C5
1000BA25 8065 FC 00 and byte ptr ss:[ebp-4],0
1000BA29 8D4D EC lea ecx,dword ptr ss:[ebp-14]
1000BA2C E8 6B3F0000 call <MFC42.CString::~CString>
1000BA31 EB 83 jmp short BasicCtr.1000B9B6
以上代码看不懂没关系,在压缩包中的VB代码 LoAnalysisQD (fbyt() As Byte) 函数概括了上述的思想,不过,对于4和7以外的数据类型,由于与本文内容无关,因此,不深入分析。
六、 QQ的另类破解
1、QQ密码算法和身份验证中存在的问题
搞个几十万次加密其实并不能阻止密码的破解,我对现在收集的EWH.db进行统计,那个循环的AST都在40万以上(可以买房子了,不是么?),因此,只要做一个40万的QQ Hash词典,在此基础上进行破解,破解速度不就提高了几万倍么?
这个词典如何形成?问得好!事实上,国际上有合作破解的先例。例如,可以给我分配000000000~999999999的段进行计算,给你分配999999999~1999999999的段进行计算……,最后,将所有结果合成为一个词典(或者根本不用合成,把Hash值发给大家就可以了,总有人能中大奖:)。
这个词典称为Hash词典,大致上是这样的(密码经过400000次加密后得到):
索引(密码) Hash值(加密后的密文)
1 2E62CD38389C3A885D7F6789FEEE8AA5
2 1F9C9B12E93A0FF2A9B7A714EF4D6CA4
3 8FE71CEF95D0F0DDAD716651E635D19C
…… ……
999999999 A041F9E6DDA44C178F24DABC9B292785
有了这个Hash词典,我们完全没有必要重新忍受漫长的计算过程,直接查表就可以了,不是吗?用黑客的行话来说,就是跑字典了。
利用压缩包中提供的函数QQMD5(unsigned char *, long, long, QQSum *),就完全可以形成这个词典了。
别笑,这好象是大炮打蚊子,对于一个小小的QQ来说,何必劳驾全世界呢?既然这是我们闲得无聊下来干的事,我们就该自己来做。
最简单的Hash词典就是利用黑客词典(网上简直多如牛毛)再通过QQMD5函数来生成,如果你想到用数据库来管理这些Hash值,你一定是个非常敬业的黑客,不过数据库也是TB级的了。
Hash散列算法非常容易产生碰撞,如果你偶尔发现输入12345和输入78952一样可以登录QQ,你千万不要怪腾讯公司没水平,这是因为12345和78952产生的Hash相同(别试,我随便说的两个数),这说明,一个Hash输出可能对应多个输入,这就是碰撞。听说山东大学的王教授就很擅长产生这种碰撞,强烈要求他来做我们的斑竹。
因为碰撞,我们的词典就会小一点,不过,这些理想和共产主义一样,离我们很远,即使王教授的快速碰撞理论,对于QQ这样的重复加密来说,只是加快计算时间,并不能对整个加密体系构成威胁,所以,即使这个世界有那么多的恐怖份子,你我夏天还是穿个短裤就可以上街。
况且,现在很多的及时通讯系统都采用本地和服务器联合验证的方式,这非常有效,即使本地的密码被攻破了,但是,不能保证服务器的也被攻破。因为,通过暴力方式破解的登录口令也只是众多产生碰撞的口令之一,如果使用不同的加密方式,即使这个口令能进入本地系统,但是不能保证同一个口令在服务器端得到验证。所以,QQ从这个意义上说,依然是相对安全的(不过众多口令中,可能就只有一个特别象口令)。
如果我是腾讯的老总,说实话,在我垄断市场的情况下,我并不希望自己的口令体系多么坚不可摧,用户有了危机感,我才能从用户手中收取保护费吧:)所以,诸如此类的文章或者工具即使漫天飞也只是帮他做市场而已。
刚才提到密码算法的问题,谈到的所有问题都是本地的密码机制,对于网络之间的报文,采用的又是TEA的加密算法。这个是我后面的文章要分析的。
在QQ的身份验证中,还存在另外一个漏洞,这个漏洞很早就被发现了,一直保留到现在,也许将来也不会改变。
我不说大家也都知道,将EWH.DB中的QQ号(第一点中的那个3C A8 93 06)替换成别人的QQ号,然后把这个东西放在别人的目录下,就可以看到那个倒霉蛋的聊天记录了。不过,好在腾迅的服务器不买这个帐:看就看吧,只要我这里安全就没事了,多看点多学点,下次聊天就更欢了。
从低层的逻辑也可以看得出来,只要用户的EWH.DB文件符合我们前面的算法,QQ就认为这个用户是合法的。因此,我们完全可以想象,如果我自己做一个EWH.DB文件,让那个40万次的东西变成0,岂不是可以让我的计算机从那个傻呼呼的循环中解脱出来吗?更懒的人可能想到,如果不用密码岂不是更爽?好,我们来实现这个愿望:
运行QQPwdFinality.exe,将登录口令中的“12345”删掉,将“循环次数”改为0,进行单步计算后,是不是得到了一个串?如果你的计算机没骗你的话,大家应该都得到同一个结果:3BF2633660EF5DEB066FE6770317AD91,好了,我们将这个结果替换掉EWH.DB中的那个Hash值07 22 AA 96 56 19 A3 9E 82 19 B7 2B BD 2D 34 4A,最后,EWH.DB文件变成下面这个样子(记得将循环次数也改成0哦):
51 44 01 01 03 00 04 03 00 BD AF A8 04 00 00 00
00 00 00 00 07 03 00 B9 AB B4 10 00 00 00 3B F2
63 36 60 EF 5D EB 06 6F E6 77 03 17 AD 91 04 03
00 A9 B5 B2 04 00 00 00 3C A8 93 06
我知道在座的懒人很多(包括我自己),我特地在QQPwdFinality.exe文件中加入了一个“产生EWH.DB文件”选项,我知道你可能连这都懒得勾,所以默认情况下,我帮你勾上了。 你可以选择任何口令和循环次数来形成EWH.DB文件,文件会生成在当前的目录下。
好了,现在,你再也不用拿着你那个EWH.DB文件到处奔波了,你就用这个吧,毛爷爷不是说过吗?打击敌人的同时还要保护自己,你用自己的口令到处看别人的记录,查出来多不好,况且,一旦忘记删掉了,被受害者拿去,访高手找名人,那你就可能重新申请QQ号了。不过,如果按照这个原理将自己的QQ改造一下,你就比任何人都更快地进入QQ,抢先零点几秒找到PLMM。但是千万别干坏事哦,如果你将别人的AST改成FFFFFF7F的话,估计他要等一天才能和自己心爱的MM聊天了,你忍心下手吗?是不是有人想到发明一个病毒,专门修改这个号,让登录越来越慢啊呵呵。
其实,腾讯稍做努力便可以改掉这个问题,要么在每个QQ Data结构后面加一个Hash验证,要么将用户的QQ号作为密钥,对口令进行加密。最简单的就是用QQ号取代MD5算法中的那个基本字串(即便那几十万个循环中用了一次),这样,自己的EWH.DB就只能自己用了,这才是数字指纹的真正用途嘛。也许你会说,这么做知道了算法还是徒劳,但是,至少可以打破现在的局面——只要会用鼠标的都可以修改EWH.DB,显得这些研究破解的同志多么没有存在的价值啊。
以上谈的这些东西总的说起来都是一些雕虫小技,估计有一半的人看到中途就睡着了,坚持下来的请跟随我进入下一个章节,如果最后还有幸存者,我希望和你交个朋友:)
谈到这里,我想,这篇文章不太适合高手拜读,如果你是高手并且很无聊地走到这里,那么,你可以休息了,走的时候别忘记关灯关门哦。
下面,我们谈谈关于网络的话题。
2、QQ网络登录时存在的问题
MD5的算法固然不错,但并不能取代传统的算法,那种可逆算法在任何时候都是必要的,特别在网络里。我们可以反证一下,如果你在注册QQ或者修改密码的时候,腾讯公司得到的是MD5 Hash,他怎么能知道你原来的密码是多少呢?他绝对不会和我们一样傻,通过暴力破解的方式得到吧。当然,腾讯公司也可以只要MD5,如果是这样,他就等于失去了一次对用户的隐私进行窥探的机会,这对于任何一个公司来说都是不可能的。
退一步说,即使有的公司宣布,为了用户利益,对用户的密码不感兴趣,但是,他还是要知道是谁采用了合法的方式登录,因此,最终都不能免俗,都必须从用户发来的网络包中提取信息来完成身份的校验,以便对上帝们发出邀请或对恶魔们进行拒绝,OK,如果魔鬼扮成上帝呢?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -