Android微信数据导出

原文地址http://maskray.me/blog/2014-10-14-wechat-export

Android微信数据导出

在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.abdd 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
  • 切换到/data/data/com.tencent.mm/shared_prefs目录,然后执行grep -rn "uin" *来查看保存的UIN的值
  • IMEI:在拨号盘输入*#06#获取IMEI,或者开启“USB侦错”后使用adb shell dumpsys iphonesubinfo得到15个十进制数字组成的imei。网上查到有些机型可能使用不同于IMEI的其他字段用于生成密钥。搜索string name="imei"

使用sqlcipher解密

把上面两步得到的imeiuin拼接起来计算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

#!/usr/bin/python
# -*- coding: utf-8 -*-
import hashlib
import os
from pysqlcipher import dbapi2 as sqlite

def calc_keys(): 
	IMEI = ['11111111']  #搜索string name="imei"
	uin = '11111111'  # 
	for imei in IMEI:
		hash_md5 = hashlib.md5(imei + uin)
		key = hash_md5.hexdigest()[0:7]
		print 'Decrypted Key:'+key       
def calc_uin():
	record = open('./record_uin.txt','w')
	md5_value = ['ee1da3ae2100e09165c2e52382cfe79f','a0e401d1016d5aed404c3ad71fe7fe0b']
	# int32(-2147483648, 2147483647)   
	uin = 2147483647
	while (uin>-2147483649):
		data = 'mm' + str(uin)
		hash_md5 = hashlib.md5(data)
		if hash_md5.hexdigest() in md5_value:
			record_value = "uin:%d; Directory name:%s"%(uin, hash_md5.hexdigest())
			record.write(record_value + '\n')
			print record_value.decode('utf-8')
		uin = uin -1
	record.close()
	print 'Match end'
def Decrypt_Wechat(): 
	DBName = 'EnMicroMsg.db'
	conn = sqlite.connect(DBName)
	c = conn.cursor()
	c.execute("PRAGMA key = '5344987';")
	c.execute("PRAGMA cipher_use_hmac = OFF;")
	c.execute("PRAGMA cipher_page_size = 1024;")
	c.execute("PRAGMA kdf_iter = 4000;")
	c.execute("ATTACH DATABASE 'wechat.db' AS wechat KEY '';")
	c.execute("SELECT sqlcipher_export('wechat');" )
	c.execute("DETACH DATABASE wechat;" )
	c.close()
if __name__ == "__main__":
	Decrypt_Wechat()  

注意,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.debsqlcipher_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_conversationrcontactchatroom表中可以得到一些联系人和聊天室的信息。

暂时使用一个比较粗糙的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



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值