diff --git a/android-interact.sh b/android-interact.sh new file mode 100755 index 0000000..4704c55 --- /dev/null +++ b/android-interact.sh @@ -0,0 +1,70 @@ +#!/bin/bash -e +# File: android-interact.sh +# Date: Thu Dec 25 00:25:07 2014 +0800 +# Author: Yuxin Wu + +# Please check that your path is the same, since this might be differnt on devices +RES_DIR="/mnt/sdcard/tencent/MicroMsg" +MM_DIR="/data/data/com.tencent.mm" + +echo "Starting rooted adb server..." +adb root + +if [[ $1 == "uin" ]]; then + adb pull $MM_DIR/shared_prefs/system_config_prefs.xml 2>/dev/null + uin=$(grep 'default_uin' system_config_prefs.xml | grep -o 'value="[0-9]*' | cut -c 8-) + [[ -n $uin ]] || { + echo "Failed to get wechat uin. You can try other methods, or report a bug." + exit 1 + } + rm system_config_prefs.xml + echo "Got wechat uin: $uin" +elif [[ $1 == "imei" ]]; then + imei=$(adb shell dumpsys iphonesubinfo | grep 'Device ID' | grep -o '[0-9]*') + [[ -n $imei ]] || { + echo "Failed to get imei. You can try other methods, or report a bug." + exit 1 + } + echo "Got imei: $imei" +elif [[ $1 == "db" || $1 == "res" ]]; then + echo "Looking for user dir name..." + userList=$(adb ls $RES_DIR | cut -f 4 -d ' ' \ + | awk '{if (length() == 32) print}') + numUser=$(echo $userList | wc -l) + # choose the first user. + chooseUser=$(echo $userList | head -n1) + [[ -n $chooseUser ]] || { + echo "Could not find user. Please check whether your resource dir is $RES_DIR" + exit 1 + } + echo "Found $numUser user(s). User chosen: $chooseUser" + + if [[ $1 == "res" ]]; then + echo "Pulling resources... this might take a long time..." + mkdir resource + cd resource + adb pull $RES_DIR/$chooseUser/image2 + adb pull $RES_DIR/$chooseUser/voice2 + adb pull $RES_DIR/$chooseUser/emoji + adb pull $RES_DIR/$chooseUser/avatar + [[ -d image2 && -d voice2 && -d emoji && -d avatar ]] && { + echo "Resource pulled." + echo "Total size: $(du -sh $chooseUser | cut -f1)" + } || { + echo "Failed to download resource directory: $RES_DIR/$chooseUser" + exit 1 + } + else + echo "Pulling database file..." + adb pull $MM_DIR/MicroMsg/$chooseUser/EnMicroMsg.db + [[ -f EnMicroMsg.db ]] && \ + echo "File successfully downloaded to EnMicroMsg.db" || { + echo "Failed to pull database from adb" + exit 1 + } + fi +else + echo "Usage: $0 " + exit 1 +fi + diff --git a/decrypt_db.sh b/decrypt_db.sh index 10cbe50..6b27b0e 100755 --- a/decrypt_db.sh +++ b/decrypt_db.sh @@ -1,6 +1,6 @@ #!/bin/bash -e # File: decrypt_db.sh -# Date: Sun Nov 23 16:46:51 2014 +0800 +# Date: Thu Dec 25 00:30:10 2014 +0800 # Author: Yuxin Wu MMSGDB=$1 @@ -13,11 +13,13 @@ if [[ -z "$1" || -z "$2" || -z "$3" ]]; then fi KEY=$(echo -n "$imei$uin" | md5sum | cut -b 1-7) +echo "KEY: $KEY" -LD_LIBRARY_PATH=./lib ./lib/sqlcipher $MMSGDB << EOF +export LD_LIBRARY_PATH=./lib +./lib/sqlcipher $MMSGDB << EOF PRAGMA key='$KEY'; PRAGMA cipher_use_hmac = off; -ATTACH DATABASE "decoded_database.db" AS decoded_database KEY ""; +ATTACH DATABASE "decoded_database.db" AS decoded_db KEY ""; SELECT sqlcipher_export("decoded_db"); -DETACH DATABASE decoded_database; +DETACH DATABASE decoded_db; EOF diff --git a/lib/msg.py b/lib/msg.py index 475093a..c37b69d 100644 --- a/lib/msg.py +++ b/lib/msg.py @@ -1,11 +1,13 @@ #!/usr/bin/env python2 # -*- coding: UTF-8 -*- # File: msg.py -# Date: Wed Dec 24 22:00:42 2014 +0800 +# Date: Thu Dec 25 09:56:24 2014 +0800 # Author: Yuxin Wu +import re from datetime import datetime from pyquery import PyQuery + from .utils import ensure_bin_str, ensure_unicode TYPE_MSG = 1 @@ -66,7 +68,14 @@ class WeChatMsg(object): elif self.type == TYPE_VIDEO: return "VIDEO FILE" elif self.type == TYPE_NAMECARD: - pq = PyQuery(self.content) + try: + pq = PyQuery(self.content) + except ValueError: + # pq doesn't support xml + pat = re.compile('', re.DOTALL) + msg = pat.search(self.content).group() + pq = PyQuery(msg) + msg = pq('msg').attr name = msg['nickname'] if not name: diff --git a/lib/parser.py b/lib/parser.py index 4a0641c..d5ac7e1 100644 --- a/lib/parser.py +++ b/lib/parser.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2 # -*- coding: UTF-8 -*- # File: parser.py -# Date: Mon Dec 22 22:14:18 2014 +0800 +# Date: Thu Dec 25 00:34:35 2014 +0800 # Author: Yuxin Wu import sqlite3 @@ -32,7 +32,7 @@ class WeChatDBParser(object): self.msgs_by_talker = defaultdict(list) self.emojis = {} self.internal_emojis = {} - self.parse() + self._parse() def _parse_contact(self): contacts = self.cc.execute( @@ -105,7 +105,7 @@ SELECT {} FROM message self.internal_emojis[md5] = name - def parse(self): + def _parse(self): self._parse_userinfo() self._parse_contact() self._parse_msg() diff --git a/lib/render.py b/lib/render.py index a295729..81d92a7 100644 --- a/lib/render.py +++ b/lib/render.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2 # -*- coding: UTF-8 -*- # File: render.py -# Date: Tue Dec 23 00:01:11 2014 +0800 +# Date: Thu Dec 25 10:01:58 2014 +0800 # Author: Yuxin Wu import os @@ -92,8 +92,12 @@ class HTMLRender(object): elif msg.type == TYPE_IMG: # imgPath was original THUMBNAIL_DIRPATH://th_xxxxxxxxx imgpath = msg.imgPath.split('_')[-1] + if not imgpath: + logger.warn('No imgpath in an image message. Perhaps a bug in wechat.') + return fallback() bigimgpath = self.parser.imginfo.get(msg.msgSvrId) - fnames = [k for k in [imgpath, bigimgpath] if k is not None] + fnames = [k for k in [imgpath, bigimgpath] if k] + assert len(fnames) > 0, msg.msg_str() bigimg, smallimg = self.res.get_img(fnames) if not smallimg: logger.warn("No image thumbnail found for {}".format(imgpath)) diff --git a/lib/res.py b/lib/res.py index 1547bb3..283e2d1 100644 --- a/lib/res.py +++ b/lib/res.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2 # -*- coding: UTF-8 -*- # File: res.py -# Date: Mon Dec 22 16:52:56 2014 +0800 +# Date: Thu Dec 25 10:04:29 2014 +0800 # Author: Yuxin Wu import glob @@ -127,6 +127,7 @@ class Resource(object): def get_img(self, fnames): """ return two base64 jpg string""" + fnames = [k for k in fnames if k] # filter out empty string big_file, small_file = self._get_img_file(fnames) def get_jpg_b64(img_file): diff --git a/plot_num_msg_by_time.py b/plot_num_msg_by_time.py index 5f86cc4..a2c0b32 100755 --- a/plot_num_msg_by_time.py +++ b/plot_num_msg_by_time.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2 # -*- coding: UTF-8 -*- # File: plot_num_msg_by_time.py -# Date: Sat Nov 22 22:32:50 2014 +0800 +# Date: Thu Dec 25 00:35:57 2014 +0800 # Author: Yuxin Wu from lib.parser import WeChatDBParser @@ -17,10 +17,9 @@ if len(sys.argv) != 3: db_file = sys.argv[1] name = ensure_unicode(sys.argv[2]) -every_k_days = 2 +every_k_days = 3 parser = WeChatDBParser(db_file) -parser.parse() msgs = parser.msgs_by_talker[name] times = [x.createTime for x in msgs] start_time = times[0]