start
这篇内容完全是意外啊,起因是酱紫的
某日看见一个Mac的app打折大礼包(bundle)买了以后里面有个神奇的iPxx设备管理的app,叫iMazing,然后用iMazing尝试了下,发现居然可以看app里面的数据,然后出于手闲好奇的心里-,-我就点开了大TX的扣扣看了一眼,于是就产生了下面的一系列意外发现
iMazing长下面酱紫,用起来赶脚还是很不错的啊,于是我顺手点开了扣扣,出于学习的目的,研究了一下
发现iMazing很强力啊,把整个app和数据都dump出来了,以及这次我们要讲的主角,消息记录,嘛大企鹅的消息记录在别的平台上似乎都是加密过的,iOS上却没有加密,这让人有点意外,不过估计也比较相信水果公司的沙盒是很安全的吧,不过这也给我们点机会一窥企鹅里面到底是啥样的。
另外本文完全自我yy的,水平有限写的不好的地方大家拍砖即可
找找主角在哪里
我们来找找主角在哪里,下面图是企鹅的document路径下的东西,从名字来看,分了好多东西,也承载了企鹅很多的功能,比如看到Weiyun,看到Video了(*゜∀゜)
上面打上马赛克的,是QQ号为路径的两个目录,大家肯定都以为我们的主角就在里面了,哈哈哈,其实大意了,打开里面是这样的
外面的QQ号的路径里面其实是头像啊,用户信息啊,图片啊,视频啊之类的东西,并不是我们期待的聊天记录,我之前也被骗了,还以为大企鹅已经加密了用户的QQ聊天记录了,后来手闲点开来看一看,发现,哎呀原来在这里啊。
上面的图就是我的一个帐号下面的所有的文件了,一眼看到,QQ.db,这个必须是主角了,接下来我们就把它拆开来看看,里面都有些啥东西呢。
拆解QQ.db
一瞥
用sqlite打开qq.db这个文件以后,发现没有加密,也就是说我们的所有聊天记录,都是明文存放在手机里面的,这里再次体会到了不越狱的重要性。接下来我们一步一步的来看看,首先.tables
看下,有一些什么样的数据表呢
上面的图就是所有的数据表了,里面所有号码都被我打上了码,不过大家都懂得,上面的码就是我们平时使用的群号码,qq号码了,以及这次的新发现,讨论组号码,另外,截图在我升级新的QQ之前截得,那么新加的表,就懒得截图了-_,-不过会在下面描述滴,以及,找到了个好看的free工具了,哈哈,可以更方便了
从上面的图片来看,大概可以把数据表分为下面几类:
注意:在花括号中的内容是根据内容可变的
- 数据库文件本身的信息
- tb_dbVersion:数据表的版本,目测每个表有一个tableSign,对应到一个版本,tx很变态-,-数据的版本是记录在表上的
- 文件相关的
- tb_File:保存用户收到和发送的文件列表
- 用户聊天(tb_c2cMsg开头)
- tb_c2cTables:跟QQ用户聊天的表
- tb_recentC2CMsg:最近的用户消息
- tb_c2cMsg_{QQ号}:跟某个QQ用户聊天的聊天记录
- 讨论组(tb_discuss开头的)
- tb_discuss_recent:最近的讨论组聊天记录
- tb_discussMaxSeq:讨论组消息序列
- tb_discussGrp_{讨论组ID}:某个讨论组的聊天记录
- 群组相关的(tb_Troop开头)
- tb_TroopAnnouncement:群通知信息
- tb_TroopMem:目前不知道是用来干啥的,也没看到数据,看字段像是保存群和群成员的表,但是几次实验都没有数据,感觉很奇怪
- tb_Troop:群列表
- tb_TroopRemark:用户在不同群的群名称
- tb_Troop_recent:最近的群聊天记录
- tb_TroopMsgSeq:群的消息序列
- tb_TroopMsg_{群号}:某个群的聊天记录
- QQ悄悄话(tb_Sec开头)
- tb_SecSession:会话列表
- tb_SecMsg_{tb_SecSession表中的sessionId}:悄悄话消息记录
- 目前未知的
- tb_eimUserSummary:某种用户信息
- tb_userSummary:某种用户信息
上面就是目前看见到的,所有类型的表,大家似乎觉得没看到用户列表,用户列表根据文件名看,应该是在同级目录下的一个plist文件里面保存着了
第一部分总结一下,QQ为了每个独立的聊天记录处理方便吧,将所有的聊天记录分成了不同的表,每个用户,每个群,每个讨论组都有一个表
聊天记录表
其实真正的主角在这里,我们的聊天记录表,因为QQ就是即时通讯软件,而及时通讯软件的核心就是聊天,那么知道聊天记录里面有些啥,那就知道在处理不同类型消息的时候,通过QQ的聊天记录表,我们可以从中窥得一些QQ在设计数据存储时的取舍和思想,对于聊天记录,这里主要关注如何处理多重类型的消息的
- 普通的文本聊天
就和我们看见的那样,直接使用聊天文本,对于QQ原生的表情,那跟通过文本看表情一样是使用\表情名称
插入到文本中的。
- 有图片的
目前看到的是通过<img>图片</img>
作为图片名字插入到消息中,之后在一个叫做picUrl的字段里面放入对应图片名字的描述,以及url,具体看图
对于我收到的图片,可以看到图片的链接
可以看得到,对于我发送的图片,并不保存连接的地址,而是直接保存了本地文件的位置,对于我收到的图片,那么连接会保存两个,一个是缩略图的,一个是原图的连接,并且仔细看的话两个连接只是第一个参数不一样,目测第一个参数应该是用来决定图片的大小的,现在看到的是198,之后,我在Documents/QQ号/image_thumbnail
路径下找了几个图片看了一下,发现宽高都是在198以内,那么可以知道QQ使用的缩略图的大小是在198以内的图片,如果过长或者过宽,那么等比例缩放。
- 声音的
声音的文件,我们从聊天数据里面来看,发现很有意思的是,文件的信息也是用过picUrl
这个字段来记录的,看图
之后在Document/QQ号/Audio
路径下能够找到这个声音文件
- 系统消息
系统消息类型的,每个系统消息都有一个单独的QQ号,比如兴趣部落这个QQ消息,也是有QQ号的,并且和普通的联系人一样有一个单独的tb_c2cMsg
开头的表保存着。
下面是一部分的内容:
<?xml version="1.0" encoding="utf-8"?>
<msg>
<appmsg>
<item>
<cover>http://s.p.qq.com/pub/jump?d=rRv3zzfe</cover>
<digest></digest>
<title>[自拍] 秀自己的自拍姿势啦,不会的进来涨姿势哦!</title>
<url>http://s.p.qq.com/pub/jump?_wv=1027&d=RZbMzFie&st=2&pt=1</url>
</item>
<item>
<cover>http://s.p.qq.com/pub/jump?d=Y3fEAqZf</cover>
<title>[90后] 你敢在这里写下你的初吻吗?</title>
<url>http://s.p.qq.com/pub/jump?_wv=1027&d=AYrfiqVZ&st=2&pt=1</url>
</item>
<item>
<cover>http://s.p.qq.com/pub/jump?d=unmeMvjU</cover>
<title>[80后] 【就爱滚床单】你的睡姿如何?</title>
<url>http://s.p.qq.com/pub/jump?_wv=1027&d=BQVna2nU&st=2&pt=1</url>
</item>
<item>
<cover>http://s.p.qq.com/pub/jump?d=7q3vrfqZ</cover>
<title>[爱情] 说说暗恋一个人最心酸的事是什么?</title>
<url>http://s.p.qq.com/pub/jump?_wv=1027&d=qz3rRnAa&st=2&pt=1</url>
</item>
</appmsg>
<meta>
<time>1414602851</time>
</meta>
</msg>
我们来看看对应的消息截图是这样的:
可以看到QQ的系统消息提供的数据是一个xml,里面用cover标记这个消息的标题以及背景,用item标签标记下面每个子项目,每一个item也有自己的title,cover,url这些属性,用来显示标题,封面,还有点击后跳转的连接。
关于表情的更新
在聊天记录中,忽略了一个事情是表情,本来按照我的想象,表情只是纯文字类似/呵呵
这样就能显示表情,但是发现,自己输入到qq的/呵呵
却没办法正确的显示表情,于是猜测了下,可能QQ用到了隐藏的字符,作为表情的标记,于是做了下面的实验,把表情复制到了自己的app中,打印一下看看
发现果然是这样的,前面多了一个\x14
的字符,在看数据库中的记录,因为历史纪录肯定是能显示的,那么数据库中肯定也能查的到
果然在数据库中也有这样的数据,第一个字符是unicode为20也就是x14(十六进制)的字符,去unicode对照表看看,似乎只是一个无关的控制字符,猜想应该是一个占位符,用来标记哪些是用户选择的表情,哪些是用户手工输入的文字,这样用户就不能通过直接编辑框输入/呵呵
来发送表情了。