本人小菜一个,呵呵 属于是瞎子逆向,不过还是分析出了一些东西,本着学习研究的态度下面就给大家分享一下。
首先QQ密码是采用了xxxx先进的键盘加密技术,所以如果再从键盘截取这条路截取密码显然是比较难的了,而且成本也比较高,所以我们要从另外一条路下手。在QQ协议里面,QQ的密码是先MD5然后BASE编码 然后再发送到服务器验证的。所以这里就是关键了,无论那个先进的键盘加密怎样加密,他最终还是要还原成原来的密码然后再进行MD5+BASE的编码,如果我们能在MD5加密之前截获他,嘿嘿~~~这里就留给了我们获取密码的机会,我的思路大概就是这样的了,下面就是具体的实现过程
我们首先要定位到MD5加密代码的附近,如何定位呢?这样用PEID里面的插件Krypto ANALyzer比较方便(当然也可以自己找),首先到目录里面看看有没有什么可疑的文件,LoginCtrl.dll 一看就应该是目标了,然后查到了MD5加密代码在0x608C5F87附近,然后直接把QQ扔OD里面到0x608C5F87去看看(呵呵,QQ无壳无反调试 还真轻松)
608C5F84 |. 8D943A 56B7C7E8 |lea edx, dword ptr [edx+edi+E8C7B75>
608C5F8B |. 8BFA |mov edi, edx
..................(很长的加密函数)
然后在函数末尾下断,先跟一下 乱输个密码登陆 QQ就断下了
返回来到这里
608C6897 |. 8B45 08 mov eax, dword ptr [ebp+8]
608C689A |. 8B0E mov ecx, dword ptr [esi]
。。。。。。。。(又是一个长长的加密函数)
然后再跟到返回 来到了608B6D1E 很明显,608b6d19应该就是MD5的call了,这个call有两个参数,一个应该是加密的字符,另外一个应该就是加密后保存的缓冲区;
608B6D15 |> \53 |push ebx
608B6D16 |. FF75 DC |push dword ptr [ebp-24]
608B6D19 |. E8 D9FA0000 |call 608C67F7
608B6D1E |. 6A 5C |push 5C ; /n = 5C (92.)
608B6D20 |. 6A 00 |push 0 ; |c = 00
608B6D22 |. 53 |push ebx ; |s
608B6D23 |. E8 9EE90000 |call <jmp.&MSVCRT.memset> ; \memset
这里想都想得到,为了密码的安全 memset应该就是清除密码
密码地址的内容如下,很奇怪uczvhcncfbsgdbms 不是我输入的密码,先不管这个,继续跟下去
01195528 77 99 93 EF 1F 3D 18 E4 95 51 1D FC DC CF 4B F0 w檽?=鋾Q螷
01195538 80 00 00 00 00 00 00 00 75 63 7A 76 68 63 6E 63 €.......uczvhcnc
01195548 66 62 73 67 64 62 6D 73 80 00 00 00 00 00 00 00 fbsgdbms€.......
再跟下去就到了下一轮循环了整个循环内容如下。
608B6C85 |> /8B45 CC /mov eax, dword ptr [ebp-34]
608B6C88 |. |8B4D E8 |mov ecx, dword ptr [ebp-18]
608B6C8B |. |03C1 |add eax, ecx
608B6C8D |. |99 |cdq
608B6C8E |. |F7FE |idiv esi
608B6C90 |. |837D D4 00 |cmp dword ptr [ebp-2C], 0
608B6C94 |. |8BFA |mov edi, edx
608B6C96 |. |75 35 |jnz short 608B6CCD
608B6C98 |. |68 ECBF8D60 |push 608DBFEC
608B6C9D |. |8D4D D8 |lea ecx, dword ptr [ebp-28]
608B6CA0 |. |E8 01E40000 |call <jmp.&MFC42.#CString::CString_5>
608B6CA5 |. |8B45 D8 |mov eax, dword ptr [ebp-28]
608B6CA8 |. |8365 FC 00 |and dword ptr [ebp-4], 0
608B6CAC |. |C1E7 04 |shl edi, 4
608B6CAF |. |FF70 F8 |push dword ptr [eax-8]
608B6CB2 |. |037D E4 |add edi, dword ptr [ebp-1C]
608B6CB5 |. |50 |push eax
608B6CB6 |. |57 |push edi
608B6CB7 |. |E8 58FC0000 |call 608C6914
608B6CBC |. |834D FC FF |or dword ptr [ebp-4], FFFFFFFF
608B6CC0 |. |83C4 0C |add esp, 0C
608B6CC3 |. |8D4D D8 |lea ecx, dword ptr [ebp-28]
608B6CC6 |. |E8 23E10000 |call <jmp.&MFC42.#CString::~CString_>
608B6CCB |. |EB 5E |jmp short 608B6D2B
608B6CCD |> |8BC7 |mov eax, edi
608B6CCF |. |8B4D EC |mov ecx, dword ptr [ebp-14]
608B6CD2 |. |6BC0 5C |imul eax, eax, 5C
608B6CD5 |. |8D1C08 |lea ebx, dword ptr [eax+ecx]
608B6CD8 |. |53 |push ebx
608B6CD9 |. |E8 87EF0000 |call 608C5C65
608B6CDE |. |8B45 D4 |mov eax, dword ptr [ebp-2C]
608B6CE1 |. |59 |pop ecx
608B6CE2 |. |85C0 |test eax, eax
608B6CE4 |. |7E 2F |jle short 608B6D15
608B6CE6 |. |8365 E0 00 |and dword ptr [ebp-20], 0
608B6CEA |. |8945 D0 |mov dword ptr [ebp-30], eax
608B6CED |> |8B45 C8 |/mov eax, dword ptr [ebp-38]
608B6CF0 |. |6A 01 ||push 1
608B6CF2 |. |8B40 44 ||mov eax, dword ptr [eax+44]
608B6CF5 |. |8B00 ||mov eax, dword ptr [eax]
608B6CF7 |. |0345 E0 ||add eax, dword ptr [ebp-20]
608B6CFA |. |8A0438 ||mov al, byte ptr [eax+edi]
608B6CFD |. |8845 F3 ||mov byte ptr [ebp-D], al
608B6D00 |. |8D45 F3 ||lea eax, dword ptr [ebp-D]
608B6D03 |. |50 ||push eax
608B6D04 |. |53 ||push ebx
608B6D05 |. |E8 99EF0000 ||call 608C5CA3
608B6D0A |. |0175 E0 ||add dword ptr [ebp-20], esi
608B6D0D |. |83C4 0C ||add esp, 0C
608B6D10 |. |FF4D D0 ||dec dword ptr [ebp-30]
608B6D13 |.^|75 D8 |\jnz short 608B6CED
608B6D15 |> |53 |push ebx
608B6D16 |. |FF75 DC |push dword ptr [ebp-24]
608B6D19 |. |E8 D9FA0000 |call 608C67F7
608B6D1E |. |6A 5C |push 5C ; /n = 5C (92.)
608B6D20 |. |6A 00 |push 0 ; |c = 00
608B6D22 |. |53 |push ebx ; |s
608B6D23 |. |E8 9EE90000 |call <jmp.&MSVCRT.memset> ; \memset
608B6D28 |. |83C4 14 |add esp, 14
608B6D2B |> |FF45 E8 |inc dword ptr [ebp-18]
608B6D2E |. |8345 DC 10 |add dword ptr [ebp-24], 10
608B6D32 |. |3975 E8 |cmp dword ptr [ebp-18], esi
608B6D35 |.^\0F8C 4AFFFFFF \jl 608B6C85
很奇怪,不知道为什么密码要计算这么多次,(很可能是混有假密码在里面),在memset这里下断 多跟踪几次,最终在memset的参数的指令里面发现了输入的密码(输入的密码是N个d),欣喜中......
01195750 F8 D9 02 4E 1E FC 5C 82 B0 39 69 4D 66 70 42 64 N黒偘9iMfpBd
01195760 80 00 00 00 00 00 00 00 64 64 64 64 64 64 64 64 €.......dddddddd
01195770 64 64 64 64 64 64 64 64 80 00 00 00 00 00 00 00 dddddddd€.......
这里是密码的HASH
01195818 F8 D9 02 4E 1E FC 5C 82 B0 39 69 4D 66 70 42 64 N黒偘9iMfpBd
接下来的问题是密码是在其中找到了,关键是我们怎么才知道哪个才是正确的密码呢?继续跟...
跳出循环后来到了这里
608B6D3B |> \2B75 CC sub esi, dword ptr [ebp-34]
608B6D3E |. 6A 10 push 10
608B6D40 |. 8D4D DC lea ecx, dword ptr [ebp-24]
608B6D43 |. 4E dec esi
608B6D44 |. C1E6 04 shl esi, 4
608B6D47 |. 0375 E4 add esi, dword ptr [ebp-1C]
608B6D4A |. 56 push esi
608B6D4B |. E8 12E50000 call <jmp.&MFC42.#CString::CString_538>
608B6D50 |. 8D45 DC lea eax, dword ptr [ebp-24]
608B6D53 |. C745 FC 01000000 mov dword ptr [ebp-4], 1
608B6D5A |. 50 push eax
608B6D5B |. FF15 3CC08C60 call dword ptr [<&BasicCtrlDll.Encode16>] ; BasicCtr.Encode16
这里看到将十六个字节转换字符串 应该就是密码的HASH了,然后下面的BasicCtrlDll.Encode16再编码,跟到CString看看堆栈
0012EFA4 01195818
0012EFA8 00000010
这里的01195818就是刚刚MD5那里算出来的hash。
到这里,整个密码处理的流程差不多就清楚了,我们就可以根据这个拦截密码了,首先在HOOK memset的这个call然后获取密码和密码的hash,然后再HOOK 后面的Cstring 根据HASH找出真的密码。这里有个问题是由于QQ2008的版本众多所以还要利用特征码来动态定位,下面就是实现的效果,和测试代码
(由于本人小菜一个,逆向功夫不到家,很多东西都吃不准,如果有什么失误,不足的还望各位高手指出,让我等小菜学习学习)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!