QQ聊天记录存储规则
. Z5 I, O4 m9 U
% D* J7 t* H8 C' G y! o, H 最近花了几天时间跟踪了一下"QQ聊天记录查看器 5.3 华军版",总算把聊天记录的存储方法弄清了。大家不要笑我,只是好奇而已,呵呵。 1 ?4 J9 M! n6 S# S
" I; o7 U$ I. q 1.聊天记录存储方式
+ h8 ?3 P6 _( F [2 M
% b# S5 K$ [: R, `/ a QQ聊天记录保存在MsgEx.db文件中。以前很早的版本是保存在Msg.db中,文件结构也与现在不同,我们就不分析了。 1 b) ] W1 f% \% D; C/ u: t
& }0 G: |* M, o5 n; Y, m+ H% r5 M MsgEx.db采用Storage结构化存储。关于Storage复合文档的知识请查阅Microsoft相关文档,我们不做赘述。
6 w8 h( H2 h* H! \2 K q8 E( \! q& W0 n9 j, B
大家可以用VC自带的DocFile View工具查看该文件的内容,可以看到文件结构大致如下: 5 j( }. ]: y9 b
" a3 h6 U; w' Z" T+ {; @: j |----MsgEx.db
5 H! `) `2 P" P | |----C2CMsg
. d3 B! R% P. Y* O8 h4 G | |----QQ号码
6 U9 A* R0 U6 U5 D0 j1 X' B | |----Data.msj % Z4 c* T7 Q' Q) L6 ]
| |----Index.msj
7 P2 f$ `5 ]8 p0 [) t9 u5 E! ? | |----IMInfo / z$ s5 q% K3 c
| |----info.dat ) W$ s5 C; ?6 S! B; T& g
| |----Matrix
0 ?* S- }$ |2 g | |----Matrix.db 6 I" ] K1 B+ @) V( e) N& B
| |----SysMsg ! O+ d& Y4 Q: H: f( y9 s$ O
| |----10000 ( F; k: I' I3 O
| |----Data.msj $ n* b- i# t( I6 V9 Y; Z, ^
| |----Index.msj
6 T/ v; m+ R; z) | | |----DiscMsg
. |( Y/ a$ i! c j U5 M* Y | |----GroupMsg ( ~- P2 C: v- j- P# ]
| |----MobileMsg
# G" J- N; B! @2 n7 T4 G, ~, t8 n3 H P/ f |---------TempSessionMsg # j% j5 o0 n% F5 ~) l$ X' j+ ?
: o8 N. X' q7 [. X8 F q6 C% @
消息内容都存储在每个号码下面的Data.msj中,通过Index.msj索引。消息内容是经过加密处理的,必须经过解密才能看到。
9 v( a+ A% g. r, v3 c' q! X( [ G! T8 F! w
QQ聊天记录解密方法
& r7 O" g6 j7 b+ a: M
3 M- R6 A% O7 m2 k8 W B$ }: z 2.解密方法 1 Q2 | [( Y# u
2 L ~9 T7 F4 {; Y, ]" s4 M 消息内容采用BlowFish分组加密。每8个字节为一个分组。密钥Key通过QQ号码生成,具体算法稍后讨论。
+ u0 p' a( ]* e" s
% y( r: t- V6 [3 E$ S! y- T! l- V+ H& \ 解密方法: a.取前8个字节,通过BlowFish解密, 得到decryptKey;
! I+ g5 C) N) }7 W7 ?
9 }4 j1 G8 B( l b.decryptKey与后面8个字节XOR,对结果再进行一次BlowFish解密; ! ^( N% j) _0 y0 B7 q6 r
1 O: a" D! e! {1 a! I0 D
c.将decryptKey与前8个字节XOR,得到第一组结果; 8 x) j) r7 g; r# Y8 d K$ K8 |
# d6 j# ~) z" ~% U8 h# G
d.decryptKey与后面8个字节XOR,重复b,c两步; 4 |' z+ Y6 ~ t% L5 r$ c- t
$ B2 }% K6 v, \1 O4 a9 N3 {2 u g e.最终全部数据解密完毕。
6 r U9 z @3 W) N/ C. h4 I0 }. }0 C; Y* n6 C5 D9 r9 `% u1 J3 [
最后会剩下一组8字节无法解密,这个实际上是冗余数据,似乎是用来作为校验。 % f/ J/ e2 M! ~
; G6 ^! C* e: L, L0 P& T5 l
3.具体步骤
9 Z# j6 w8 a" |* P' e5 { k7 L9 b4 }$ q5 c
以上解密时,BlowFish的密钥是一个全局公用密钥Key。Key要通过QQ号码生成,具体步骤是: 9 m- a" F! @3 k( D( e
7 G: t( h9 s. n; a
a.将QQ号码进行MD5变换,得到Md5Key " L/ P G$ m" S- R6 M. c' f
f2 P% n/ ]7 g" F/ I b.取Matrix.db的数据,对其进行解码。简单说一下Matrix.db文件的结构: % B4 a3 R" U% {
! ~; _7 n6 [+ D: l) Q X$ k4 d Matrix.db采用分块存储,每个Record包含类型、名字长度、名字、内容长度、内容几个字段组成。用数据结构表示就是: 5 W2 o O" o1 I6 B: m6 X
) j! {0 @3 E( b, N5 {' D1 q
struct Record{
3 G+ n) G( k! Q& N" D
! r% K% B d+ A) n8 M, ? char rType; ) Q& l. b5 N, U" M6 G: }
2 j4 ?6 y( y1 z$ F short nLen;
- t; a- h& k8 ~/ Z8 B. A! D6 S- o2 S( ~ W$ q. S
char Name[nLen]; 0 R9 a% |5 e; M6 @
X8 y% N% d% B R O* V" L
int rLen; ( Y" z3 Q. O: O) G
$ D$ q2 Z5 d% X9 C# G- o. B6 _& @ char Content[rLen]; $ V4 x! @9 }/ o
& p( D$ K7 | L: [& j6 R; k) ` };
! P9 _1 c8 J: I
7 H* B% x" N- o7 P/ C& j6 ^ 初始内容也是通过加密存储的。解密方法很简单:将长度的低位字节和高位字节XOR,得到key;将内容逐个与key进行XOR,就得到结果。对名字和内容分别进行解密即可。解密后会看到STL, TIP, CRK, CPH, CAH等字段,不清楚具体的啥含义,感兴趣的同学可以自己去研究研究。我们要用到的是CRK字段,长度为32字节(如果本地聊天记录加密,可能会有变化,没试过)。将得到的CRK字段作为pData。 2 W; h2 |) s7 q
# }& ~( j# n3 M/ m0 ? c.用Md5Key对pData进行BlowFish解密,得到全局密钥Key
$ C. [9 F3 W9 _) n* y5 `
3 t2 W5 }/ X. [' h4 T F1 h4 ?0 B6 z 4.结论 7 k( Z) s% ~$ A6 E) ~
9 ?0 U6 @( A- i% {" h
以上讨论的都是本地聊天记录没有加密的情况。如果选择了加密,没有密码是肯定解不出来滴,大伙就不用费心了。 |