获取并解密QQ-ClientKey
Contents
ClientKey是类似SSO的token,拿到后可以访问各种QQ服务,如空间、邮箱、微博等,2014年分析着玩的,在此记录一下。
分析记录:
QQ:6.3、6.8 7.4 PlatformCore
1、找到KernelUtil!Util::Misc::GetSignature,挂QQ调试,跟进这些函数里看找函数地址,看偏移是否对得上
2、CTXStringW* KernelUtil!Util::Misc::GetSignature 获取ClientKey
struct ITXCore
{
char* c1; // 00
c1->common_func1(ITXCore*, 675585B0, &Prelogin); // 24
char* c2; // 18
common_func2(c2, ITXCore*,675585B0,&Prelogin); // 20
char* c3; //2c
c3->common_func3(ITXCore*,675585B0,&Prelogin) // 4
c4 = poi(c3+0c)+poi(c3+4)
c4->common_func4(ITXCore*,675585B0,&Prelogin)// 8
c5 = poi(c4+1c)
common_func5(c5,ITXCore*,675585B0,&Prelogin)// 34
c6 = c5+14
c6->search1(&&Prelogin,675585B0,c4)
index = poi(poi(c6+4)+4)+c;
memcmp(index,675585B0)
};
find_clientkey_script:
1、找到PreLogin对象。
as platform_core 004b69b8
as c2 poi(platform_core+0x18)
as c3 poi(c2+0x2c)
as c4 poi(c3+0x0c)+poi(c3+0x4)
as c5 poi(c4+0x1c)
as c6 c5 + 0x14
step1:
r $t1=004b69b8;r $t2=poi($t1+0x18);r $t3=poi($t2+0x2c);r $t4=poi($t3+0x0c)+poi($t3+0x4);r $t5=poi($t4+0x1c);r $t6=$t5+0x14;
step2:
r $t3=poi($t6+4); r $t0=poi(poi($t6+4)+4);.while(by($t0+0x25)==0){r $t2=0x0;.while($t2<0x10){.if(by($t0+0xc+$t2)!=by(0x675585b0+$t2)){.break};r $t2=$t2+1;};.if($t2<0x10){r $t0=poi($t0)}.else{r $t3=$t0;r $t0=poi($t0+8)}}
004b69b8 = platform_core
c2 = poi(platform_core+0x18)
c3 = poi(c2+0x2c)
c4 = poi(c3+0x0c)+poi(c3+0x4)
c5 = poi(c4+0x1c)
c6 = c5 + 0x14
poi($c6+4)
$platform_core
3、对照脚本和ClientKey.xmind,windbg和IDA分析。
1 d 75803c39 0001 (0001) 0:**** SHELL32!ShellExecuteW
4 d 674d7c29 0001 (0001) 0:**** Common!Util::UrlBase::OpenUrlWithTT
5 d 674d7c18 0001 (0001) 0:**** Common!Util::UrlBase::OpenUrlWithDefBrowser
6 d 674d7ab9 0001 (0001) 0:**** Common!Util::UrlBase::OpenUrlWithDefBrowser
7 d 66049a90 0001 (0001) 0:**** Mail!DllUnregisterServer+0x8304
8 d 660499d1 0001 (0001) 0:**** Mail!DllUnregisterServer+0x8245
9 d 672e00b5 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature
10 e 672e014a 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature+0x95
KernelUtil!Util::Misc::GetSignature+0x95
0 d 674d014a 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature+0x95
1 d 674d00b5 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature
2 d 676b7f28 0001 (0001) 0:**** Common!Util::Encode::Encode16+0x25
3 d 674d1cd1 0001 (0001) 0:**** KernelUtil!Util::Misc::Get32ByteValueAddedSign+0x10
4 d 674d0139 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature+0x84
5 d 6539c8c7 0001 (0001) 0:**** PreloginLogic!UtilCSProcessor::CreateDRCSProcessor+0x14b68
6 e 674d011a 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature+0x65
7 e 674d011d 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature+0x68
8 e 674d00e2 0001 (0001) 0:**** KernelUtil!Util::Misc::GetSignature+0x2d
9 e 676d570c 0001 (0001) 0:**** Common!Util::Core::GetPlatformCore
调用流程
编写windbg脚本提取ClientKey
为了简单直接讲QQ.exe存个dump,然后用脚本从dump文件中提取。
find_clientkey.ws是windbg脚本
$$used with QQ.exe.dmp
.printf "\n\n\t$$ **Find QQ ClientKey Windbg Script**\n"
r $t1=dwo(dwo(Common!Util::CoreCenter::GetPlatformCore+4))
r $t2=dwo($t1+0x18);
r $t3=dwo($t2+0x2c);
r $t4=dwo($t3+0x0c)+dwo($t3+0x4);
r $t5=dwo($t4+0x1c);
r $t6=$t5+0x14;
r $t3=dwo($t6+4);
r $t0=dwo(dwo($t6+4)+4);
$$eax=03cbe550
eb @eip 4e 0f 99 3a bc 95 00 4f ae 52 fd d9 fb ff 30 3e
.while(by($t0+0x25)==0)
{
r $t4=0;
.if(dwo($t0+0xc)<0x3a990f4e)
{
r $t4=1;
}
.elsif(dwo($t0+0xc)>0x3a990f4e)
{
r $t4=0;
}
.else
{
r $t2=0x0;
.while($t2<0x10)
{
.if(by($t0+0xc+$t2)<by(eip+$t2))
{
r $t4=1;
.break;
}
r $t2=$t2+1;
}
}
.if($t4==0)
{
r $t3=$t0;
r $t0=dwo($t0)
}
.else
{
r $t0=dwo($t0+8)
}
}
r $t9=dwo($t3+0x20)
.printf "[+] PreLogin: %x\n",$t9
r $t1=dwo($t9+0x14)
r $t1=dwo($t1+0x2c)
.printf "[+] PreLogin2: %x\n",$t1
$$hash_string
r $t3=0xa5177eef
.printf "[+] HashValue: %x\n",$t3
$$find_hash_data
!for_each_module "
r @$t7 = @#End - @#Base;
.if($spat(\"@#ModuleName\", \"Common\") != 0)
{
.foreach(found1 {s -[1]b @#Base L@$t7 55 8b ec 53 8b 5d 10 56 57 0f b7 fb 6b ff 0c})
{
.echo ${found1}
r $t5=dwo(${found1}+0x11)
r $t6=dwo(${found1}+0x1d)
.break
}
}
"
r $t2=dwo(@$t5+0x5f334)
.printf "[+] HashValue2: %x\n",$t2
.for(r $t4=0;1==1;r $t2=dwo($t2+4))
{
.if($t2==0)
{
r $t4=0;
.break
}
.if(dwo($t2)==$t3)
{
r $t4=$t2+8
.if(dwo($t6+0x5f334)==0){.break}
as /mu ${/v:signstr} $t4;
.block
{
.if($sicmp(\"${signstr}\",\"buf32ByteValueAddedSignature\") == 0)
{
.break
}
}
}
}
.printf "[+] HashValue3: %x\n",$t4
$$find HashTable index
r $t2=wo($t1+0x22)
.printf "[+] HashTableLength: %x\n",$t2
r $t5=dwo($t1+0x28)
.for(r $t3=0;$t3<$t2;r $t3=$t3+1)
{
.if(dwo($t5)==$t4)
{
.break
}
r $t5=$t5+0x9
}
.printf "[+] TableIndex: %x\n",$t3
r $t5=dwo(dwo($t1+0x28)+$t3*9+4)
r $t6=dwo($t5-4)
.printf "[+] ClientKeyAddress: %x\n",$t5
.printf "[+] ClientKeyLength: %x\n",$t6
.printf "[+] Number:\n"
.printf "%d\n",dwo($t9+0x78)
.printf "[+] ClienKey:\n"
.for(r $t2=0;$t2<$t6;r $t2=$t2+1)
{
.printf "%02X",by($t5+$t2)
}
.printf "\n[+] Bye.\n\n"
BAT调用
@echo off
::%1 is QQ Dump filepath
call %~dp0/windbg32/cdb.exe -z %1 -c "$$><%~dp0/find_clientkey.ws"
pause