QQ聊天记录存储规则
5 l4 p( C. @, }; U+ H. E- ]
; \, a% P' T5 I6 V0 A 最近花了几天时间跟踪了一下"QQ聊天记录查看器 5.3 华军版",总算把聊天记录的存储方法弄清了。大家不要笑我,只是好奇而已,呵呵。
8 x+ p! d- L% f5 O! O1 u
' m+ o9 u2 Q/ W/ _6 _5 Z) o! ` 1.聊天记录存储方式
$ z5 x# m2 k/ i, X' _( n5 l/ k+ U6 [4 z% {
QQ聊天记录保存在MsgEx.db文件中。以前很早的版本是保存在Msg.db中,文件结构也与现在不同,我们就不分析了。
$ {7 V+ I0 E$ v0 }. @+ A, F6 q0 x! E% X$ I
MsgEx.db采用Storage结构化存储。关于Storage复合文档的知识请查阅Microsoft相关文档,我们不做赘述。 5 h( g6 h/ _' p
) @) ~* H A0 a% M1 r8 p( k
大家可以用VC自带的DocFile View工具查看该文件的内容,可以看到文件结构大致如下:
- J- J( S2 Y( v& q2 t# S# q
. H/ [# s. j- G) z: M( K7 T, c: W; z |----MsgEx.db / E- f. A5 I4 h" b' E
| |----C2CMsg
& V/ @& I1 R9 S- g# D# A& ~ | |----QQ号码
6 y) F, n5 z1 c7 w | |----Data.msj
/ i; `7 B3 S2 H1 f [5 G | |----Index.msj
& x$ d+ ~1 A* d- ]8 l9 @; P, M+ d( y | |----IMInfo
. f. @& T- {$ X b( j) }; z | |----info.dat
9 T7 U* e' [8 h. V5 L | |----Matrix 7 ` ]1 a5 r- Y* `$ J6 N; @% q
| |----Matrix.db . Q! i% [7 B' V) [4 E
| |----SysMsg : `) h8 X0 c6 }! R# }
| |----10000 + k# l0 s+ a9 C0 ?
| |----Data.msj
$ ]5 d2 I3 H, p- ~ | |----Index.msj + ^& o0 Z. c) p. V$ b0 S9 x6 g
| |----DiscMsg , p) V2 j: U _% Q( z% Z' G
| |----GroupMsg
9 Q7 z& I- d5 z7 d | |----MobileMsg
+ M& y, C ]3 Y$ L# g |---------TempSessionMsg
" T8 g# W/ Z. V9 G! L' Z5 `7 \$ J j
消息内容都存储在每个号码下面的Data.msj中,通过Index.msj索引。消息内容是经过加密处理的,必须经过解密才能看到。 & J4 d5 L l* g/ b
# l" K9 ]- [# T" y1 x6 s
QQ聊天记录解密方法
. ^; i, M N3 [9 O1 G& |
3 ^# i$ k7 G' M' U, X* `5 e 2.解密方法 6 B s7 f$ ]' ^! {/ n5 a
1 A: O, j r" s* }& V 消息内容采用BlowFish分组加密。每8个字节为一个分组。密钥Key通过QQ号码生成,具体算法稍后讨论。
" s( {- U D$ ^% w, k5 t" D0 O' M
解密方法: a.取前8个字节,通过BlowFish解密, 得到decryptKey;
0 C0 S# n0 A: ~- A2 }) @( e( z4 \( a5 w9 Y
b.decryptKey与后面8个字节XOR,对结果再进行一次BlowFish解密;
. Z! z2 n. V. T5 Q4 d
$ F" S# x3 Z( W2 w& {+ ~, W8 p c.将decryptKey与前8个字节XOR,得到第一组结果;
- \5 O' |4 D5 x) t' M; k* [2 d
6 `4 W" S; b2 ?$ |0 G d.decryptKey与后面8个字节XOR,重复b,c两步;
7 G! O: k, `" U9 [+ o. L2 h4 S2 V y& O
e.最终全部数据解密完毕。 ]! r; N3 p" o* C- c, o W3 e% s
) a( o$ a8 ~$ x3 P* t" @2 E
最后会剩下一组8字节无法解密,这个实际上是冗余数据,似乎是用来作为校验。 ( P* W" l8 C+ A0 i! _, m4 x
+ X* {% j. l+ [. x2 n) W3 p0 A
3.具体步骤
$ y4 \' L+ j% g2 x; Q+ y) ^5 P
以上解密时,BlowFish的密钥是一个全局公用密钥Key。Key要通过QQ号码生成,具体步骤是: ' S0 \2 [+ F* l( z. O
7 z* I- p, d+ f0 U$ x' b6 }% e a.将QQ号码进行MD5变换,得到Md5Key
G* Y! } X! [" c3 }
+ R5 ]& f6 A2 H" h b.取Matrix.db的数据,对其进行解码。简单说一下Matrix.db文件的结构: & a5 P2 P1 S1 a( x! G# D6 z
+ x' _1 w% i9 O/ ] Matrix.db采用分块存储,每个Record包含类型、名字长度、名字、内容长度、内容几个字段组成。用数据结构表示就是: & n5 I' n4 s7 O: |! U) V- Z' W/ ~
, M. B1 f! F" [; J7 q3 ?
struct Record{ . }1 S- |* I( p/ B4 N
5 h2 G2 w* d, H6 X' q
char rType;
8 J1 \1 e% Y+ J9 ?7 @3 l# a9 W
9 V7 B- x) j; o) z8 s short nLen;
' |# f& Z% ^4 U, J0 ~( ]& ]0 t' R! n& }. M
char Name[nLen];
6 p' ~* e( y9 K% y# S Q
% r0 w. o+ p! t4 e int rLen;
7 j8 B; K, p+ k# _) R0 t: ?* x$ { I1 P' o
char Content[rLen];
0 V7 L, M: ~" _- a7 b8 h% }& u* g8 v! {; n/ @
};
( y; ]5 m4 a# J: k( h- M' Q2 N+ y; p
初始内容也是通过加密存储的。解密方法很简单:将长度的低位字节和高位字节XOR,得到key;将内容逐个与key进行XOR,就得到结果。对名字和内容分别进行解密即可。解密后会看到STL, TIP, CRK, CPH, CAH等字段,不清楚具体的啥含义,感兴趣的同学可以自己去研究研究。我们要用到的是CRK字段,长度为32字节(如果本地聊天记录加密,可能会有变化,没试过)。将得到的CRK字段作为pData。
- C8 l( s$ L8 M) V' Z: f6 f' g
$ K$ A* b# Q7 b c.用Md5Key对pData进行BlowFish解密,得到全局密钥Key 6 O$ R, L: u& z" n& D; T
( H6 ]& c+ B* {: P$ Q3 @/ @ 4.结论
9 t" I5 G; ~' z; V$ u& B; V2 J" } V2 J! Z* h! O1 {$ |# N4 t
以上讨论的都是本地聊天记录没有加密的情况。如果选择了加密,没有密码是肯定解不出来滴,大伙就不用费心了。 |