import os
import sys
import re
import hashlib
import csv
import time
import locale
import getopt
def get_db():
os.popen(
'adb root'
).close()
text = os.popen(
'adb shell ls /data/data/com.tencent.mm/MicroMsg/*/EnMicroMsg.db'
).read()
return
text.splitlines()[- 1]
if
text
else
''
def get_default_uin():
os.popen(
'adb root'
).close()
text = os.popen(
'adb shell cat /data/data/com.tencent.mm/shared_prefs/system_config_prefs.xml'
).read()
default_uin = re.findall(
'name="default_uin" value="([0-9]+)"'
, text)
return
default_uin[0]
if
default_uin
else
0
def get_device_ID():
text = os.popen(
'adb shell dumpsys iphonesubinfo'
).read()
device_ID = re.findall(
'Device ID = ([0-9]+)'
, text)
return
device_ID[0]
if
device_ID
else
0
def get_md5():
default_uin = get_default_uin()
device_ID = get_device_ID()
if
default_uin and device_ID:
return
hashlib.md5(device_ID + default_uin).hexdigest()[0: 7]
return
''
def parse_msgcsv(msgcsv):
locale.setlocale(locale.LC_ALL,
''
)
if
hasattr(msgcsv,
'title'
):
msgcsv = [ooOoo0O +
'\n'
for
ooOoo0O
in
msgcsv.splitlines()]
pass
OooO0 = csv.reader(msgcsv)
OooO0.next()
for
ooOoo0O
in
OooO0:
try
:
II11iiii1Ii, OO0o, Ooo, O0o0Oo, Oo00OOOOO, O0O, O00o0OO, name, iIi1ii1I1, o0, I11II1i, IIIII = ooOoo0O[
: 12]
pass
except:
continue
ooooooO0oo =
'me'
if
(Oo00OOOOO ==
'1'
)
else
name
IIiiiiiiIi1I1 = time.localtime(
int
(O00o0OO) / 1000)
I1IIIii = time.strftime(
"%Y-%m-%d %a %H:%M:%S"
, IIiiiiiiIi1I1)
yield [name, I1IIIii, ooooooO0oo, iIi1ii1I1, o0]
pass
pass
def get_names(chat):
names = {}
for
name, I1IIIii, ooooooO0oo, iIi1ii1I1, o0
in
chat:
names[name] = 1
pass
return
names.keys()
def oo(chat, name=
''
):
text = []
name = name.lower()
for
name, I1IIIii, ooooooO0oo, iIi1ii1I1, o0
in
chat:
iIi1ii1I1 = iIi1ii1I1.replace(
'\n'
,
'\n '
)
o0 = (
'\t'
+ o0)
if
o0
else
''
if
not name:
text.append(
'%s: %s %s: %s %s'
%
(name, I1IIIii, ooooooO0oo, iIi1ii1I1, o0))
pass
elif name.lower() == name:
text.append(
'%s %s: %s %s'
%
(I1IIIii, ooooooO0oo, iIi1ii1I1, o0))
pass
pass
return
'\n'
.
join
(text) +
'\n'
def IIIii1II1II(dbn, key=
''
):
child_stdin, child_stdout = os.popen2([
'sqlcipher'
, dbn])
if
key:
child_stdin.write(
'PRAGMA key=%s;\n'
% ` key `)
child_stdin.write(
'pragma cipher_use_hmac=off;\n'
)
pass
child_stdin.write(
'.tables\n'
)
child_stdin.close()
return
child_stdout.read().split()
def decrypt(dbn, key=
''
, table=
'message'
):
table = table or
'message'
child_stdin, child_stdout = os.popen2([
'sqlcipher'
, dbn])
child_stdin.write(
'.header on\n'
)
child_stdin.write(
'.mode csv\n'
)
if
key:
child_stdin.write(
'PRAGMA key=%s;\n'
% ` key `)
child_stdin.write(
'pragma cipher_use_hmac=off;\n'
)
pass
child_stdin.write(
'select * from %s;\n'
% ` table `)
child_stdin.close()
return
child_stdout.read()
def wechat2txt(names=[]):
in_file =
'EnMicroMsg.db'
out_file =
'message.csv'
db = get_db()
md5 = get_md5()
os.popen(
'adb wait-for-device'
)
os.popen(
'adb pull %s %s'
% (db, in_file)).close()
msgcsv = decrypt(in_file, md5)
if
msgcsv.find(
'\n'
) < 0:
return
1
file(out_file,
'w'
).write(msgcsv)
msgs = list(parse_msgcsv(msgcsv))
if
not msgs:
return
1
if
not names:
names = get_names(msgs)
pass
for
name
in
names:
filename =
'message.%s.txt'
% name
text = oo(msgs, name)
if
len(text) > 4:
file(filename,
'w'
).write(text)
pass
pass
pass
help_msg =
''
'Usage: wechat2txt.py [OPTIONS] [NAME]...
OPTIONS:
-h display
this
help and exit
''
'
def main():
try
:
opts, args = getopt.getopt(sys.argv[1:],
'h'
)
except getopt.error, e:
print help_msg
return
1
for
opt, arg
in
opts:
if
opt ==
'-h'
:
print help_msg
return
1
pass
names = args
text = wechat2txt(names)
return
not text
if
__name__ ==
"__main__"
:
sys.exit(main())