commit a77147a3d38a416bd8d4ef38601409000810488b Author: ppwwyyxx Date: Fri Nov 21 13:09:01 2014 +0800 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c290a7 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +## Dump Wechat Messages from Android diff --git a/decrypt_db.sh b/decrypt_db.sh new file mode 100755 index 0000000..521dd26 --- /dev/null +++ b/decrypt_db.sh @@ -0,0 +1,23 @@ +#!/bin/bash -e +# File: decrypt_db.sh +# Date: Fri Nov 21 13:07:33 2014 +0800 +# Author: Yuxin Wu + +MMSGDB=$1 +imei=$2 +uin=$3 + +if [[ -z "$1" || -z "$2" || -z "$3" ]]; then + echo "Usage: $0 " + exit +fi + +KEY=$(echo -n "$imei$uin" | md5sum | cut -b 1-7) + +LD_LIBRARY_PATH=./lib ./lib/sqlcipher $MMSGDB << EOF +PRAGMA key='$KEY'; +PRAGMA cipher_use_hmac = off; +ATTACH DATABASE "decrypted_database.db" AS decrypted_database KEY ""; +SELECT sqlcipher_export("decrypted_database"); +DETACH DATABASE decrypted_database; +EOF diff --git a/dump.py b/dump.py new file mode 100755 index 0000000..bf35ddc --- /dev/null +++ b/dump.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python2 +# -*- coding: UTF-8 -*- +# File: dump.py +# Date: Fri Nov 21 13:07:58 2014 +0800 +# Author: Yuxin Wu + +import sqlite3 +from collections import defaultdict +from pprint import PrettyPrinter +pp = PrettyPrinter() +def log(x): print repr(x).decode('unicode-escape') +from lib.Msg import WeChatMsg + +""" tables in concern: +emojiinfo +imginfo2 +addr_upload2 +chatroom +message +rcontact + +""" + +class WeChatDBParser(object): + def __init__(self, db_fname): + """ db_fname: EnMicroMsg.db""" + self.db_fname = db_fname + self.db_conn = sqlite3.connect(self.db_fname) + self.cc = self.db_conn.cursor() + self.contacts = {} + + def _parse_contact(self): + contacts = self.cc.execute( +""" +SELECT username,conRemark,nickname +FROM rcontact +""") + for row in contacts: + username, remark, nickname = row + if remark: + self.contacts[username] = remark + else: + self.contacts[username] = nickname + + def _parse_msg(self): + msgs_by_talker = defaultdict(list) + db_msgs = self.cc.execute( +""" +SELECT {} +FROM message ORDER BY createTime +""".format(','.join(WeChatMsg.FIELDS))) + for row in db_msgs: + msg = WeChatMsg(row) + msgs_by_talker[msg.talker].append(msg) + msgs_by_talker = dict([ + (self.contacts[k], sorted(v, key=lambda x: x.createTime)) + for k, v in msgs_by_talker.iteritems()]) + for k, v in msgs_by_talker.iteritems(): + for msg in v: + msg.talker = k + pp.pprint(msgs_by_talker.items()[0]) + + def parse(self): + self._parse_contact() + msg = self._parse_msg() + pass + +if __name__ == '__main__': + parser = WeChatDBParser('./decrypted_database.db') + parser.parse() diff --git a/lib/Msg.py b/lib/Msg.py new file mode 100644 index 0000000..40c3714 --- /dev/null +++ b/lib/Msg.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python2 +# -*- coding: UTF-8 -*- +# File: Msg.py +# Date: Fri Nov 21 12:15:27 2014 +0800 +# Author: Yuxin Wu + +from datetime import datetime + +class WeChatMsg(object): + """ fields in concern""" + FIELDS = ["msgSvrId","type","isSend","createTime","talker","content","imgPath"] + + def __init__(self, row): + """ row: a tuple corresponding to FIELDS""" + assert len(row) == len(WeChatMsg.FIELDS) + for f, v in zip(WeChatMsg.FIELDS, row): + setattr(self, f, v) + self.createTime = datetime.fromtimestamp(self.createTime / 1000) + if self.content: + self.content = self.content.encode('utf-8') + + def __repr__(self): + return "{}:{}:{}".format(self.talker.encode('utf-8') if not self.isSend else 'me', self.createTime, self.content) diff --git a/lib/libsqlcipher.so.0 b/lib/libsqlcipher.so.0 new file mode 100644 index 0000000..04ccce3 Binary files /dev/null and b/lib/libsqlcipher.so.0 differ diff --git a/lib/sqlcipher b/lib/sqlcipher new file mode 100755 index 0000000..4f3b3d4 Binary files /dev/null and b/lib/sqlcipher differ