使用微信聊天记录统计信息
需求
在公司食堂吃饭,由于每张饭卡每月需要缴纳150管理费,所以大家为了省钱几个或十几人共用一张饭卡,以此省钱。多人公用饭卡,这就涉及到一个记账的问题。充值需要记录,每人花费多少也要记录。
一种方案是,设计信息系统,大家吃完后自行记录,B/S或APP或文件,但多少有些不方便,容易忘记,造成坏账众多。后来找到简便易行之法——利用微信群,大家吃完后发送数字即可,除了记账,大家还可以互相监督,减少坏账。期间也想过微信公众号,类似桌游助手那种思路,或者小程序肯定也可以。但开发工作量较大,所有就一直用微信群做了。
但微信群统计有一个缺点,月末统计每人的花费比较麻烦。目前只能是,聊天记录按人筛选,然后手工输入到excel统计。这显然太麻烦了,一定要想个办法。
思路
只要能导出聊天记录,就可以很简单的实现统计分析。但是偏偏微信的聊天记录好像不能导出文本或其他什么形式用于程序处理,所以此法不通。
另一种思路是读取微信PC端或移动端的本地数据库,直接统计。PC端不包含所有聊天记录,但微信移动端是会接受所以消息的,所以要拿到移动端的本地数据库,然后做一些统计即可。
实施
获取数据库文件
借助谷歌,已经有人逆向微信APP,拿到本地数据库。
详情参照知乎的回答
这里简述一下,需要root的手机,拿到/data/data/com.tencent.mm/MicroMsg/一个长串/EnMicroMsg.db
,文件为加密的,密钥为md5(IMEI+UIN)
的前7位,手机序列号IMEI通常可在设置->关于中获得,或拨号键盘*#06#。我这里为IMEI1,UIN为用户信息号,可在/data/data/com.tencent.mm/shared_prefs/system_config_prefs.xml
中获得,文件中default_uid的value即是。
解密sqlite database
微信使用了sqlcipher做得加密,看来sqlcipher常用于安卓端sqlite数据库加密。
最初原本想在PC端引入sqlcipher的包连接db文件,后来发现sqlcipher主要是用于安卓应用,没找到普通java项目可用的库,于是作罢。
又了解到sqlcipher用了AES256做得加密,刚要手写AES解密,发现JDK自带AES为128位的,如若想用,还得下载额外的包,期间还去看过sqlcipher的加密部分的源码,后来想到AES还分不同类型,这样成功的几率不高呀,于是也作罢。
解铃还须系铃人,还是用sqlchipher来解密吧,安装和命令参照了这篇和这篇,多谢分享。
安装sqlcipher
1 | apt-get install sqlcipher |
或者
1 | unzip -q sqlcipher-master.zip |
解密
使用上一步得到的密钥,如key = ‘1234567’。
1 | ./sqlcipher EnMicroMsg.db |
或者一句话直接执行
1 | sqlcipher EnMicroMsg.db 'PRAGMA key = "1234567"; PRAGMA cipher_use_hmac = off; PRAGMA kdf_iter = 4000; ATTACH DATABASE "wechat.db" AS wechat KEY "";SELECT sqlcipher_export("wechat");DETACH DATABASE wechat;' |
即可得到普通未加密的wechat.db。
其中PRAGMA cipher_use_hmac = off; PRAGMA kdf_iter = 4000;
可用PRAGMA cipher_migrate;
代替。使用后者,会改变原文件,如sqlcipher EnMicroMsg.db 'PRAGMA key = "1234567"; PRAGMA cipher_migrate; '
,执行完后可使用DB Browser for SQLite
输入密钥打开,然后菜单栏->文件->设置加密,密码为空即可清除密码。
了解数据库结构
使用Browser打开数据库文件,大致浏览了一下表结构和数据,这里主要使用三个表:
- rcontact,通讯录表
- chatroom,群聊表
- message,聊天记录表
message中每条记录即为一条聊天消息,包含着聊天对象talker
,如果为群聊,message.talker=chatroom.chatroomname,message.content中存储形式为:”群成员wxid:\n内容”。
编码
编码过程比较容易,统计聊天记录会按照正则表达式匹配,这里要求群成员,饭费消息为单独一个数值。
具体代码见
由于程序较小,为实现方便舍弃了一些编码规则,比如函数的可重入性等,这里仅供参考。