在Nexus 5(Android 4.4)+WeChat 5.4,和Nexus 5(Android 5.0)+Wechat 6.0上測試可用。
獲取加密的sqlite3數據庫EnMicroMsg.db
如果已經root過,可以下載/data/data/com.tencent.mm/MicroMsg/*/EnMicroMsg.db
。
若沒有root,則/data/data/com.tencent.mm
下多數目錄都不可讀,可以使用下面的方法:
- 開啓“開發人員選項”,選上“USB偵錯”
- 電腦上執行
adb backup -noapk com.tencent.mm
- 在手機上彈出對話框提示是否允許備份
- 不要設置密碼,點備份,電腦會收到
backup.ab
- 解壓
backup.ab
:dd if=backup.ab bs=24 skip=1 | openssl zlib -d > backup.tar
- 解壓
backup.tar
得到數據庫apps/com.tencent.mm/r/MicroMsg/*/EnMicroMsg.db
獲取用於生成密鑰的信息
- uin:訪問
/data/data/com.tencent.mm/MicroMsg/*/system_config_prefs.xml
,獲取其中name="default_uin" value="([0-9]+)"
的value
字段值uin
。也可以打開wx.qq.com網頁版,查找.wx.qq.com
域的cookie,其中wxuin
字段的值就是uin
。也可以用backup.tar
裏的apps/com.tencent.mm/sp/system_config_prefs.xml
。 - IMEI:在撥號盤輸入
*#06#
獲取IMEI,或者開啓“USB偵錯”後使用adb shell dumpsys iphonesubinfo
得到15個十進制數字組成的imei
。網上查到有些機型可能使用不同於IMEI的其他字段用於生成密鑰。
使用sqlcipher解密
把上面兩步得到的imei
和uin
拼接起來計算MD5。執行echo -n "$imei$uin" | md5sum | cut -c -7
獲取sqlcipher使用的加密密鑰,下面用abcdefg
指代。
執行sqlcipher EnMicroMsg.db
,輸入:
1 2 3 4 5 |
PRAGMA key='abcdefg'; PRAGMA cipher_use_hmac = off; ATTACH DATABASE "decrypted_database.db" AS decrypted_database KEY ""; SELECT sqlcipher_export("decrypted_database"); DETACH DATABASE decrypted_database; |
解密得到可用sqlite3打開的decrypted_database.db
。
注意,sqlcipher不同版本使用的加密方式不同,我嘗試使用3.8.4.3版本打開數據庫文件,得到如下錯誤信息:
1 2 3 |
sqlite> PRAGMA key='abcdefg'; sqlite> .schema Error: file is encrypted or is not a database |
目前發現2.1.1版本的sqlcipher可以解密。可以下載https://github.com/CovenantEyes/sqlcipher-windows/releases提供的2.1.1的Windows用exe,用wine運行,或者在https://launchpad.net/ubuntu/+source/sqlcipher/2.1.1-2/+build/4642377上下載libsqlcipher0_2.1.1-2_amd64.deb
和sqlcipher_2.1.1-2_amd64.deb
,執行:
1 2 3 4 5 6 7 |
# /tmp/sqlcipher_2.1.1-2_amd64.deb # /tmp/libsqlcipher0_2.1.1-2_amd64.deb cd /tmp # get /tmp/usr/bin/sqlcipher ar x sqlcipher_2.1.1-2_amd64.deb && tar xf data.tar.gz --no-overwrite-dir # get /tmp/usr/lib/x86_64-linux-gnu/libsqlcipher.so.0.8.6 ar x libsqlcipher0_2.1.1-2_amd64.deb && tar xf data.tar.gz --no-overwrite-dir |
解壓後執行:
1
|
cd /tmp/usr && LD_LIBRARY_PATH=lib/x86_64-linux-gnu bin/sqlcipher /tmp/EnMicroMsg.db
|
解析message
表並導出消息
message
表儲存消息。目前瞭解到從fmessage_conversation
、rcontact
和chatroom
表中可以得到一些聯繫人和聊天室的信息。
暫時使用一個比較粗糙的Ruby腳本導出信息,需要先gem install sqlite3
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
require 'sqlite3' begin talker2name = {} username2name = {} db = SQLite3::Database.open '/tmp/decrypted_database.db' db.results_as_hash = true db.execute('SELECT talker,displayName FROM fmessage_conversation').each {|row| talker2name[row['talker']] = row['displayName'] } db.execute('SELECT username,nickname FROM rcontact').each {|row| username = row['username'] nickname = row['nickname'] if nickname != '' if username =~ /@chatroom$/ talker2name[username] = nickname == '' ? username : nickname else username2name[username] = nickname == '' ? username : nickname end end } db.execute('SELECT createTime,talker,content FROM message').each {|row| time,talker,content = row.values_at 'createTime','talker','content' next unless content if talker =~ /@chatroom$/ content.sub!(/^(\w+):\n/) {|x| "#{username2name.fetch($1,'xx')}: " } end #next if content =~ /^~SEMI_XML~|</ next if content =~ /^~SEMI_XML~/ name = talker2name.fetch talker, talker puts "#{Time.at(time/1000).strftime('%FT%R')}\t#{name}\t#{content}" } rescue SQLite3::Exception => e puts e ensure db.close if db end |
Refenrences
来自:http://maskray.me/blog/2014-10-14-wechat-export