QQ聊天记录存储规则
8 g" s- w$ @0 [4 @/ w+ l; r
- a3 s8 C3 r$ u6 |' H. x( U' C 最近花了几天时间跟踪了一下"QQ聊天记录查看器 5.3 华军版",总算把聊天记录的存储方法弄清了。大家不要笑我,只是好奇而已,呵呵。
; s. E7 V) r) \( c3 u: ?) W, i$ E0 R
1.聊天记录存储方式 : p+ i. ?3 H; ?1 n
3 m8 F) d! X9 u3 ~ QQ聊天记录保存在MsgEx.db文件中。以前很早的版本是保存在Msg.db中,文件结构也与现在不同,我们就不分析了。 & u* P2 Y" |1 Z; d4 S
3 g' {$ u% R% i MsgEx.db采用Storage结构化存储。关于Storage复合文档的知识请查阅Microsoft相关文档,我们不做赘述。
+ A5 E; p0 m9 C
- C% ?' Y$ }5 \3 G3 X) G 大家可以用VC自带的DocFile View工具查看该文件的内容,可以看到文件结构大致如下: ' Z4 }7 z! g, I3 u
* c$ p Q+ i% T" K6 K4 t w4 `2 j- L7 l8 j
|----MsgEx.db
+ Q B. n N; \/ K4 y: z: U1 O | |----C2CMsg ! q1 e& j; W6 Y
| |----QQ号码
5 b1 j1 w1 z+ m: E% ` | |----Data.msj
7 F6 q5 {% I9 B1 r, x2 I | |----Index.msj
6 h( n4 l' L( N: \" i; C8 }; O* [ | |----IMInfo : `5 Y4 c4 h7 f
| |----info.dat % z) @4 A( m7 P+ B
| |----Matrix ; Y5 t- E& D8 K2 q- p& c; Y
| |----Matrix.db
8 P8 ]' v. h6 b L, r2 N7 p | |----SysMsg & X$ y. `% a4 s' k7 {
| |----10000
5 C) S5 C: i, k | |----Data.msj
) e1 v% r* ~/ n" n$ Y | |----Index.msj
% D. ? T0 L+ Z( m9 g O+ ?" O | |----DiscMsg # l* t8 I: G3 k; _3 M
| |----GroupMsg * O, c8 L4 |( s" ]; ?0 p8 ]
| |----MobileMsg
4 j' F+ k; v {: r* r# p$ {7 p |---------TempSessionMsg ' A* U e7 R1 l
! o: ]" k$ u- y$ K! J4 Q; d1 q 消息内容都存储在每个号码下面的Data.msj中,通过Index.msj索引。消息内容是经过加密处理的,必须经过解密才能看到。 ; }2 Z' c( V' c6 t" h& G9 I
& y1 ?3 C# u% \* J* R, h q( U
QQ聊天记录解密方法
; I: l& ?, U! p0 `9 k. F" c5 r9 f& v6 g/ X: Z J
2.解密方法
; B( j$ q; \ H) N! z. O) d, n$ ?) s4 f) m; l
消息内容采用BlowFish分组加密。每8个字节为一个分组。密钥Key通过QQ号码生成,具体算法稍后讨论。
; ]9 I( s3 v9 `; j3 [& ]7 ^& ]' _# s0 u \3 S
解密方法: a.取前8个字节,通过BlowFish解密, 得到decryptKey;
, b" G7 g0 `8 \* T8 i4 r0 r
5 W/ V+ Z1 y" n8 N7 q b.decryptKey与后面8个字节XOR,对结果再进行一次BlowFish解密; ) ]% Z6 I1 u! a. |( P# B, Q8 x, V
3 }* v# p( c* d2 `/ ?* U9 c& [ c.将decryptKey与前8个字节XOR,得到第一组结果; 8 _# m; D$ p. C* v
2 ]# W0 d( s1 {( J+ [/ j
d.decryptKey与后面8个字节XOR,重复b,c两步; 4 E9 @8 u! O, l+ V) l. A
3 t; {: p( D- K+ |1 b: _- g1 U
e.最终全部数据解密完毕。 8 P1 q) I3 I4 ^- X
5 l2 Z# [0 Y3 }" S
最后会剩下一组8字节无法解密,这个实际上是冗余数据,似乎是用来作为校验。
: Z- R9 c& T( J+ \" @: M3 s# X7 U2 F: K
3.具体步骤 " Y4 w Y6 e: _ C8 G' v
' n5 a; c8 `# A1 i `( J 以上解密时,BlowFish的密钥是一个全局公用密钥Key。Key要通过QQ号码生成,具体步骤是:
+ J& @! B) M$ S) a" h }3 R6 t
+ E$ \( c- q8 J% _) e$ v' @ a.将QQ号码进行MD5变换,得到Md5Key
- j$ J% d, h, O- I s+ z# B+ x$ D2 i6 r3 }2 r5 w" z
b.取Matrix.db的数据,对其进行解码。简单说一下Matrix.db文件的结构: . o3 N( a/ s+ Y7 ~; I2 L
7 N6 v3 _% W X7 k
Matrix.db采用分块存储,每个Record包含类型、名字长度、名字、内容长度、内容几个字段组成。用数据结构表示就是:
* w" G: c8 Z }) N" A0 j+ C
6 D8 _: z5 U' `: t3 |8 v1 g8 l" K# l struct Record{ ! H, k( v- @0 V q7 F" @
* F7 \2 C0 o( l2 U' R" w
char rType;
0 x6 `9 ?: k: P; @+ m* `9 d3 m0 M7 j! @5 z
short nLen; . Y% H) p: L" r7 l* p5 x' j
8 s5 [/ C! i; E4 a& E* m& P
char Name[nLen]; 1 e# U8 \/ C4 ?; {/ e$ Y2 f
7 N k0 B8 b# Q* P
int rLen; ! ?, M5 d1 r/ f* }1 d% w
9 i/ D% `) K0 T1 q) Q" | char Content[rLen];
& H& L& } v ]0 H2 x$ t1 v& k" u3 w% x. {+ W; d: s, w
};
5 v) x& n' T# q7 \! F& F( V# }0 }* B* i+ R
初始内容也是通过加密存储的。解密方法很简单:将长度的低位字节和高位字节XOR,得到key;将内容逐个与key进行XOR,就得到结果。对名字和内容分别进行解密即可。解密后会看到STL, TIP, CRK, CPH, CAH等字段,不清楚具体的啥含义,感兴趣的同学可以自己去研究研究。我们要用到的是CRK字段,长度为32字节(如果本地聊天记录加密,可能会有变化,没试过)。将得到的CRK字段作为pData。 6 L' N' \( p+ H7 Q2 `
/ b! I* M! B( A# T* y9 M P; U
c.用Md5Key对pData进行BlowFish解密,得到全局密钥Key
: D3 e! q2 S$ X* Y" D0 X6 \- j @4 Z5 f
4.结论
6 z" y# @6 e7 `: Q" Y; a) r# t; c+ \6 Y/ l' u" k; \% A) ^
以上讨论的都是本地聊天记录没有加密的情况。如果选择了加密,没有密码是肯定解不出来滴,大伙就不用费心了。 |