-
-
Save cllu/b55d90769217797c2d80 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment