微信聊天记录分析

解密聊天记录数据库


2017年2月12日更新:微信6.5.*可能已经更改读取方式,具体还没了解。

微信6.2.5使用sqlcipher进行AES加密,因此我们要得到密钥,根据编译的信息,可以得知微信使用 key=md5(IMEI+uin) | cut -c -7 , 即取md5的前7位做为密钥。解密微信聊天数据库就是简单的一行代码,(注意sqlcipher新版本(3.x)默认不向下兼容,需要使用,cipher_use_hmac 是兼容1.1.x,kdf_iter 是兼容2.1.x的)。

IMEI很容易获取,uin在shared_prefs/多个文件中存在,如com.tencent.mm_preferences.xml,auth_info_key_prefs.xml, system_config_prefs.xml。理论上是在system_config_prefs.xml文件中的default_uin,注意有可能是负的,之前我没有意识到这个问题,导致一直解码不成功,直到看了这个博客。ps. 负数是因为溢出 int32(2639833126) = -1655134170 。

解密曾经登录过的帐号(多个用户的微信)


网上的解密聊天记录都是以登录帐号为基础的,直到我阴差阳错发现这个牛逼的微信聊天记录导出应用。重点不是在他能导出,而是他能导出之前登录过的帐号的聊天记录。仔细的思考一下,一旦有过登录,微信就会生成一个32位长的用户文件目录如 da60995c77c8cd8b47f69cc38e7a52cc ,一看就知道是个md5的hash。根据测试,在不同的机子上这个文件夹名是不变的,也就是说只跟微信ID(wx_user_name, uin…)有关,所以是跟微信哪个id是一一映射的? 感觉还是跟uin有关。

分析那个应用的包网络通信,发现他跟服务器通信只用了文件目录名如 da60995c77c8cd8b47f69cc38e7a52cc ,所以可以肯定能够通过目录名逆推uin。我尝试了不同的组合 wx_uin,wechat_uin... ,都不对。看来只能反编译。

反编译

直觉上来说,反编译微信的难度太大。还是反编译那个聊天记录导出应用好了。写应用的那哥们还是比较专业的,都做了加密和混淆,而且貌似是手动的,导致里面的字符串都难以识别。经过努力,还是破解了那哥们的加密方式,看得懂应用源码中的字符串就事半功倍,不到1小时就发现原来

TM就是前面加了”mm”。注意 uin=-1655134170 是负的。。至此,就能够逆推uin,也就是说你手机丢了,别人还是能够破解你的微信聊天记录,因为uin是int啊,找md5不要太快!所以多用户的微信当某一用户退出后能通过这种方法破解得到uin,然后破解聊天记录文件。爽歪歪。。

聊天记录整理


这方面已经很人做了,比如github上的wechat-dump,效果还是可以的,稍微有点问题,日后再改

日后改了一些东西,最重要的是微信的头像文件不再单一保存,而是用 avatar.index 来索引,保存在一个大文件中avatar.block.0000x。经测试,可以得知用户头像以avatar.index中的数值为起始位置,找到avatar.block.0000x相应连续的96×96×3×4个连续字节就算用户头像的bitmap(png.bm)。具体见代码

 

 

国庆期间,别人在玩,我在写代码。这波不亏

 

参考


26 thoughts to “微信聊天记录分析”

      1. ios应该有戏,但要获得root权限。对应越狱?我没有用过ios,不是很清楚。但原理是一样的。

  1. 最新微信版本6.5.4使用android-database-sqlcipher(链接:https://github.com/sqlcipher/android-database-sqlcipher。gradle:compile ‘net.zetetic:android-database-sqlcipher:3.5.5@aar’)解密会报这个错:attempt to write a readonly database: , while compiling: select count(*) from sqlite_master;

    而微信6.3.x可以正常读取数据。我是按照这个博客的代码进行读取的:http://blog.csdn.net/yuanbohx/article/details/41674949。

    现在我完全没有头绪了,楼主能帮我看看是怎么回事吗

    1. 我建议先把 微信 那个EnMicroMsg.db复制到外面(可写文件目录,如sdcard),然后使用sqlcipher读取试试。不行的话再复制到电脑上试试。我觉得有可能加密方式变了。

      1. 但是有个问题是我需要每隔10秒读一次,所以拷出来不是很可行。
        您觉得这个地方是不是有可以改进的地方:
        mHook = new SQLiteDatabaseHook() {
        public void preKey(SQLiteDatabase database) {
        }

        public void postKey(SQLiteDatabase database) {
        database.rawExecSQL(“PRAGMA cipher_migrate;”); //最关键的一句!!!
        }
        };

          1. 外面能用这个脚本解密:
            # 解密数据库
            def decodeDb():
            print(“– decodeDb”)
            conn = sqlite.connect(“tmp” + “/EnMicroMsg.db”)
            c = conn.cursor()
            c.execute(“PRAGMA key = ‘” + password + “‘;”)
            c.execute(“PRAGMA cipher_use_hmac = OFF;”)
            c.execute(“PRAGMA cipher_page_size = 1024;”)
            c.execute(“PRAGMA kdf_iter = 4000;”)
            c.execute(“ATTACH DATABASE ‘tmp/decrypted” + “.db’ AS db KEY ”;”)
            c.execute(“SELECT sqlcipher_export(‘db’);” )
            c.execute(“DETACH DATABASE db;” )
            c.close()

            用的是Python的from pysqlcipher import dbapi2 as sqlite这个模块。

          2. 感觉没问题,https://github.com/sqlcipher/android-database-sqlcipher/issues/161
            这里也有讨论,我猜测几个原因:
            1. 好像跟设备也有关系。你是小米系列的5.0.x?
            2. 有时候这个数据库会变成EnMicroMsg.db2,数据库确实存在吧?路径能看一下吗(/data/data/com.tencent.mm/…)这样子的?
            3. 或者微信对数据库加了锁?我也不清楚什么原因

          3. 手机不是小米系列,数据库应该是存在的。估计是微信对数据库加了锁。我再研究研究。
            有一个比较奇怪的问题是如果我从6.3.30升级到6.5.4则可以使用原来的方式。如果直接安装6.5.4就不能。估计就是微信换了加密方式吧。估计!

          4. 估计是微信换了加密方式,之前我看到我那个文件夹中有EnMicroMsg.db2和EnMicroMsg.db这两个文件。EnMicroMsg.db是升级前的,EnMicroMsg.db2是升级之后的。如果你解决了麻烦通知我一下,多谢!

          5. 哎,我发现只要把EnMicroMsg.db拷贝到/sdcard/目录就能正常读取了。具体原因不明。。。。暂时的解决方案是定时拷贝吧!

          6. 我也遇到不拷贝不行的问题了,问一下有没有解决
            我试过了修改数据库和目录的权限为777,java这边还是访问不到
            我是把定时拷贝换成了微信收到消息再拷贝解析,这样稍微好点

          7. @SwordYork:disqus @disqus_OqswM6AwHD:disqus 好像是存在一个journal文件,是数据备份还是什么的我查到,只要把这个文件改名或者删除就可以直接用java读取数据库了。

          8. 那个是事务回滚文件,我这里没有,我已经解决了
            创建硬链接到自己的app数据库目录下,改权限606就直接可以读取了

发表评论

电子邮件地址不会被公开。 必填项已用*标注