QQ聊天记录存储规则
+ W6 j8 O9 R- R! ^6 |
+ @6 ^* k. e% H5 L8 d) s+ J& | 最近花了几天时间跟踪了一下"QQ聊天记录查看器 5.3 华军版",总算把聊天记录的存储方法弄清了。大家不要笑我,只是好奇而已,呵呵。
' t% Z Q; Q) k8 f
5 V4 K1 s0 b3 D& Y& m 1.聊天记录存储方式
) x4 \7 i! ]& j+ P# y5 E8 g2 n! W; {
QQ聊天记录保存在MsgEx.db文件中。以前很早的版本是保存在Msg.db中,文件结构也与现在不同,我们就不分析了。
9 P9 ]7 P0 ?# `; A! R" M2 W/ E. ?9 i5 V7 o
MsgEx.db采用Storage结构化存储。关于Storage复合文档的知识请查阅Microsoft相关文档,我们不做赘述。
6 v: a; \; E& ?# _/ ?) o
- |% G2 a. Q& h/ A 大家可以用VC自带的DocFile View工具查看该文件的内容,可以看到文件结构大致如下:
6 }4 i, f4 ~7 W0 t
# o+ x9 ^, u+ Z( u |----MsgEx.db
$ v \% f" S+ B | |----C2CMsg 3 c; r) v8 X! E6 G4 U$ R9 b2 z
| |----QQ号码 ' W3 W% Q$ `+ l0 `( g2 j
| |----Data.msj
- y# b% i) L4 y `& D/ e | |----Index.msj , Y1 n8 y. r+ F t# q$ a; j+ V
| |----IMInfo + i& ?; @' w+ B- a$ S3 @# U
| |----info.dat * O1 E/ q5 H6 D* C C
| |----Matrix ' E9 T# v/ e5 Y0 K5 c4 f
| |----Matrix.db
# t5 _/ ^3 j: K/ w' a% C G' p | |----SysMsg
8 n8 G( [* \! Y5 |3 ^" {; V | |----10000 7 L: i( G$ m' K
| |----Data.msj
7 S# j, H, l; f' f. ~" [' g | |----Index.msj 5 a0 p- L) z/ q e' O% {
| |----DiscMsg & J* C A+ t1 d1 ?( I, `1 n5 f) l
| |----GroupMsg * a( c3 D. e) D* P# F1 F
| |----MobileMsg
" O0 z" V5 X5 J/ |3 L |---------TempSessionMsg
) {( [5 {( t M/ m8 F8 ]' F: m
' |8 d0 p- g4 D# G 消息内容都存储在每个号码下面的Data.msj中,通过Index.msj索引。消息内容是经过加密处理的,必须经过解密才能看到。 & o4 K+ h. D* y3 H/ `* s7 G4 v
; G) `! C7 j8 }4 C QQ聊天记录解密方法 - `, i3 U w# j) v
0 u/ a [- I G& e0 x6 @ 2.解密方法 - v! W* ^6 O1 q! B$ T, w
# Y- _% j) I& e) [* q; t
消息内容采用BlowFish分组加密。每8个字节为一个分组。密钥Key通过QQ号码生成,具体算法稍后讨论。 / P" n9 ^/ D! C. Y: z0 l; G) ?
- m8 ~& a2 E( D 解密方法: a.取前8个字节,通过BlowFish解密, 得到decryptKey; ' c5 }8 `+ v% V; E o6 T
D4 Z- D# m2 b4 I! K b.decryptKey与后面8个字节XOR,对结果再进行一次BlowFish解密;
" e4 u- k# a: u; h+ k, c/ L; ?: C# s& b1 {, z9 Z& \
c.将decryptKey与前8个字节XOR,得到第一组结果; ; t' D" U) R; Q2 u
) v( L$ X! _+ E2 T* y( U
d.decryptKey与后面8个字节XOR,重复b,c两步; & l* Q" O) C R" j0 T7 \7 D- g; V
- z& R/ w: ?7 L& O
e.最终全部数据解密完毕。 & _( U S- H5 Q7 {# S
/ t8 n7 b9 z& D$ Z
最后会剩下一组8字节无法解密,这个实际上是冗余数据,似乎是用来作为校验。 ]. z; T0 p3 @$ ~: W- D5 s
$ Y+ v7 P q3 F$ N 3.具体步骤
; `! H1 c$ Y) ] t# \$ J+ q6 r% Q, \- y
以上解密时,BlowFish的密钥是一个全局公用密钥Key。Key要通过QQ号码生成,具体步骤是: # G" ?# Q9 a% n2 ~
' s" c- X. o1 Q0 x- g a.将QQ号码进行MD5变换,得到Md5Key 5 w1 D4 A- T+ Y) P! f/ _
% z/ s. X4 [1 w$ E7 A2 m, ^ b.取Matrix.db的数据,对其进行解码。简单说一下Matrix.db文件的结构: 3 l, w# n& v- n* T- U* E
# @% R/ k* {3 Q% U& {! P- Z$ Y Matrix.db采用分块存储,每个Record包含类型、名字长度、名字、内容长度、内容几个字段组成。用数据结构表示就是: * b4 d, C1 j: ~6 U
! }# i* `3 p% l4 g0 @8 Z6 p struct Record{ 7 G- ~* U: o* \/ ]/ x! Y, H7 J
! G& x8 t* B9 x8 Z* M
char rType;
1 |) l Y/ X1 ]3 J! Y4 X2 W$ }+ |9 s' T- _8 h/ v" w: J
short nLen; ' B7 C9 l8 e1 r+ J
" ? H/ K+ [& o
char Name[nLen];
! ~% F$ w( k$ ?9 h3 _ }/ e' j/ r+ s6 g1 e/ \/ w& }
int rLen;
8 d, e# {- p6 X/ Q" b+ n
% x+ \ j5 @$ N9 V, [& N: C char Content[rLen]; ( f Z2 V: i( d
. m2 t2 o A' a* d2 [: } };
. K9 m6 k f m( ?. h- M8 g. l1 l% K
+ u; I2 g9 ^. v4 U: r 初始内容也是通过加密存储的。解密方法很简单:将长度的低位字节和高位字节XOR,得到key;将内容逐个与key进行XOR,就得到结果。对名字和内容分别进行解密即可。解密后会看到STL, TIP, CRK, CPH, CAH等字段,不清楚具体的啥含义,感兴趣的同学可以自己去研究研究。我们要用到的是CRK字段,长度为32字节(如果本地聊天记录加密,可能会有变化,没试过)。将得到的CRK字段作为pData。
) |3 Q2 q! {' c. C0 @5 g. s6 }! \- W+ u7 H
c.用Md5Key对pData进行BlowFish解密,得到全局密钥Key ; ?/ k/ h0 Q, s* K
3 n2 o$ K: O, {& _) q1 v
4.结论
$ w$ ^( U# k3 W7 l% o$ x$ l1 ~0 y$ G6 {7 b3 C% @
以上讨论的都是本地聊天记录没有加密的情况。如果选择了加密,没有密码是肯定解不出来滴,大伙就不用费心了。 |