diff --git a/README.md b/README.md index 073b45a..3f4fde5 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ Logo -

WhatsApp Key/Database Extractor

+

WhatsApp Key/Database Extractor

+

NO LONGER MAINTAINED

Extract key/msgstore.db from /data/data/com.whatsapp in Android v4.0+ without root. diff --git a/helpers/__init__.py b/helpers/__init__.py index 903ed9a..47f814f 100644 --- a/helpers/__init__.py +++ b/helpers/__init__.py @@ -1,4 +1,5 @@ # For relative imports to work in Python 3.6 import os import sys + sys.path.append(os.path.dirname(os.path.realpath(__file__))) diff --git a/helpers/custom_ci.py b/helpers/custom_ci.py index ef200f9..f7f512d 100644 --- a/helpers/custom_ci.py +++ b/helpers/custom_ci.py @@ -8,37 +8,45 @@ from termcolor import colored, cprint except ImportError: try: - os.system('pip3 install termcolor') + os.system("pip3 install termcolor") except Exception: - os.system('python3 -m pip install termcolor') + os.system("python3 -m pip install termcolor") -if not (os.path.isdir('log')): - os.mkdir('log') -logging.basicConfig(filename='log/wa_kdbe.log', level=logging.DEBUG, format='') +if not (os.path.isdir("log")): + os.mkdir("log") +logging.basicConfig(filename="log/wa_kdbe.log", level=logging.DEBUG, format="") masked = [] -def custom_input(text_to_input, color='green', attr=[], is_get_time=True, is_log=True): - time = get_time() if is_get_time else '' - data = input(colored(f'{time}{text_to_input}', color, attrs=attr)) - if(is_log): - logging.debug(f'{time}{text_to_input}{data}') +def custom_input(text_to_input, color="green", attr=[], is_get_time=True, is_log=True): + time = get_time() if is_get_time else "" + data = input(colored(f"{time}{text_to_input}", color, attrs=attr)) + if is_log: + logging.debug(f"{time}{text_to_input}{data}") else: - logging.debug(f'{time}{text_to_input}********') + logging.debug(f"{time}{text_to_input}********") # Add that password in list, and mask that while printing also. masked.append(data) return data -def custom_print(text_to_print, color='green', attr=[], is_get_time=True, is_log=True, is_print=True, end='\n'): - time = get_time() if is_get_time else '' +def custom_print( + text_to_print, + color="green", + attr=[], + is_get_time=True, + is_log=True, + is_print=True, + end="\n", +): + time = get_time() if is_get_time else "" text_to_print = str(text_to_print) - if(is_print): - cprint(f'{time}{text_to_print}', color, attrs=attr, end=end) + if is_print: + cprint(f"{time}{text_to_print}", color, attrs=attr, end=end) else: pass - if(is_log): - logging.debug(f'{time}{text_to_print}') + if is_log: + logging.debug(f"{time}{text_to_print}") else: # Search for password and mask. for i in masked: diff --git a/helpers/device_serial_id.py b/helpers/device_serial_id.py index 7cf392b..a7054ae 100644 --- a/helpers/device_serial_id.py +++ b/helpers/device_serial_id.py @@ -5,124 +5,148 @@ from custom_ci import custom_input, custom_print -def init(mode, tcp_ip='', tcp_port=''): +def init(mode, tcp_ip="", tcp_port=""): custom_print( - f'>>> I am in device_serial_id.init({mode=!s}, {tcp_ip=!s}, {tcp_port=!s})', is_print=False) + f">>> I am in device_serial_id.init(mode={mode}, tcp_ip{tcp_ip}, tcp_port={tcp_port})", + is_print=False, + ) # Detect OS is_windows = False - if platform.system() == 'Windows': + if platform.system() == "Windows": is_windows = True # Global command line helpers curr_dir = os.path.dirname(os.path.realpath(__file__)) - root_dir = os.path.abspath(os.path.join(curr_dir, '..')) + root_dir = os.path.abspath(os.path.join(curr_dir, "..")) - if(is_windows): - adb = f'{root_dir}\\bin\\adb.exe' + if is_windows: + adb = f"{root_dir}\\bin\\adb.exe" else: - adb = 'adb' + adb = "adb" # Kill server before getting list to avoid daemon texts. - os.system(f'{adb} kill-server') - os.system(f'{adb} start-server') - - combo = f'{tcp_ip}:{tcp_port}' - cmd = '' - if mode == 'USB': - cmd = f'{adb} devices' - elif mode == 'TCP': - cmd = f'{adb} connect {combo}' + os.system(f"{adb} kill-server") + os.system(f"{adb} start-server") + + combo = f"{tcp_ip}:{tcp_port}" + cmd = "" + if mode == "USB": + cmd = f"{adb} devices" + elif mode == "TCP": + cmd = f"{adb} connect {combo}" else: pass # FIXME: Wrong choice. - proc = sp.Popen(cmd.split(), stdin=sp.PIPE, stdout=sp.PIPE, - stderr=sp.PIPE, shell=False) + proc = sp.Popen( + cmd.split(), stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=False + ) output, error = proc.communicate() - output = output.decode('utf-8') - error = error.decode('utf-8') + output = output.decode("utf-8") + error = error.decode("utf-8") if len(output) == 0 or error: output = None - custom_print(error, 'red') + custom_print(error, "red") kill_me() - if mode == 'USB': - output = [x.strip() for x in output.split('\n') if len(x.strip()) > 0] + if mode == "USB": + output = [x.strip() for x in output.split("\n") if len(x.strip()) > 0] - if(len(output) == 1): + if len(output) == 1: custom_print( - 'Could not find any connected device. Is USB Debugging on?', 'red') - return '' + "Could not find any connected device. Is USB Debugging on?", "red" + ) + return "" device_to_connect = None - if(len(output) == 2): - if(output[1].split()[1] == 'offline'): + if len(output) == 2: + if output[1].split()[1] == "offline": custom_print( - 'Device is offline, try turning off USB debugging and turn on again.', 'yellow') + "Device is offline, try turning off USB debugging and turn on again.", + "yellow", + ) kill_me() - if(output[1].split()[1] == 'unauthorized'): + if output[1].split()[1] == "unauthorized": custom_print( - 'Device unauthorized. Please check the confirmation dialog on your device.', 'red') + "Device unauthorized. Please check the confirmation dialog on your device.", + "red", + ) kill_me() return output[1].split()[0] custom_print(output[0]) - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) if device_to_connect is None: padding = f' {" " * 25}' for index, device in enumerate(output[1:]): serial = device.split()[0] state = device.split()[1] - name = 'Unknown' if state == 'unauthorized' else sp.getoutput( - f'{adb} -s {device.split()[0]} shell getprop ro.product.model').strip() - custom_print('{}. {:.15s} {:.15s} {}' - .format(index + 1, serial + padding, state + padding, name)) + name = ( + "Unknown" + if state == "unauthorized" + else sp.getoutput( + f"{adb} -s {device.split()[0]} shell getprop ro.product.model" + ).strip() + ) + custom_print( + "{}. {:.15s} {:.15s} {}".format( + index + 1, serial + padding, state + padding, name + ) + ) while device_to_connect is None: - device_index = int(custom_input( - 'Enter device number (for ex: 2): ')) + device_index = int(custom_input("Enter device number (for ex: 2): ")) if device_index <= 0 or device_index + 1 > len(output): continue device_to_connect = output[device_index] - if(device_to_connect.split()[1] == 'offline'): + if device_to_connect.split()[1] == "offline": custom_print( - 'Device is offline, try turning off USB debugging and turn on again.', 'yellow') + "Device is offline, try turning off USB debugging and turn on again.", + "yellow", + ) kill_me() - if(device_to_connect.split()[1] == 'unauthorized'): + if device_to_connect.split()[1] == "unauthorized": custom_print( - 'Device unauthorized. Please check the confirmation dialog on your device.', 'red') + "Device unauthorized. Please check the confirmation dialog on your device.", + "red", + ) kill_me() return device_to_connect.split()[0] - elif mode == 'TCP': + elif mode == "TCP": output = [x.strip() for x in output.split() if len(x.strip()) > 0] - if('connected' in (x.lower() for x in output)): + if "connected" in (x.lower() for x in output): return combo - if('authenticate' in (x.lower() for x in output)): + if "authenticate" in (x.lower() for x in output): custom_print( - 'Device unauthorized. Please check the confirmation dialog on your device.', 'red') + "Device unauthorized. Please check the confirmation dialog on your device.", + "red", + ) kill_me() - if('refused' in (x.lower() for x in output)): + if "refused" in (x.lower() for x in output): custom_print( - 'Could not find any connected device. Either USB Debugging is off or device is not running ADB over TCP', 'red') - return '' - ''' Possible outputs + "Could not find any connected device. Either USB Debugging is off or device is not running ADB over TCP", + "red", + ) + return "" + """ Possible outputs ['connected', 'to', '192.168.43.130:5555'] ['failed', 'to', 'authenticate', 'to', '192.168.43.130:5555'] ['cannot', 'connect', 'to', '192.168.43.130:5555:', 'No', 'connection', 'could', 'be', 'made', 'because', 'the', 'target', 'machine', 'actively', 'refused', 'it.', '(10061)'] - ''' + """ else: pass # FIXME: Wrong choice. def kill_me(): + custom_print(">>> I am in device_serial_id.kill_me()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Exiting...") custom_print( - '>>> I am in device_serial_id.kill_me()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Exiting...') - custom_print( - 'Turn off USB debugging [and USB debugging (Security Settings)] if you\'re done.', 'cyan') - custom_input('Hit \"Enter\" key to continue....', 'cyan') + "Turn off USB debugging [and USB debugging (Security Settings)] if you're done.", + "cyan", + ) + custom_input('Hit "Enter" key to continue....', "cyan") quit() diff --git a/helpers/handler.py b/helpers/handler.py index b92f0d0..5c896f0 100644 --- a/helpers/handler.py +++ b/helpers/handler.py @@ -3,36 +3,39 @@ import shutil import subprocess from subprocess import getoutput + try: import requests from packaging import version from tqdm import tqdm except ImportError: try: - os.system('pip3 install packaging requests tqdm') + os.system("pip3 install packaging requests tqdm") except Exception: - os.system('python3 -m pip install packaging requests tqdm') + os.system("python3 -m pip install packaging requests tqdm") from custom_ci import custom_input, custom_print # Global variables -app_url_primary_cdn = 'https://web.archive.org/web/20141111030303if_/http://www.whatsapp.com/android/current/WhatsApp.apk' -app_url_alternate_cdn = 'https://legacy-static-assets.androidapksfree.com/earth/androidbucket/WhatsApp-v2.11.431-AndroidBucket.com.apk' +app_url_primary_cdn = "https://web.archive.org/web/20141111030303if_/http://www.whatsapp.com/android/current/WhatsApp.apk" +app_url_alternate_cdn = "https://legacy-static-assets.androidapksfree.com/earth/androidbucket/WhatsApp-v2.11.431-AndroidBucket.com.apk" + def after_connect(adb): - custom_print( - f'>>> I am in handler.after_connect({adb=!s})', is_print=False) - sdk_version = int(getoutput(f'{adb} shell getprop ro.build.version.sdk')) - if (sdk_version <= 13): + custom_print(f">>> I am in handler.after_connect(adb={adb})", is_print=False) + sdk_version = int(getoutput(f"{adb} shell getprop ro.build.version.sdk")) + if sdk_version <= 13: custom_print( - 'Unsupported device. This method only works on Android v4.0 or higher.', 'red') - custom_print('Cleaning up \"tmp\" folder.', 'red') - shutil.rmtree('tmp') + "Unsupported device. This method only works on Android v4.0 or higher.", + "red", + ) + custom_print('Cleaning up "tmp" folder.', "red") + shutil.rmtree("tmp") kill_me() - _wa_path_text = f'{adb} shell pm path com.whatsapp' + _wa_path_text = f"{adb} shell pm path com.whatsapp" whatsapp_apk_path_in_device = subprocess.getoutput(_wa_path_text) - if(not whatsapp_apk_path_in_device): - custom_print('Looks like WhatsApp is not installed on device.', 'red') + if not whatsapp_apk_path_in_device: + custom_print("Looks like WhatsApp is not installed on device.", "red") kill_me() whatsapp_apk_path_in_device = whatsapp_apk_path_in_device.split(":")[1] # To check if APK even exists at a given path to download! @@ -40,33 +43,34 @@ def after_connect(adb): try: resp = requests.head(app_url_primary_cdn, timeout=5) try: - content_length = resp.headers['content-length'] + content_length = resp.headers["content-length"] except KeyError as e: custom_print(e, is_print=False) - custom_print( - 'No \"content-length\" field in header, defaulting to 0.') + custom_print('No "content-length" field in header, defaulting to 0.') content_length = 0 except requests.exceptions.RequestException as e: custom_print(e, is_print=False) custom_print( - 'An exception has occured while checking for LegacyWhatsApp existence at web.archive.org, defaulting to alternate CDN server, check log for futher details.', 'yellow') + "An exception has occured while checking for LegacyWhatsApp existence at web.archive.org, defaulting to alternate CDN server, check log for futher details.", + "yellow", + ) content_length = 0 - _version_name_text = f'{adb} shell dumpsys package com.whatsapp' + _version_name_text = f"{adb} shell dumpsys package com.whatsapp" version_name = re.findall( - "(?<=versionName=)(.*?)(?=\n)", getoutput(_version_name_text))[0] - custom_print(f'WhatsApp v{version_name} installed on device') - download_app_from = app_url_primary_cdn if( - content_length == 18329558) else app_url_alternate_cdn - if (version.parse(version_name) > version.parse('2.11.431')): - if not (os.path.isfile('helpers/LegacyWhatsApp.apk')): - custom_print( - 'Downloading legacy WhatsApp V2.11.431 to \"helpers\" folder') - download_apk(download_app_from, 'helpers/LegacyWhatsApp.apk') + "(?<=versionName=)(.*?)(?=\n)", getoutput(_version_name_text) + )[0] + custom_print(f"WhatsApp v{version_name} installed on device") + download_app_from = ( + app_url_primary_cdn if (content_length == 18329558) else app_url_alternate_cdn + ) + if version.parse(version_name) > version.parse("2.11.431"): + if not (os.path.isfile("helpers/LegacyWhatsApp.apk")): + custom_print('Downloading legacy WhatsApp V2.11.431 to "helpers" folder') + download_apk(download_app_from, "helpers/LegacyWhatsApp.apk") # wget.download(downloadAppFrom, 'helpers/LegacyWhatsApp.apk') - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) else: - custom_print( - 'Found legacy WhatsApp V2.11.431 apk in \"helpers\" folder') + custom_print('Found legacy WhatsApp V2.11.431 apk in "helpers" folder') else: # Version lower than 2.11.431 installed on device. pass @@ -76,56 +80,62 @@ def after_connect(adb): def download_apk(url, file_name): custom_print( - f'>>> I am in handler.download_apk({url=!s}, {file_name=!s})', is_print=False) + f">>> I am in handler.download_apk(url={url}, file_name={file_name})", + is_print=False, + ) # Streaming, so we can iterate over the response. response = requests.get(url, stream=True) # For WayBackMachine only. - total_size_in_bytes = response.headers.get( - 'x-archive-orig-content-length') or response.headers.get('content-length', 0) - if(total_size_in_bytes): + total_size_in_bytes = int( + response.headers.get("x-archive-orig-content-length", 0) + ) or int(response.headers.get("content-length", 0)) + if total_size_in_bytes: # Fixed where it stuck on "Downloading legacy WhatsApp V2.11.431 to helpers folder" total_size_in_bytes = int(total_size_in_bytes) else: # totalSizeInBytes must be null custom_print( - '\aFor some reason I could not download Legacy WhatsApp, you need to download it on your own now from either of the links given below: ', 'red') - custom_print('\n', is_get_time=False) - custom_print( - f'1. \"{app_url_primary_cdn}\" (official\'s archive)', 'red') + "\aFor some reason I could not download Legacy WhatsApp, you need to download it on your own now from either of the links given below: ", + "red", + ) + custom_print("\n", is_get_time=False) + custom_print(f'1. "{app_url_primary_cdn}" (official\'s archive)', "red") + custom_print(f'2. "{app_url_alternate_cdn}" unofficial website.', "red") + custom_print("\n", is_get_time=False) custom_print( - f'2. \"{app_url_alternate_cdn}\" unofficial website.', 'red') - custom_print('\n', is_get_time=False) - custom_print( - 'Once downloaded rename it to \"LegacyWhatsApp.apk\" exactly and put in \"helpers\" folder.', 'red') + 'Once downloaded rename it to "LegacyWhatsApp.apk" exactly and put in "helpers" folder.', + "red", + ) kill_me() block_size = 1024 # 1 Kibibyte - progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True) - with open('helpers/temp.apk', 'wb') as f: + progress_bar = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True) + with open("helpers/temp.apk", "wb") as f: for data in response.iter_content(block_size): progress_bar.update(len(data)) f.write(data) progress_bar.close() - os.rename('helpers/temp.apk', file_name) - if (total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes): - custom_print('\aSomething went during downloading LegacyWhatsApp.apk') + os.rename("helpers/temp.apk", file_name) + if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes: + custom_print("\aSomething went during downloading LegacyWhatsApp.apk") kill_me() def kill_me(): - custom_print('>>> I am in handler.kill_me()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Exiting...') - os.system( - 'bin\\adb.exe kill-server') if(os.name == 'nt') else os.system('adb kill-server') + custom_print(">>> I am in handler.kill_me()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Exiting...") + os.system("bin\\adb.exe kill-server") if (os.name == "nt") else os.system( + "adb kill-server" + ) custom_print( - 'Turn off USB debugging [and USB debugging (Security Settings)] if you\'re done.', 'cyan') - custom_input('Hit \"Enter\" key to continue....', 'cyan') + "Turn off USB debugging [and USB debugging (Security Settings)] if you're done.", + "cyan", + ) + custom_input('Hit "Enter" key to continue....', "cyan") quit() def handler(adb): - custom_print( - f'>>> I am in handler.handler({adb=!s})', is_print=False) - custom_print( - f'Connected to {getoutput(adb + " shell getprop ro.product.model")}') + custom_print(f">>> I am in handler.handler(adb={adb})", is_print=False) + custom_print(f'Connected to {getoutput(adb + " shell getprop ro.product.model")}') return after_connect(adb) diff --git a/protect.py b/protect.py index 1b820e2..1bf2624 100644 --- a/protect.py +++ b/protect.py @@ -7,71 +7,81 @@ # Detect OS is_windows = False is_linux = False -if platform.system() == 'Windows': +if platform.system() == "Windows": is_windows = True -if platform.system() == 'Linux': +if platform.system() == "Linux": is_linux = True # Global command line helpers -extracted = 'extracted/' -bin = 'bin/' -if(is_windows): - seven_zip = 'bin\\7za.exe' +extracted = "extracted/" +bin = "bin/" +if is_windows: + seven_zip = "bin\\7za.exe" else: - seven_zip = '7z' + seven_zip = "7z" def main(): - custom_print('>>> I am in protect.main()', is_print=False) - custom_print('This utility is for archiving your output folder with password to enchance it\'s security. Secure is a relative term. Choose longer password.') - is_compressing = custom_input( - 'Are you (C)ompressing or (D)ecompressing?: ') - while(True): - if(is_compressing.upper() == 'C'): + custom_print(">>> I am in protect.main()", is_print=False) + custom_print( + "This utility is for archiving your output folder with password to enhance it's security. Secure is a relative term. Choose longer password." + ) + is_compressing = custom_input("Are you (C)ompressing or (D)ecompressing?: ") + while True: + if is_compressing.upper() == "C": list_user_folders() - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) user_folder = custom_input( - 'Enter a name of folder from above (case sensitive): ') + "Enter a name of folder from above (case sensitive): " + ) compress(user_folder) break - elif(is_compressing.upper() == 'D'): + elif is_compressing.upper() == "D": list_user_files() - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) user_zip = custom_input( - 'Enter a name of file from above (case sensitive): ') + "Enter a name of file from above (case sensitive): " + ) uncompress(user_zip) break else: - is_compressing = custom_input('Choose either \'c\' or \'d\': ') + is_compressing = custom_input("Choose either 'c' or 'd': ") continue def compress(user_folder): custom_print( - f'>>> I am in protect.compress({user_folder=!s})', is_print=False) - if(not os.path.isdir(f'{extracted}{user_folder}')): - custom_print(f'Could not find directory \"{extracted}{user_folder}\"') + f">>> I am in protect.compress(user_folder={user_folder})", is_print=False + ) + if not os.path.isdir(f"{extracted}{user_folder}"): + custom_print(f'Could not find directory "{extracted}{user_folder}"') kill_me() - elif(len(os.listdir(f'{extracted}{user_folder}')) == 0): - custom_print('User folder is empty.') + elif len(os.listdir(f"{extracted}{user_folder}")) == 0: + custom_print("User folder is empty.") kill_me() else: - password = custom_input('Choose a password for zip: ', is_log=False) - if(password): - password = f' -p{password}' + password = custom_input("Choose a password for zip: ", is_log=False) + if password: + password = f" -p{password}" os.system( - f'{seven_zip} a -t7z -mhe {extracted}{user_folder} {extracted}{user_folder}/* {password}') - custom_print('\n', is_get_time=False) + f"{seven_zip} a -t7z -mhe {extracted}{user_folder} {extracted}{user_folder}/* {password}" + ) + custom_print("\n", is_get_time=False) custom_print( - 'If you see \"Everything is OK\" in above line then it is recommended to delete user folder.') - is_delete_user_folder = custom_input( - f'Delete \"{user_folder}\" folder? (default y): ') or 'Y' - custom_print('\n', is_get_time=False) + 'If you see "Everything is OK" in above line then it is recommended to delete user folder.' + ) + is_delete_user_folder = ( + custom_input(f'Delete "{user_folder}" folder? (default y): ') or "Y" + ) + custom_print("\n", is_get_time=False) custom_print( - f'\aYour \"{user_folder}.7z\" file is in \"{os.path.realpath(extracted)}\" folder. Password is: {password.replace(" -p", "")}', 'yellow', is_log=False) - custom_print('\n', is_get_time=False) - custom_input('Hit \"Enter\" key to continue.') - if(is_delete_user_folder.upper() == 'Y'): + f'\aYour "{user_folder}.7z" file is in "{os.path.realpath(extracted)}" folder. Password is: {password.replace(" -p", "")}', + "yellow", + is_log=False, + ) + custom_print("\n", is_get_time=False) + custom_input('Hit "Enter" key to continue.') + if is_delete_user_folder.upper() == "Y": delete_user_folder(user_folder) else: kill_me() @@ -79,80 +89,85 @@ def compress(user_folder): def delete_user_folder(user_folder): custom_print( - f'>>> I am in protect.delete_user_folder({user_folder=!s})', is_print=False) - custom_print('Deleting...') + f">>> I am in protect.delete_user_folder(user_folder={user_folder})", + is_print=False, + ) + custom_print("Deleting...") try: - shutil.rmtree(f'{extracted}{user_folder}') + shutil.rmtree(f"{extracted}{user_folder}") except Exception as e: - custom_print(e, 'red') - custom_print('Please manually delete it.', 'red') + custom_print(e, "red") + custom_print("Please manually delete it.", "red") kill_me() def delete_user_zip(user_zip): custom_print( - f'>>> I am in protect.delete_user_zip({user_zip=!s})', is_print=False) - custom_print('Deleting...') + f">>> I am in protect.delete_user_zip(user_zip={user_zip})", is_print=False + ) + custom_print("Deleting...") try: - os.remove(f'{extracted}{user_zip}') + os.remove(f"{extracted}{user_zip}") except Exception as e: - custom_print(e, 'red') - custom_print('Please manually delete it.', 'red') + custom_print(e, "red") + custom_print("Please manually delete it.", "red") kill_me() def kill_me(): - custom_print('>>> I am in protect.kill_me()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Exiting...') + custom_print(">>> I am in protect.kill_me()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Exiting...") try: # Open in explorer. - if(is_windows): + if is_windows: os.startfile(os.path.realpath(extracted)) - elif(is_linux): - os.system(f'xdg-open {os.path.realpath(extracted)}') + elif is_linux: + os.system(f"xdg-open {os.path.realpath(extracted)}") else: try: - os.system(f'open {os.path.realpath(extracted)}') + os.system(f"open {os.path.realpath(extracted)}") except Exception as e: custom_print(e, is_print=False) except Exception as e: custom_print(e, is_print=False) custom_print( - 'Turn off USB debugging [and USB debugging (Security Settings)] if you\'re done.', 'cyan') - custom_input('Hit \"Enter\" key to continue....', 'cyan') + "Turn off USB debugging [and USB debugging (Security Settings)] if you're done.", + "cyan", + ) + custom_input('Hit "Enter" key to continue....', "cyan") quit() def list_user_files(): - custom_print('>>> I am in protect.list_user_files()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Available user files in extracted directory.') - custom_print('\n', is_get_time=False) + custom_print(">>> I am in protect.list_user_files()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Available user files in extracted directory.") + custom_print("\n", is_get_time=False) all_files = next(os.walk(extracted))[2] - if(len(all_files) == 1 and os.path.isfile(f'{extracted}.placeholder')): - custom_print(f'No user files found in \"{extracted}\" folder.', 'red') + if len(all_files) == 1 and os.path.isfile(f"{extracted}.placeholder"): + custom_print(f'No user files found in "{extracted}" folder.', "red") kill_me() for f in all_files: - if(f != '.placeholder'): + if f != ".placeholder": custom_print(f) def list_user_folders(): - custom_print('>>> I am in protect.list_user_folders()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Available user folders in extracted directory.') - custom_print('\n', is_get_time=False) + custom_print(">>> I am in protect.list_user_folders()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Available user folders in extracted directory.") + custom_print("\n", is_get_time=False) all_folders = next(os.walk(extracted))[1] - if(len(all_folders) == 0): - custom_print(f'No folders found in \"{extracted}\" folder.', 'red') + if len(all_folders) == 0: + custom_print(f'No folders found in "{extracted}" folder.', "red") kill_me() for folder in all_folders: custom_print(folder) def show_banner(): - custom_print('>>> I am in protect.show_banner()', is_print=False) - banner_content = ''' + custom_print(">>> I am in protect.show_banner()", is_print=False) + banner_content = """ ================================================================================ ======== ======== ======== db d8b db .d8b. db dD d8888b. d8888b. d88888b ======== @@ -163,41 +178,46 @@ def show_banner(): ======== `8b8' `8d8' YP YP YP YD Y8888D' Y8888P' Y88888P ======== ======== ======== ================================================================================ - ''' - custom_print(banner_content, 'green', ['bold'], False) - custom_print('============ WhatsApp Key / Database Extrator for non-rooted Android ===========\n', - 'green', ['bold'], False) + """ + custom_print(banner_content, "green", ["bold"], False) + custom_print( + "============ WhatsApp Key / Database Extrator for non-rooted Android ===========\n", + "green", + ["bold"], + False, + ) def uncompress(user_zip): - custom_print( - f'>>> I am in protect.uncompress({user_zip=!s})', is_print=False) - if(not str(user_zip).endswith('7z')): - user_zip = f'{user_zip}.7z' - if(not os.path.isfile(f'{extracted}{user_zip}')): - custom_print(f'Could not find {extracted}{user_zip}') + custom_print(f">>> I am in protect.uncompress(user_zip={user_zip})", is_print=False) + if not str(user_zip).endswith("7z"): + user_zip = f"{user_zip}.7z" + if not os.path.isfile(f"{extracted}{user_zip}"): + custom_print(f"Could not find {extracted}{user_zip}") kill_me() - elif(os.path.getsize(f'{extracted}{user_zip}') <= 0): - custom_print(f'{extracted}{user_zip} is empty.') + elif os.path.getsize(f"{extracted}{user_zip}") <= 0: + custom_print(f"{extracted}{user_zip} is empty.") kill_me() else: - password = custom_input( - 'Enter password, leave empty for none: ', is_log=False) - if(password): - password = f' -p{password}' + password = custom_input("Enter password, leave empty for none: ", is_log=False) + if password: + password = f" -p{password}" os.system( - f'{seven_zip} e -aot {extracted}{user_zip} -o{extracted}{user_zip.replace(".7z", "")} {password}') - custom_print('\n', is_get_time=False) + f'{seven_zip} e -aot {extracted}{user_zip} -o{extracted}{user_zip.replace(".7z", "")} {password}' + ) + custom_print("\n", is_get_time=False) custom_print( - 'If you see \"Everything is OK\" in above line then you can delete user zip file.') - is_delete_user_zip = custom_input( - f'Delete {user_zip} ? (default n): ') or 'N' - custom_print('\n', is_get_time=False) + 'If you see "Everything is OK" in above line then you can delete user zip file.' + ) + is_delete_user_zip = custom_input(f"Delete {user_zip} ? (default n): ") or "N" + custom_print("\n", is_get_time=False) custom_print( - f'\aYour extracted \"{user_zip.replace(".7z","")}\" folder is in \"{os.path.realpath(extracted + user_zip.replace(".7z", ""))}\" folder.', 'yellow') - custom_print('\n', is_get_time=False) - custom_input('Hit \"Enter\" key to continue.') - if(is_delete_user_zip.upper() == 'Y'): + f'\aYour extracted "{user_zip.replace(".7z","")}" folder is in "{os.path.realpath(extracted + user_zip.replace(".7z", ""))}" folder.', + "yellow", + ) + custom_print("\n", is_get_time=False) + custom_input('Hit "Enter" key to continue.') + if is_delete_user_zip.upper() == "Y": delete_user_zip(user_zip) else: kill_me() @@ -205,11 +225,15 @@ def uncompress(user_zip): if __name__ == "__main__": from datetime import datetime + dt = datetime.now() custom_print( - f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', is_get_time=False, is_print=False) - os.system('cls' if os.name == 'nt' else 'clear') + f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', + is_get_time=False, + is_print=False, + ) + os.system("cls" if os.name == "nt" else "clear") show_banner() main() diff --git a/restore_whatsapp.py b/restore_whatsapp.py index d6f5b53..3459ab4 100644 --- a/restore_whatsapp.py +++ b/restore_whatsapp.py @@ -9,51 +9,64 @@ # Detect OS is_windows = False is_linux = False -if platform.system() == 'Windows': +if platform.system() == "Windows": is_windows = True -if platform.system() == 'Linux': +if platform.system() == "Linux": is_linux = True def kill_me(): - custom_print('>>> I am in restore_whatsapp.kill_me()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Exiting...') - os.system( - 'bin\\adb.exe kill-server') if(is_windows) else os.system('adb kill-server') + custom_print(">>> I am in restore_whatsapp.kill_me()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Exiting...") + os.system("bin\\adb.exe kill-server") if (is_windows) else os.system( + "adb kill-server" + ) custom_print( - 'Turn off USB debugging [and USB debugging (Security Settings)] if you\'re done.', 'cyan') - custom_input('Hit \"Enter\" key to continue....', 'cyan') + "Turn off USB debugging [and USB debugging (Security Settings)] if you're done.", + "cyan", + ) + custom_input('Hit "Enter" key to continue....', "cyan") quit() def reinstall_whatsapp(adb): custom_print( - f'>>> I am in restore_whatsapp.restore_whatsapp({adb=!s})', is_print=False) - custom_print('Reinstalling original WhatsApp.') - if('/data/local/tmp/WhatsAppbackup.apk' in subprocess.getoutput(f'{adb} shell ls /data/local/tmp/WhatsAppbackup.apk')): + f">>> I am in restore_whatsapp.restore_whatsapp(adb={adb})", is_print=False + ) + custom_print("Reinstalling original WhatsApp.") + if "/data/local/tmp/WhatsAppbackup.apk" in subprocess.getoutput( + f"{adb} shell ls /data/local/tmp/WhatsAppbackup.apk" + ): try: reinstall_whatsapp_out = subprocess.getoutput( - f'{adb} shell pm install /data/local/tmp/WhatsAppbackup.apk') - if('Success' in reinstall_whatsapp_out): - custom_print('Reinstallation complete.') + f"{adb} shell pm install /data/local/tmp/WhatsAppbackup.apk" + ) + if "Success" in reinstall_whatsapp_out: + custom_print("Reinstallation complete.") kill_me() else: - custom_print('Could not install WhatsApp, install by running \"restore_whatsapp.py\" or manually installing from Play Store.\nHowever if it crashes then you have to clear storage/clear data from \"Settings \u2192 App Settings \u2192 WhatsApp\".', 'red') - custom_print(reinstall_whatsapp_out, 'red') + custom_print( + 'Could not install WhatsApp, install by running "restore_whatsapp.py" or manually installing from Play Store.\nHowever if it crashes then you have to clear storage/clear data from "Settings \u2192 App Settings \u2192 WhatsApp".', + "red", + ) + custom_print(reinstall_whatsapp_out, "red") kill_me() except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") kill_me() else: - custom_print('Could not find backup APK, install from play store.\nHowever if it crashes then you have to clear storage/clear data from \"Settings \u2192 App Settings \u2192 WhatsApp\".', 'red') + custom_print( + 'Could not find backup APK, install from play store.\nHowever if it crashes then you have to clear storage/clear data from "Settings \u2192 App Settings \u2192 WhatsApp".', + "red", + ) kill_me() def show_banner(): - custom_print('>>> I am in restore_whatsapp.show_banner()', is_print=False) - banner_content = ''' + custom_print(">>> I am in restore_whatsapp.show_banner()", is_print=False) + banner_content = """ ================================================================================ ======== ======== ======== db d8b db .d8b. db dD d8888b. d8888b. d88888b ======== @@ -64,44 +77,57 @@ def show_banner(): ======== `8b8' `8d8' YP YP YP YD Y8888D' Y8888P' Y88888P ======== ======== ======== ================================================================================ - ''' - custom_print(banner_content, 'green', ['bold'], False) - custom_print('============ WhatsApp Key / Database Extrator for non-rooted Android ===========\n', - 'green', ['bold'], False) + """ + custom_print(banner_content, "green", ["bold"], False) + custom_print( + "============ WhatsApp Key / Database Extrator for non-rooted Android ===========\n", + "green", + ["bold"], + False, + ) if __name__ == "__main__": from datetime import datetime + dt = datetime.now() custom_print( - f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', is_get_time=False, is_print=False) - os.system('cls' if os.name == 'nt' else 'clear') + f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', + is_get_time=False, + is_print=False, + ) + os.system("cls" if os.name == "nt" else "clear") parser = argparse.ArgumentParser() - parser.add_argument('-tip', - '--tcp-ip', help='Connects to a remote device via TCP mode.') - parser.add_argument('-tp', '--tcp-port', default='5555', - help='Port number to connect to. Default: 5555') + parser.add_argument( + "-tip", "--tcp-ip", help="Connects to a remote device via TCP mode." + ) + parser.add_argument( + "-tp", + "--tcp-port", + default="5555", + help="Port number to connect to. Default: 5555", + ) args = parser.parse_args() # args = parser.parse_args('--tcp-ip 192.168.168.117'.split()) tcp_ip = args.tcp_ip tcp_port = args.tcp_port - if(tcp_ip): - adb_device_serial_id = device_id.init('TCP', tcp_ip, tcp_port) + if tcp_ip: + adb_device_serial_id = device_id.init("TCP", tcp_ip, tcp_port) else: - adb_device_serial_id = device_id.init('USB') - if(not adb_device_serial_id): + adb_device_serial_id = device_id.init("USB") + if not adb_device_serial_id: kill_me() # Global command line helpers - helpers = 'helpers/' - if(is_windows): - adb = f'bin\\adb.exe -s {adb_device_serial_id}' + helpers = "helpers/" + if is_windows: + adb = f"bin\\adb.exe -s {adb_device_serial_id}" else: - adb = f'adb -s {adb_device_serial_id}' + adb = f"adb -s {adb_device_serial_id}" - os.system('cls' if os.name == 'nt' else 'clear') + os.system("cls" if os.name == "nt" else "clear") show_banner() reinstall_whatsapp(adb) diff --git a/view_extract.py b/view_extract.py index 005af18..7bba7b5 100644 --- a/view_extract.py +++ b/view_extract.py @@ -13,187 +13,220 @@ # Detect OS is_windows = False is_linux = False -if platform.system() == 'Windows': +if platform.system() == "Windows": is_windows = True -if platform.system() == 'Linux': +if platform.system() == "Linux": is_linux = True # Global command line helpers -tmp = 'tmp/' -helpers = 'helpers/' -bin = 'bin/' -extracted = 'extracted/' -if(is_windows): - adb = 'bin\\adb.exe -s ' +tmp = "tmp/" +helpers = "helpers/" +bin = "bin/" +extracted = "extracted/" +if is_windows: + adb = "bin\\adb.exe -s " else: - adb = 'adb -s ' + adb = "adb -s " def main(): - custom_print('>>> I am in view_extract.main()', is_print=False) - os.system('cls' if os.name == 'nt' else 'clear') + custom_print(">>> I am in view_extract.main()", is_print=False) + os.system("cls" if os.name == "nt" else "clear") show_banner() check_java() extract_self(is_tar_only=is_tar_only) def check_java(): - custom_print('>>> I am in view_extract.check_java()', is_print=False) - java_version = '' - out = getoutput('java -version') - if(out): + custom_print(">>> I am in view_extract.check_java()", is_print=False) + java_version = "" + out = getoutput("java -version") + if out: java_version = re.findall('(?<=version ")(.*)(?=")', out) else: custom_print( - 'Could not get output of \"java -version\" in \"view_extract.py\"', 'red') + 'Could not get output of "java -version" in "view_extract.py"', "red" + ) kill_me() if java_version: custom_print( - f'Found Java v{java_version[0]} installed on system. Continuing...') + f"Found Java v{java_version[0]} installed on system. Continuing..." + ) else: - is_no_java_continue = custom_input( - 'It looks like you don\'t have JAVA installed on your system. If you are sure that JAVA is installed you can (C)ontinue with the process or (S)top?: ', 'red') or 's' - if(is_no_java_continue.upper() == 'C'): - custom_print( - 'Continuing without detecting JAVA...', 'yellow') + is_no_java_continue = ( + custom_input( + "It looks like you don't have JAVA installed on your system. If you are sure that JAVA is installed you can (C)ontinue with the process or (S)top?: ", + "red", + ) + or "s" + ) + if is_no_java_continue.upper() == "C": + custom_print("Continuing without detecting JAVA...", "yellow") else: - kill_me('Can not view extract without java installed on system!') + kill_me("Can not view extract without java installed on system!") def clean_tmp(): - custom_print('>>> I am in view_extract.clean_tmp()', is_print=False) - if(os.path.isdir(tmp)): - custom_print(f'Cleaning up \"{tmp}\" folder...', 'yellow') - shutil.rmtree(tmp) + custom_print(">>> I am in view_extract.clean_tmp()", is_print=False) + if os.path.isdir(tmp): + custom_print(f'Cleaning up "{tmp}" folder...', "yellow") + try: + shutil.rmtree(tmp) + except PermissionError as e: + custom_print(f'Could not delete "{tmp}" folder...', "red") + custom_print(e, 'red') + custom_print('Delete it manually, it\'s important.') -def kill_me(reason: str = ''): - custom_print( - f'>>> I am in view_extract.kill_me({reason=!s})', is_print=False) - custom_print('\n', is_get_time=False) +def kill_me(reason: str = ""): + custom_print(f">>> I am in view_extract.kill_me(reason={reason})", is_print=False) + custom_print("\n", is_get_time=False) if reason: custom_print(reason) - custom_print('Exiting...') - os.system( - 'bin\\adb.exe kill-server') if(is_windows) else os.system('adb kill-server') + custom_print("Exiting...") + os.system("bin\\adb.exe kill-server") if (is_windows) else os.system( + "adb kill-server" + ) custom_print( - 'Turn off USB debugging [and USB debugging (Security Settings)] if you\'re done.', 'cyan') - custom_input('Hit \"Enter\" key to continue....', 'cyan') + "Turn off USB debugging [and USB debugging (Security Settings)] if you're done.", + "cyan", + ) + custom_input('Hit "Enter" key to continue....', "cyan") quit() def extract_ab(is_java_installed, is_tar_only=False): custom_print( - f'>>> I am in view_extract.extract_ab({is_java_installed=!s}, {is_tar_only=!s})', is_print=False) + f">>> I am in view_extract.extract_ab(is_java_installed={is_java_installed}, is_tar_only={is_tar_only})", + is_print=False, + ) if not is_java_installed: - custom_print('\aCan not detect JAVA on system.', 'red') + custom_print("\aCan not detect JAVA on system.", "red") # move whatsapp.ab from tmp to user specified folder. - username = custom_input('Enter a name for this user.: ') + username = custom_input("Enter a name for this user.: ") os.mkdir(extracted) if not (os.path.isdir(extracted)) else custom_print( - f'Folder \"{extracted}\" already exists.', 'yellow') - if not os.path.isdir(f'{extracted}{username}'): - os.mkdir(f'{extracted}{username}') - custom_print(f'Created folder \"{extracted}{username}\"') + f'Folder "{extracted}" already exists.', "yellow" + ) + if not os.path.isdir(f"{extracted}{username}"): + os.mkdir(f"{extracted}{username}") + custom_print(f'Created folder "{extracted}{username}"') else: - while(os.path.isdir(f'{extracted}{username}')): - custom_print('\n', is_get_time=False) + while os.path.isdir(f"{extracted}{username}"): + custom_print("\n", is_get_time=False) custom_print( - f'Folder \"{extracted}{username}\" exists, contents may get overwritten.', 'red') - username = custom_input('Enter different name of this user.: ') - if not (os.path.isdir(f'{extracted}{username}')): - os.mkdir(f'{extracted}{username}') - custom_print(f'Created folder \"{extracted}{username}\"') + f'Folder "{extracted}{username}" exists, contents may get overwritten.', + "red", + ) + username = custom_input("Enter different name of this user.: ") + if not (os.path.isdir(f"{extracted}{username}")): + os.mkdir(f"{extracted}{username}") + custom_print(f'Created folder "{extracted}{username}"') break - os.rename(f'{tmp}whatsapp.ab', f'{extracted}{username}/whatsapp.ab') + os.rename(f"{tmp}whatsapp.ab", f"{extracted}{username}/whatsapp.ab") custom_print( - f'Moved \"whatsapp.ab\" to \"{extracted}{username}\" folder. Size: {os.path.getsize(extracted + username + "/whatsapp.ab")} bytes.') - custom_print( - 'Run \"view_extract.py\" after installing Java on system.') + f'Moved "whatsapp.ab" to "{extracted}{username}" folder. Size: {os.path.getsize(extracted + username + "/whatsapp.ab")} bytes.' + ) + custom_print('Run "view_extract.py" after installing Java on system.') clean_tmp() kill_me() - if(os.path.isfile(f'{tmp}whatsapp.ab')): + if os.path.isfile(f"{tmp}whatsapp.ab"): custom_print( - f'Found \"whatsapp.ab\" in \"tmp\" folder. Continuing... Size: {os.path.getsize(tmp + "/whatsapp.ab")} bytes.') - username = custom_input( - 'Enter a name for this user (default \"user\").: ') or 'user' + f'Found "whatsapp.ab" in "tmp" folder. Continuing... Size: {os.path.getsize(tmp + "/whatsapp.ab")} bytes.' + ) + username = ( + custom_input('Enter a name for this user (default "user").: ') or "user" + ) ab_pass = custom_input( - 'Enter same password which you entered on device when prompted earlier.: ', is_log=False) + "Enter same password which you entered on device when prompted earlier.: ", + is_log=False, + ) try: unpack_out = getoutput( - f'java -jar {bin}abe.jar unpack {tmp}whatsapp.ab {tmp}whatsapp.tar {ab_pass}') - if('Exception' in unpack_out): - custom_print(f'Could not unpack \"{tmp}whatsapp.ab\"', 'red') - custom_print(unpack_out, 'red') + f"java -jar {bin}abe.jar unpack {tmp}whatsapp.ab {tmp}whatsapp.tar {ab_pass}" + ) + if "Exception" in unpack_out: + custom_print(f'Could not unpack "{tmp}whatsapp.ab"', "red") + custom_print(unpack_out, "red") kill_me() custom_print( - f'Successfully unpacked \"{tmp}whatsapp.ab\" to \"{tmp}whatsapp.tar\". Size: {os.path.getsize(tmp + "whatsapp.tar")} bytes.') - if(is_tar_only): + f'Successfully unpacked "{tmp}whatsapp.ab" to "{tmp}whatsapp.tar". Size: {os.path.getsize(tmp + "whatsapp.tar")} bytes.' + ) + if is_tar_only: taking_out_only_tar(username) else: taking_out_main_files(username) except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") kill_me() else: - custom_print( - '\aCould not find \"whatsapp.ab\" in \"tmp\" folder.', 'red') + custom_print('\aCould not find "whatsapp.ab" in "tmp" folder.', "red") kill_me() def extract_self(is_tar_only=False): custom_print( - f'>>> I am in view_extract.extract_self({is_tar_only=!s})', is_print=False) + f">>> I am in view_extract.extract_self(is_tar_only={is_tar_only})", + is_print=False, + ) list_user_folders() - username = custom_input( - 'Enter a name of folder from above (case sensitive): ') - while(not os.path.isfile(f'{extracted}{username}/whatsapp.ab')): - if(os.path.isdir(f'{extracted}{username}') and not os.path.isfile(f'{extracted}{username}/whatsapp.ab')): + username = custom_input("Enter a name of folder from above (case sensitive): ") + while not os.path.isfile(f"{extracted}{username}/whatsapp.ab"): + if os.path.isdir(f"{extracted}{username}") and not os.path.isfile( + f"{extracted}{username}/whatsapp.ab" + ): custom_print( - f'Folder \"{extracted}{username}\" does not even contain whatsapp.ab', 'red') + f'Folder "{extracted}{username}" does not even contain whatsapp.ab', + "red", + ) kill_me() username = custom_input( - f'No such folder: \"{extracted}{username}\". Enter correct name (case sensitive).: ') + f'No such folder: "{extracted}{username}". Enter correct name (case sensitive).: ' + ) ab_pass = custom_input( - 'Enter same password which you entered on device when prompted earlier.: ', is_log=False) + "Enter same password which you entered on device when prompted earlier.: ", + is_log=False, + ) try: os.mkdir(tmp) if not (os.path.isdir(tmp)) else custom_print( - f'Folder \"{tmp}\" already exists.', 'yellow') + f'Folder "{tmp}" already exists.', "yellow" + ) unpack_out = getoutput( - f'java -jar {bin}abe.jar unpack {extracted}{username}/whatsapp.ab {tmp}whatsapp.tar {ab_pass}') - if('Exception' in unpack_out): - custom_print(f'Could not unpack \"{tmp}whatsapp.ab\"', 'red') - custom_print(unpack_out, 'red') + f"java -jar {bin}abe.jar unpack {extracted}{username}/whatsapp.ab {tmp}whatsapp.tar {ab_pass}" + ) + if "Exception" in unpack_out: + custom_print(f'Could not unpack "{tmp}whatsapp.ab"', "red") + custom_print(unpack_out, "red") kill_me() custom_print( - f'Successfully unpacked \"{extracted}{username}/whatsapp.ab\" to \"{tmp}whatsapp.tar\". Size: {os.path.getsize(tmp + "whatsapp.tar")} bytes.') - if(is_tar_only): + f'Successfully unpacked "{extracted}{username}/whatsapp.ab" to "{tmp}whatsapp.tar". Size: {os.path.getsize(tmp + "whatsapp.tar")} bytes.' + ) + if is_tar_only: taking_out_only_tar(username) else: taking_out_main_files(username) except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") kill_me() def list_user_folders(): - custom_print('>>> I am in view_extract.list_user_folders()', - is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Available user folders in extracted directory.') + custom_print(">>> I am in view_extract.list_user_folders()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Available user folders in extracted directory.") all_folders = next(os.walk(extracted))[1] - if(len(all_folders) == 0): - custom_print(f'No folders found in \"{extracted}\" folder.', 'red') + if len(all_folders) == 0: + custom_print(f'No folders found in "{extracted}" folder.', "red") kill_me() for folder in all_folders: custom_print(folder) - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) def show_banner(): - custom_print('>>> I am in view_extract.show_banner()', is_print=False) - banner_content = ''' + custom_print(">>> I am in view_extract.show_banner()", is_print=False) + banner_content = """ ================================================================================ ======== ======== ======== db d8b db .d8b. db dD d8888b. d8888b. d88888b ======== @@ -204,124 +237,152 @@ def show_banner(): ======== `8b8' `8d8' YP YP YP YD Y8888D' Y8888P' Y88888P ======== ======== ======== ================================================================================ - ''' - custom_print(banner_content, 'green', ['bold'], False) - custom_print('============ WhatsApp Key / Database Extrator for non-rooted Android ===========\n', - 'green', ['bold'], False) + """ + custom_print(banner_content, "green", ["bold"], False) + custom_print( + "============ WhatsApp Key / Database Extractor for non-rooted Android ==========\n", + "green", + ["bold"], + False, + ) def taking_out_main_files(username): custom_print( - f'>>> I am in view_extract.taking_out_main_files({username=!s})', is_print=False) + f">>> I am in view_extract.taking_out_main_files(username={username})", + is_print=False, + ) os.mkdir(extracted) if not (os.path.isdir(extracted)) else custom_print( - f'Folder \"{extracted}\" already exists.', 'yellow') - os.mkdir(f'{extracted}{username}') if not (os.path.isdir(f'{extracted}{username}') - ) else custom_print(f'Folder \"{extracted}{username}\" already exists.', 'yellow') + f'Folder "{extracted}" already exists.', "yellow" + ) + os.mkdir(f"{extracted}{username}") if not ( + os.path.isdir(f"{extracted}{username}") + ) else custom_print(f'Folder "{extracted}{username}" already exists.', "yellow") # If user folder already exists ask user to overwrite or skip. - custom_print(f'Taking out main files in \"{tmp}\" folder temporarily.') + custom_print(f'Taking out main files in "{tmp}" folder temporarily.') try: - tar = tarfile.open(f'{tmp}whatsapp.tar') + tar = tarfile.open(f"{tmp}whatsapp.tar") all_tar_files = tar.getnames() files_to_extract = { - 'axolotl.db': 'apps/com.whatsapp/db/axolotl.db', - 'encrypted_backup.key': 'apps/com.whatsapp/f/encrypted_backup.key', - 'password_data.key': 'apps/com.whatsapp/f/password_data.key', - 'chatsettings.db': 'apps/com.whatsapp/db/chatsettings.db', - 'key': 'apps/com.whatsapp/f/key', - 'msgstore.db': 'apps/com.whatsapp/db/msgstore.db', - 'wa.db': 'apps/com.whatsapp/db/wa.db', + "axolotl.db": "apps/com.whatsapp/db/axolotl.db", + "encrypted_backup.key": "apps/com.whatsapp/f/encrypted_backup.key", + "password_data.key": "apps/com.whatsapp/f/password_data.key", + "chatsettings.db": "apps/com.whatsapp/db/chatsettings.db", + "key": "apps/com.whatsapp/f/key", + "msgstore.db": "apps/com.whatsapp/db/msgstore.db", + "wa.db": "apps/com.whatsapp/db/wa.db", } for key in files_to_extract: - if(files_to_extract[key] in all_tar_files): + if files_to_extract[key] in all_tar_files: tar.extract(files_to_extract[key], tmp) os.replace( - f'{tmp}{files_to_extract[key]}', f'{extracted}{username}/{key}') - custom_print(f'Copied to \"{extracted}{username}\": {key}') + f"{tmp}{files_to_extract[key]}", f"{extracted}{username}/{key}" + ) + custom_print(f'Copied to "{extracted}{username}": {key}') else: - if key in ['encrypted_backup.key', 'password_data.key']: + if key in ["encrypted_backup.key", "password_data.key"]: custom_print( - f'\"{key}\" is not present in tarfile, if you have crypt15 backups then visit \"https://github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor/issues/94\" for more details.', 'red', ['bold']) + f'"{key}" is not present in tarfile, if you have crypt15 backups then visit "https://github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor/issues/94" for more details.', + "red", + ["bold"], + ) else: custom_print( - f'\"{key}\" is not present in tarfile, visit \"https://github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor/issues/73\" for more details.', 'red', ['bold']) + f'"{key}" is not present in tarfile, visit "https://github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor/issues/73" for more details.', + "red", + ["bold"], + ) tar.close() time.sleep(2) # So that 'tar' is free to delete. try: clean_tmp() except Exception as e: - custom_print(e, 'red') - custom_print('\n', is_get_time=False) + custom_print(e, "red") + custom_print("\n", is_get_time=False) custom_print( - f'Go & delete \"{tmp}\" folder yourself (It\'s important, DO IT.)', 'red') - custom_print('\n', is_get_time=False) + f'Go & delete "{tmp}" folder yourself (It\'s important, DO IT.)', "red" + ) + custom_print("\n", is_get_time=False) # TODO: Major security risk: Data in tmp is not deleted. custom_print( - 'You should not leave these extracted database and other files hanging in folder, it is very insecure.') - is_create_archive = custom_input( - 'Would you like to create a password protected archive? (default y): ') or 'Y' - if(is_create_archive.upper() == 'Y'): - custom_print('\n', is_get_time=False) - custom_print('Now an archive will be created in extracted folder and original files will be deleted. To later \"un-archive\" and access these files you need to run \"python protect.py\" from root directory of this project.', 'yellow') + "You should not leave these extracted database and other files hanging in folder, it is very insecure." + ) + is_create_archive = ( + custom_input( + "Would you like to create a password protected archive? (default y): " + ) + or "Y" + ) + if is_create_archive.upper() == "Y": + custom_print("\n", is_get_time=False) + custom_print( + 'Now an archive will be created in extracted folder and original files will be deleted. To later "un-archive" and access these files you need to run "python protect.py" from root directory of this project.', + "yellow", + ) protect.compress(username) else: - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) custom_print( - f'\aYour WhatsApp database along with other files is in \"{os.path.realpath(extracted + username)}\" folder.', 'yellow') - custom_print('\n', is_get_time=False) - custom_input('Hit \"Enter\" key to continue.') + f'\aYour WhatsApp database along with other files is in "{os.path.realpath(extracted + username)}" folder.', + "yellow", + ) + custom_print("\n", is_get_time=False) + custom_input('Hit "Enter" key to continue.') try: # Open in explorer. - if(is_windows): - os.startfile(os.path.realpath(f'{extracted}{username}')) - elif(is_linux): - os.system( - f'xdg-open {os.path.realpath(extracted + username)}') + if is_windows: + os.startfile(os.path.realpath(f"{extracted}{username}")) + elif is_linux: + os.system(f"xdg-open {os.path.realpath(extracted + username)}") else: try: - os.system( - f'open {os.path.realpath(extracted + username)}') + os.system(f"open {os.path.realpath(extracted + username)}") except Exception as e: custom_print(e, is_print=False) except Exception as e: custom_print(e, is_print=False) kill_me() except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") clean_tmp() kill_me() def taking_out_only_tar(username): custom_print( - f'>>> I am in view_extract.taking_out_only_tar({username=!s})', is_print=False) + f">>> I am in view_extract.taking_out_only_tar(username={username})", + is_print=False, + ) os.mkdir(extracted) if not (os.path.isdir(extracted)) else custom_print( - f'Folder \"{extracted}\" already exists.', 'yellow') + f'Folder "{extracted}" already exists.', "yellow" + ) try: - custom_print( - f'Moving \"tmp/whatsapp.tar\" to \"{extracted}{username}.tar\"') - os.replace(f'{tmp}whatsapp.tar', f'{extracted}{username}.tar') + custom_print(f'Moving "tmp/whatsapp.tar" to "{extracted}{username}.tar"') + os.replace(f"{tmp}whatsapp.tar", f"{extracted}{username}.tar") except Exception as e: - custom_print(f'\a{e}', 'red') + custom_print(f"\a{e}", "red") kill_me() clean_tmp() - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) custom_print( - f'\aYour \"{username}.tar\" is in \"{os.path.realpath(extracted)}\" folder.', 'yellow') + f'\aYour "{username}.tar" is in "{os.path.realpath(extracted)}" folder.', + "yellow", + ) - custom_print('\n', is_get_time=False) - custom_input('Hit \"Enter\" key to continue.') + custom_print("\n", is_get_time=False) + custom_input('Hit "Enter" key to continue.') try: # Open in explorer. - if(is_windows): + if is_windows: os.startfile(os.path.realpath(extracted)) - elif(is_linux): - os.system(f'xdg-open {os.path.realpath(extracted)}') + elif is_linux: + os.system(f"xdg-open {os.path.realpath(extracted)}") else: try: - os.system(f'open {os.path.realpath(extracted)}') + os.system(f"open {os.path.realpath(extracted)}") except Exception as e: custom_print(e, is_print=False) except Exception as e: @@ -331,19 +392,29 @@ def taking_out_only_tar(username): if __name__ == "__main__": from datetime import datetime + dt = datetime.now() custom_print( - f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', is_get_time=False, is_print=False) + f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', + is_get_time=False, + is_print=False, + ) parser = argparse.ArgumentParser() parser.add_argument( - '-tip', '--tcp-ip', help='Connects to a remote device via TCP mode.') - parser.add_argument('-tp', '--tcp-port', - help='Port number to connect to. Default: 5555') + "-tip", "--tcp-ip", help="Connects to a remote device via TCP mode." + ) + parser.add_argument( + "-tp", "--tcp-port", help="Port number to connect to. Default: 5555" + ) - parser.add_argument('-to', '--tar-only', action='store_true', - help='Get entire WhatsApp\'s data in \".tar\" file instead of just getting few important files.') + parser.add_argument( + "-to", + "--tar-only", + action="store_true", + help='Get entire WhatsApp\'s data in ".tar" file instead of just getting few important files.', + ) args = parser.parse_args() # args = parser.parse_args('--tcp-ip 192.168.43.130 -tp 555'.split()) diff --git a/waZ b/waZ new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/waZ @@ -0,0 +1 @@ + diff --git a/wa_kdbe.py b/wa_kdbe.py index be93ff4..b66d60c 100644 --- a/wa_kdbe.py +++ b/wa_kdbe.py @@ -10,13 +10,14 @@ import termcolor from tqdm import tqdm except ImportError: - print('\nFirst run: Auto installing python requirements.\n') + print("\nFirst run: Auto installing python requirements.\n") try: # Trying both methods of installations - os.system('pip3 install --upgrade packaging psutil termcolor requests tqdm') + os.system("pip3 install --upgrade packaging psutil termcolor requests tqdm") except Exception: os.system( - 'python3 -m pip install --upgrade packaging psutil termcolor requests tqdm') + "python3 -m pip install --upgrade packaging psutil termcolor requests tqdm" + ) import argparse @@ -34,46 +35,54 @@ # Detect OS is_windows = False is_linux = False -if platform.system() == 'Windows': +if platform.system() == "Windows": is_windows = True -if platform.system() == 'Linux': +if platform.system() == "Linux": is_linux = True + def main(): - custom_print('>>> I am in wa_kdbe.main()', is_print=False) - os.system('cls' if os.name == 'nt' else 'clear') + custom_print(">>> I am in wa_kdbe.main()", is_print=False) + os.system("cls" if os.name == "nt" else "clear") check_bin() show_banner() global is_java_installed is_java_installed = check_java() - custom_print('', is_get_time=False) + custom_print("", is_get_time=False) try: - custom_print(f'Arguments passed: {args}', is_print=False) + custom_print(f"Arguments passed: {args}", is_print=False) except Exception as e: custom_print(e, is_print=False) try: custom_print( - f'System Info: {json.dumps(get_sys_info(), indent=2, default=str)}', is_print=False) + f"System Info: {json.dumps(get_sys_info(), indent=2, default=str)}", + is_print=False, + ) except Exception as e: - custom_print( - 'Can\'t get system information. Continuing anyway...', 'yellow') + custom_print("Can't get system information. Continuing anyway...", "yellow") custom_print(e, is_print=False) - if(tcp_ip): - custom_print('TCP mode, not turning data and wifi off...', - is_print=False) + if tcp_ip: + custom_print("TCP mode, not turning data and wifi off...", is_print=False) else: - os.system(f'{adb} shell svc data disable') - os.system(f'{adb} shell svc wifi disable') - custom_print('Turned off wifi and mobile data...', 'yellow') - - is_read_instructions = custom_input( - '\aPlease read above instructions carefully \u2191 . Continue? (default y): ', 'yellow') or 'Y' - if(is_read_instructions.upper() == 'Y'): - custom_print('\n', is_get_time=False) + os.system(f"{adb} shell svc data disable") + os.system(f"{adb} shell svc wifi disable") + custom_print("Turned off wifi and mobile data...", "yellow") + + is_read_instructions = ( + custom_input( + "\aPlease read above instructions carefully \u2191 . Continue? (default y): ", + "yellow", + ) + or "Y" + ) + if is_read_instructions.upper() == "Y": + custom_print("\n", is_get_time=False) custom_input( - '\aIf you haven\'t already, it is advised to take a WhatsApp chat backup by going to \"WhatsApp settings \u2192 Chat Settings \u2192 Chat Backup". Hit \"Enter\" key to continue.', 'yellow') + '\aIf you haven\'t already, it is advised to take a WhatsApp chat backup by going to "WhatsApp settings \u2192 Chat Settings \u2192 Chat Backup". Hit "Enter" key to continue.', + "yellow", + ) usb_mode() else: kill_me() @@ -90,17 +99,18 @@ def animate(message): "| o |", "| o |", "| o |", - "|o |" + "|o |", ] - message = f'{message} ' + message = f"{message} " is_log_only_one_instance = True - while(subprocess.getoutput(f'{adb} get-state') != 'device'): + while subprocess.getoutput(f"{adb} get-state") != "device": # 6 iterations of 0.8 seconds sleep before checking again. temp = 6 - while(temp >= 0): + while temp >= 0: for frame in frames: - custom_print(f'{message}{frame}', - is_log=is_log_only_one_instance, end='\r') + custom_print( + f"{message}{frame}", is_log=is_log_only_one_instance, end="\r" + ) is_log_only_one_instance = False # 0.8 seconds sleep: 0.08 * 10(frames) time.sleep(0.08) @@ -109,67 +119,85 @@ def animate(message): def backup_whatsapp_apk(sdk_version, version_name, whatsapp_apk_path_in_device): custom_print( - f'>>> I am in wa_kdbe.backup_whatsapp_apk({sdk_version=!s}, {version_name=!s}, {whatsapp_apk_path_in_device=!s})', is_print=False) - os.system(f'{adb} shell am force-stop com.whatsapp') if(sdk_version > - 11) else os.system(f'{adb} shell am kill com.whatsapp') + f">>> I am in wa_kdbe.backup_whatsapp_apk(sdk_version={sdk_version}, version_name={version_name}, whatsapp_apk_path_in_device={whatsapp_apk_path_in_device})", + is_print=False, + ) + os.system(f"{adb} shell am force-stop com.whatsapp") if ( + sdk_version > 11 + ) else os.system(f"{adb} shell am kill com.whatsapp") custom_print( - f'Backing up WhatsApp {version_name} apk, the one installed on device to \"/data/local/tmp/WhatsAppbackup.apk\" in your phone.') + f'Backing up WhatsApp {version_name} apk, the one installed on device to "/data/local/tmp/WhatsAppbackup.apk" in your phone.' + ) os.system( - f'{adb} shell cp {whatsapp_apk_path_in_device} /data/local/tmp/WhatsAppbackup.apk') - custom_print('Apk backup is completed.') + f"{adb} shell cp {whatsapp_apk_path_in_device} /data/local/tmp/WhatsAppbackup.apk" + ) + custom_print("Apk backup is completed.") def backup_whatsapp_data_as_ab(sdk_version): custom_print( - f'>>> I am in wa_kdbe.backup_whatsapp_data_as_ab({sdk_version=!s})', is_print=False) + f">>> I am in wa_kdbe.backup_whatsapp_data_as_ab(sdk_version={sdk_version})", + is_print=False, + ) os.mkdir(tmp) if not (os.path.isdir(tmp)) else custom_print( - f'Folder {tmp} already exists.', 'yellow') + f"Folder {tmp} already exists.", "yellow" + ) custom_print( - f'Backing up WhatsApp data as \"{tmp}whatsapp.ab\". May take time, don\'t panic.') + f'Backing up WhatsApp data as "{tmp}whatsapp.ab". May take time, don\'t panic.' + ) try: - os.system(f'{adb} backup -f {tmp}whatsapp.ab com.whatsapp') if(sdk_version >= - 23) else os.system(f'{adb} backup -f {tmp}whatsapp.ab -noapk com.whatsapp') + os.system(f"{adb} backup -f {tmp}whatsapp.ab com.whatsapp") if ( + sdk_version >= 23 + ) else os.system(f"{adb} backup -f {tmp}whatsapp.ab -noapk com.whatsapp") except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") kill_me() custom_print( - f'Done backing up data. Size: {os.path.getsize(tmp + "whatsapp.ab")} bytes.') + f'Done backing up data. Size: {os.path.getsize(tmp + "whatsapp.ab")} bytes.' + ) def check_bin(): - custom_print('>>> I am in wa_kdbe.check_bin()', is_print=False) - if (not os.path.isdir('bin')): - custom_print('I can not find \"bin\" folder, check again...', 'red') + custom_print(">>> I am in wa_kdbe.check_bin()", is_print=False) + if not os.path.isdir("bin"): + custom_print('I can not find "bin" folder, check again...', "red") kill_me() else: pass def check_java(): - custom_print('>>> I am in wa_kdbe.check_java()', is_print=False) - java_version = '' - out = subprocess.getoutput('java -version') - if(out): + custom_print(">>> I am in wa_kdbe.check_java()", is_print=False) + java_version = "" + out = subprocess.getoutput("java -version") + if out: java_version = re.findall('(?<=version ")(.*)(?=")', out) else: - custom_print( - 'Could not get output of \"java -version\" in \"wa_kdbe.py\"', 'red') - custom_print('Continuing without JAVA...', 'red') + custom_print('Could not get output of "java -version" in "wa_kdbe.py"', "red") + custom_print("Continuing without JAVA...", "red") return False - if(java_version): + if java_version: is_java_installed = True else: is_java_installed = False if is_java_installed: custom_print( - f'Found Java v{java_version[0]} installed on system. Continuing...') + f"Found Java v{java_version[0]} installed on system. Continuing..." + ) return is_java_installed else: - is_no_java_continue = custom_input( - 'It looks like you don\'t have JAVA installed on your system. Would you like to (C)ontinue with the process and \"view extract\" later? or (S)top?: ', 'red') or 'C' - if(is_no_java_continue.upper() == 'C'): + is_no_java_continue = ( + custom_input( + 'It looks like you don\'t have JAVA installed on your system. Would you like to (C)ontinue with the process and "view extract" later? or (S)top?: ', + "red", + ) + or "C" + ) + if is_no_java_continue.upper() == "C": custom_print( - 'Continuing without JAVA, once JAVA is installed on system run \"view_extract.py\"', 'yellow') + 'Continuing without JAVA, once JAVA is installed on system run "view_extract.py"', + "yellow", + ) return is_java_installed else: kill_me() @@ -178,138 +206,162 @@ def check_java(): def countdown(message, time_sec): while time_sec: mins, secs = divmod(time_sec, 60) - timeformat = '{:02d}:{:02d}'.format(mins, secs) - custom_print(f'{message}{timeformat}.', end='\r') + timeformat = "{:02d}:{:02d}".format(mins, secs) + custom_print(f"{message}{timeformat}.", end="\r") time.sleep(1) time_sec -= 1 - custom_print('', is_get_time=False) + custom_print("", is_get_time=False) def kill_me(): - custom_print('>>> I am in wa_kdbe.kill_me()', is_print=False) - custom_print('\n', is_get_time=False) - custom_print('Exiting...') - os.system( - 'bin\\adb.exe kill-server') if(is_windows) else os.system('adb kill-server') + custom_print(">>> I am in wa_kdbe.kill_me()", is_print=False) + custom_print("\n", is_get_time=False) + custom_print("Exiting...") + os.system("bin\\adb.exe kill-server") if (is_windows) else os.system( + "adb kill-server" + ) custom_print( - 'Turn off USB debugging [and USB debugging (Security Settings)] if you\'re done.', 'cyan') - custom_input('Hit \"Enter\" key to continue....', 'cyan') + "Turn off USB debugging [and USB debugging (Security Settings)] if you're done.", + "cyan", + ) + custom_input('Hit "Enter" key to continue....', "cyan") quit() def get_sys_info(): - custom_print('>>> I am in wa_kdbe.get_sys_info()', is_print=False) + custom_print(">>> I am in wa_kdbe.get_sys_info()", is_print=False) info = {} - info['Architecture'] = platform.machine() - info['Hostname'] = socket.gethostname() - info['Platform'] = platform.system() - info['Platform Release'] = platform.release() - info['Platform Version'] = platform.version() - info['Processor'] = platform.processor() - info['RAM'] = f'{round(psutil.virtual_memory().total / (1024.0 ** 3))} GB' - info['Python'] = platform.python_build() + info["Architecture"] = platform.machine() + info["Hostname"] = socket.gethostname() + info["Platform"] = platform.system() + info["Platform Release"] = platform.release() + info["Platform Version"] = platform.version() + info["Processor"] = platform.processor() + info["RAM"] = f"{round(psutil.virtual_memory().total / (1024.0 ** 3))} GB" + info["Python"] = platform.python_build() return info def install_legacy(sdk_version): custom_print( - f'>>> I am in wa_kdbe.install_legacy({sdk_version=!s})', is_print=False) - custom_print('Installing legacy WhatsApp V2.11.431, hold tight now.') - if(sdk_version >= 17): + f">>> I am in wa_kdbe.install_legacy(sdk_version={sdk_version})", is_print=False + ) + custom_print("Installing legacy WhatsApp V2.11.431, hold tight now.") + if sdk_version >= 17: install_legacy_out = subprocess.getoutput( - f'{adb} install -r -d -g {helpers}LegacyWhatsApp.apk') - if('Success' in install_legacy_out): - custom_print('Installation Complete.') + f"{adb} install -r -d -g {helpers}LegacyWhatsApp.apk" + ) + if "Success" in install_legacy_out: + custom_print("Installation Complete.") else: - custom_print('Could not install legacy WhatsApp', 'red') - custom_print(install_legacy_out, 'red') - countdown('Trying to restore WhatsApp in ', 10) + custom_print("Could not install legacy WhatsApp", "red") + custom_print(install_legacy_out, "red") + countdown("Trying to restore WhatsApp in ", 10) reinstall_whatsapp() kill_me() else: install_legacy_out = subprocess.getoutput( - f'{adb} install -r -g {helpers}LegacyWhatsApp.apk') - if('Success' in install_legacy_out): - custom_print('Installation Complete.') + f"{adb} install -r -g {helpers}LegacyWhatsApp.apk" + ) + if "Success" in install_legacy_out: + custom_print("Installation Complete.") else: - custom_print('Could not install legacy WhatsApp', 'red') - custom_print(install_legacy_out, 'red') + custom_print("Could not install legacy WhatsApp", "red") + custom_print(install_legacy_out, "red") kill_me() def real_deal(sdk_version, whatsapp_apk_path_in_device, version_name): custom_print( - f'>>> I am in wa_kdbe.real_deal({sdk_version=!s}, {whatsapp_apk_path_in_device=!s}, {version_name=!s})', is_print=False) + f">>> I am in wa_kdbe.real_deal(sdk_version={sdk_version}, whatsapp_apk_path_in_device={whatsapp_apk_path_in_device}, version_name={version_name})", + is_print=False, + ) backup_whatsapp_apk(sdk_version, version_name, whatsapp_apk_path_in_device) uninstall_whatsapp(sdk_version) # Reboot here. - if(is_allowed_reboot): - if(not tcp_ip): - custom_print('\n', is_get_time=False) - custom_print('Rebooting device, please wait.', 'yellow') - os.system(f'{adb} reboot') - animate('Waiting for device to get online') - custom_input('Hit \"Enter\" key after unlocking device.', 'yellow') + if is_allowed_reboot: + if not tcp_ip: + custom_print("\n", is_get_time=False) + custom_print("Rebooting device, please wait.", "yellow") + os.system(f"{adb} reboot") + animate("Waiting for device to get online") + custom_input('Hit "Enter" key after unlocking device.', "yellow") else: custom_print( - 'Rebooting device in TCP mode break the connection and won\'t work until explicitly turned on in device and/or in PC. Skipping...', 'yellow') + "Rebooting device in TCP mode break the connection and won't work until explicitly turned on in device and/or in PC. Skipping...", + "yellow", + ) install_legacy(sdk_version) # Before backup run app - custom_print(subprocess.getoutput( - f'{adb} shell am start -n com.whatsapp/.Main')) + custom_print(subprocess.getoutput(f"{adb} shell am start -n com.whatsapp/.Main")) # custom_input('\aHit \"Enter\" key after running Legacy WhatsApp for a while. Ignore invalid date warning.', 'yellow') custom_print( - 'Running legacy WhatsApp, it may crash, do not check for updates if it prompts.') + "Running legacy WhatsApp, it may crash, do not check for updates if it prompts." + ) time.sleep(5) backup_whatsapp_data_as_ab(sdk_version) reinstall_whatsapp() - custom_print('\n', is_get_time=False) + custom_print("\n", is_get_time=False) custom_print( - '\aOur work with device has finished, it is safe to remove it now.', 'yellow') - custom_print('\n', is_get_time=False) + "\aOur work with device has finished, it is safe to remove it now.", "yellow" + ) + custom_print("\n", is_get_time=False) extract_ab(is_java_installed, is_tar_only=is_tar_only) def reinstall_whatsapp(): - custom_print('>>> I am in wa_kdbe.reinstall_whatsapp()', is_print=False) - custom_print('Reinstalling original WhatsApp.') + custom_print(">>> I am in wa_kdbe.reinstall_whatsapp()", is_print=False) + custom_print("Reinstalling original WhatsApp.") try: reinstall_whatsapp_out = subprocess.getoutput( - f'{adb} shell pm install /data/local/tmp/WhatsAppbackup.apk') - if('Success' in reinstall_whatsapp_out): - custom_print('Reinstallation complete.') + f"{adb} shell pm install /data/local/tmp/WhatsAppbackup.apk" + ) + if "Success" in reinstall_whatsapp_out: + custom_print("Reinstallation complete.") else: - custom_print('Could not install WhatsApp, install by running \"restore_whatsapp.py\" or manually installing from Play Store.\nHowever if it crashes then you have to clear storage/clear data from \"Settings \u2192 App Settings \u2192 WhatsApp\".', 'red') - custom_print(reinstall_whatsapp_out, 'red') + custom_print( + 'Could not install WhatsApp, install by running "restore_whatsapp.py" or manually installing from Play Store.\nHowever if it crashes then you have to clear storage/clear data from "Settings \u2192 App Settings \u2192 WhatsApp".', + "red", + ) + custom_print(reinstall_whatsapp_out, "red") except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") kill_me() def run_scrcpy(_is_scrcpy): custom_print( - f'>>> I am in wa_kdbe.run_scrcpy({_is_scrcpy=!s})', is_print=False) - if(_is_scrcpy): - cmd = 'bin\\scrcpy.exe --max-fps 15 -b 4M --always-on-top' if( - is_windows) else 'scrcpy --max-fps 15 -b 4M --always-on-top' - proc = subprocess.Popen(cmd.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=False) + f">>> I am in wa_kdbe.run_scrcpy(_is_scrcpy={_is_scrcpy})", is_print=False + ) + if _is_scrcpy: + cmd = ( + "bin\\scrcpy.exe --max-fps 15 -b 4M --always-on-top" + if (is_windows) + else "scrcpy --max-fps 15 -b 4M --always-on-top" + ) + proc = subprocess.Popen( + cmd.split(), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + ) proc.communicate() def show_banner(): - custom_print('>>> I am in wa_kdbe.show_banner()', is_print=False) - release_date = 'xx/xx/xxxx' + custom_print(">>> I am in wa_kdbe.show_banner()", is_print=False) + release_date = "xx/xx/xxxx" try: - release_date_file = open('non_essentials/DATE', 'r') + release_date_file = open("non_essentials/DATE", "r") release_date = release_date_file.readline() release_date_file.close() except Exception as e: custom_print(e, is_print=False) - banner_content = f''' + banner_content = f""" ================================================================================ ======== Current release date: {release_date.strip()} ======== ======== ======== @@ -320,26 +372,26 @@ def show_banner(): ======== `8b d8'8b d8' 88 88 88 `88. 88 .8D 88 8D 88. ======== ======== `8b8' `8d8' YP YP YP YD Y8888D' Y8888P' Y88888P ======== ======== ======== -================================================================================''' +================================================================================""" - intro_a = ''' + intro_a = """ ============ WhatsApp Key / Database Extrator for non-rooted Android ===========\n ================================================================================ -=== ===''' +=== ===""" - intro_b = '''=== xxxxx PLEASE TAKE WHATSAPP CHAT BACKUP BEFORE GETTING STARTED. xxxxx ===''' + intro_b = """=== xxxxx PLEASE TAKE WHATSAPP CHAT BACKUP BEFORE GETTING STARTED. xxxxx ===""" - intro_c = '''=== === + intro_c = """=== === === For that go to \"WhatsApp settings \u2192 Chat Settings \u2192 Chat Backup\" === === here take a local backup. Prepare for Worst. === -=== ===''' +=== ===""" - intro_d = '''=== Also if you see a folder \"Android/media/com.whatsapp\" copy it somewhere === + intro_d = """=== Also if you see a folder \"Android/media/com.whatsapp\" copy it somewhere === === safe. New versions of WhatsApp are saving data here INCLUDING IMAGES === === AND VIDEOS. I try to save it while uninstalling WhatsApp but === -=== YOU CAN NEVER BE TOO SAFE. ===''' +=== YOU CAN NEVER BE TOO SAFE. ===""" - intro_e = '''=== === + intro_e = """=== === === This script can extract your WhatsApp msgstore.db (non crypt12, === === un-encrypted file) and your \"key\" file from \"/data/data/com.whatsapp\" === === directory in Android 4.0+ device without root access. However you need === @@ -356,60 +408,89 @@ def show_banner(): === Script by: Yuvraj Raghuvanshi === === Github.com/YuvrajRaghuvanshiS === ================================================================================ - ''' - custom_print(banner_content, 'green', ['bold'], False) - custom_print(intro_a, 'green', ['bold'], False) - custom_print(intro_b, 'red', ['bold'], False) - custom_print(intro_c, 'green', ['bold'], False) - custom_print(intro_d, 'red', ['bold'], False) - custom_print(intro_e, 'green', ['bold'], False) + """ + custom_print(banner_content, "green", ["bold"], False) + custom_print(intro_a, "green", ["bold"], False) + custom_print(intro_b, "red", ["bold"], False) + custom_print(intro_c, "green", ["bold"], False) + custom_print(intro_d, "red", ["bold"], False) + custom_print(intro_e, "green", ["bold"], False) def uninstall_whatsapp(sdk_version): custom_print( - f'>>> I am in wa_kdbe.uninstall_whatsapp({sdk_version=!s})', is_print=False) - if(sdk_version >= 23): + f">>> I am in wa_kdbe.uninstall_whatsapp(sdk_version={sdk_version})", + is_print=False, + ) + if sdk_version >= 23: try: - custom_print('Uninstalling WhatsApp, skipping data.') + custom_print("Uninstalling WhatsApp, skipping data.") uninstall_out = subprocess.getoutput( - f'{adb} shell pm uninstall -k com.whatsapp') - if('Success' in uninstall_out): - custom_print('Uninstalled.') + f"{adb} shell pm uninstall -k com.whatsapp" + ) + if "Success" in uninstall_out: + custom_print("Uninstalled.") else: - custom_print('Could not uninstall WhatsApp.', 'red') - custom_print(uninstall_out, 'red') + custom_print("Could not uninstall WhatsApp.", "red") + custom_print(uninstall_out, "red") kill_me() except Exception as e: - custom_print(e, 'red') + custom_print(e, "red") kill_me() def usb_mode(): - custom_print('>>> I am in wa_kdbe.usb_mode()', is_print=False) - after_connect_return_code, sdk_version, whatsapp_apk_path_in_device, version_name = handler( - adb) - real_deal(sdk_version, whatsapp_apk_path_in_device, - version_name) if after_connect_return_code == 1 else kill_me() + custom_print(">>> I am in wa_kdbe.usb_mode()", is_print=False) + ( + after_connect_return_code, + sdk_version, + whatsapp_apk_path_in_device, + version_name, + ) = handler(adb) + real_deal( + sdk_version, whatsapp_apk_path_in_device, version_name + ) if after_connect_return_code == 1 else kill_me() if __name__ == "__main__": from datetime import datetime + dt = datetime.now() custom_print( - f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', is_get_time=False, is_print=False) + f'\n\n\n====== Logging starts here. ====== \nFile: {os.path.basename(__file__)}\nDate: {dt.strftime("%A %d/%m/%Y, %H:%M:%S")}\nIf you see any password here then do let know @github.com/YuvrajRaghuvanshiS/WhatsApp-Key-Database-Extractor\n\n\n', + is_get_time=False, + is_print=False, + ) parser = argparse.ArgumentParser() - parser.add_argument('-ar', '--allow-reboot', action='store_true', - help='Allow reboot of device before installation of LegacyWhatsApp.apk to prevent some issues like [INSTALL_FAILED_VERSION_DOWNGRADE]') - parser.add_argument('-tip', '--tcp-ip', - help='Connects to a remote device via TCP mode.') - parser.add_argument('-tp', '--tcp-port', default='5555', - help='Port number to connect to. Default: 5555') - parser.add_argument('-s', '--scrcpy', action='store_true', - help='Run ScrCpy to see and control Android device.') - parser.add_argument('-to', '--tar-only', action='store_true', - help='Get entire WhatsApp\'s data in \".tar\" file instead of just getting few important files.') + parser.add_argument( + "-ar", + "--allow-reboot", + action="store_true", + help="Allow reboot of device before installation of LegacyWhatsApp.apk to prevent some issues like [INSTALL_FAILED_VERSION_DOWNGRADE]", + ) + parser.add_argument( + "-tip", "--tcp-ip", help="Connects to a remote device via TCP mode." + ) + parser.add_argument( + "-tp", + "--tcp-port", + default="5555", + help="Port number to connect to. Default: 5555", + ) + parser.add_argument( + "-s", + "--scrcpy", + action="store_true", + help="Run ScrCpy to see and control Android device.", + ) + parser.add_argument( + "-to", + "--tar-only", + action="store_true", + help='Get entire WhatsApp\'s data in ".tar" file instead of just getting few important files.', + ) args = parser.parse_args() is_allowed_reboot = args.allow_reboot @@ -417,20 +498,20 @@ def usb_mode(): tcp_port = args.tcp_port is_scrcpy = args.scrcpy is_tar_only = args.tar_only - if(tcp_ip): - adb_device_serial_id = device_id.init('TCP', tcp_ip, tcp_port) + if tcp_ip: + adb_device_serial_id = device_id.init("TCP", tcp_ip, tcp_port) else: - adb_device_serial_id = device_id.init('USB') - if(not adb_device_serial_id): + adb_device_serial_id = device_id.init("USB") + if not adb_device_serial_id: kill_me() # Global command line helpers - tmp = 'tmp/' - helpers = 'helpers/' - if(is_windows): - adb = f'bin\\adb.exe -s {adb_device_serial_id}' + tmp = "tmp/" + helpers = "helpers/" + if is_windows: + adb = f"bin\\adb.exe -s {adb_device_serial_id}" else: - adb = f'adb -s {adb_device_serial_id}' + adb = f"adb -s {adb_device_serial_id}" with concurrent.futures.ThreadPoolExecutor() as executor: f1 = executor.submit(main)