def list_devices(host="127.0.0.1", port=5037): client = AdbClient(host=host, port=port) try: client.version() except RuntimeError: # Can't connect to the adb server, try to start the adb server by command line. Adb._start_adb_server() return client.devices()
def get_devices(): for attempt in range(2): try: client = AdbClient(host="127.0.0.1", port=5037) client.version() # a random call to check if adb server is up except Exception as err: print(str(err)) print("⚡ Starting ADB server...") subprocess.run(["adb", "start-server"]) devices = client.devices() if len(devices) == 0: print("⚠️ no devices connected!") return devices
class AdbUtils: def __init__(self, ip="127.0.0.1", port=5037): subprocess.run(["adb", "devices"]) self.client = AdbClient(host=ip, port=port) self.devices = [] def get_client_version(self): return self.client.version() def list_all_devices(self): for device in self.client.devices(): self.devices.append(device.serial) return self.devices # Exemple "example.package" def is_installed_apk(self, device, apk_package): return device.is_installed(apk_package) def install_apk(self, device, apk_path): device.install(apk_path) # Exemple "example.package" def uninstall_apk(self, device, apk_package): device.install(apk_package) return self.is_installed_apk(device, apk_package) def get_device_name(self, device): model = device.shell("getprop ro.product.model") manufacturer = device.shell("getprop ro.product.manufacturer") full_name = manufacturer + " " + model return full_name.replace("\n", "").replace("\r", "") def _dump_logcat(connection): while True: data = connection.read(1024) if not data: break print(data.decode('utf-8')) connection.close() def get_device_logcat(self, device): return device.shell("logcat", handler=self._dump_logcat) def get_screen_shot(self, device): result = device.screencap() with open( datetime.datetime.now().replace(" ", "").replace( "-", "").replace(":", "").replace(".", "") + ".png", "wb") as fp: fp.write(result)
def client(request): logger.info("Connecting to adb server {}:{}...".format(adb_host, adb_port)) client = AdbClient(host=adb_host, port=adb_port) def try_to_connect_to_adb_server(): try: client.version() return True except Exception: return False wait_until_true(try_to_connect_to_adb_server, timeout=60, description="Try to connect to adb server {}:{}".format(adb_host, adb_port)) logger.info("Adb server version: {}".format(client.version())) return client
class Adb(object): def __init__(self, serial=None, host="127.0.0.1", port=5037): self._serial = serial self._client = AdbClient(host=host, port=port) try: self._client.version() except RuntimeError: # Can't connect to the adb server, try to start the adb server by command line. self._start_adb_server() if self._serial: self._device = self._client.device(serial) else: # The serial can be None only when there is only one device/emulator. devices = self._client.devices() if len(devices) == 0: raise RuntimeError("Can't find any android device/emulator") elif len(devices) > 1: raise RuntimeError( "more than one device/emulator, please specify the serial number" ) else: device = devices[0] self._serial = device.get_serial_no() self._device = device @staticmethod def list_devices(host="127.0.0.1", port=5037): client = AdbClient(host=host, port=port) try: client.version() except RuntimeError: # Can't connect to the adb server, try to start the adb server by command line. Adb._start_adb_server() return client.devices() @staticmethod def _start_adb_server(): adb_path = whichcraft.which("adb") if adb_path is None: raise EnvironmentError( "Can't find the adb, please install adb on your PC") cmd = [adb_path, "start-server"] cmdline = subprocess.list2cmdline(cmd) try: return subprocess.check_output(cmdline, stderr=subprocess.STDOUT, shell=True).decode('utf-8') except subprocess.CalledProcessError as e: raise EnvironmentError("subprocess", cmdline, e.output.decode('utf-8', errors='ignore')) def devices(self, states=['device', 'offline']): """ Returns: [($serial1, "device"), ($serial2, "offline")] """ # TODO: not really checking anything return [(d, "device") for d in self.list_devices()] output = subprocess.check_output([self.adb_path(), 'devices']) pattern = re.compile(r'(?P<serial>[^\s]+)\t(?P<status>device|offline)') matches = pattern.findall(output.decode()) return [(m[0], m[1]) for m in matches] @property def serial(self): return self._serial def forward(self, local, remote, rebind=True): if isinstance(local, int): local = 'tcp:%d' % local if isinstance(remote, int): remote = 'tcp:%d' % remote return self._device.forward(local, remote, norebind=not rebind) def forward_list(self): """ Only return tcp:<int> format forwards Returns: { "{RemotePort}": "{LocalPort}" } """ forward_list = self._device.list_forward() ret = {} for local, remote in forward_list.items(): ltype, lport = local.split(":") rtype, rport = remote.split(":") if ltype == "tcp" and rtype == "tcp": ret[int(rport)] = int(lport) return ret def forward_port(self, remote_port): forwards = self.forward_list() lport = forwards.get(remote_port) if lport: return lport free_port = find_free_port() self.forward(free_port, remote_port) return free_port def shell(self, *args, **kwargs): return self._device.shell(" ".join(args)) def getprop(self, prop): return self.shell('getprop', prop).strip() def push(self, src, dst, mode=0o644): self._device.push(src, dst, mode=mode) def install(self, apk_path): sdk = self.getprop('ro.build.version.sdk') if int(sdk) <= 23: self._device.install(apk_path, reinstall=True, downgrade=True) return try: # some device is missing -g self._device.install(apk_path, reinstall=True, downgrade=True, grand_all_permissions=True) except InstallError: self._device.install(apk_path, reinstall=True, downgrade=True) def uninstall(self, pkg_name): return self._device.uninstall(pkg_name) def package_info(self, pkg_name): output = self.shell('dumpsys', 'package', pkg_name) m = re.compile(r'versionName=(?P<name>[\d.]+)').search(output) version_name = m.group('name') if m else None m = re.search(r'PackageSignatures\{(.*?)\}', output) signature = m.group(1) if m else None if version_name is None and signature is None: return None return dict(version_name=version_name, signature=signature)
def record_event(device, filepath, timeout=5): global event, cmd event = "" cmd = "" signal.alarm(timeout) try: k = device.shell("getevent /dev/input/event1", handler=event_handler) except: pass print("Event recorded") # print(event) generate_cmd() # print(cmd) write_cmd(filepath) signal.signal(signal.SIGALRM, handler=sig_handler) if __name__ == "__main__": client = AdbClient(host="127.0.0.1", port=5037) print(client.version()) device = client.device("10.42.0.231:5555") signal.signal(signal.SIGALRM, handler=sig_handler) record_event(device, "cmd.sh") play_event(device, "cmd.sh") # print(event)
def main(): phone = None source_device = None sdk = AndroidSDK() parser = argparse.ArgumentParser(prog='WhatsDump') parser.add_argument( '--install-sdk', action='store_true', help='Download & extract latest Android SDK emulator packages') parser.add_argument('--msgstore', help='Location of msgstore database to decrypt') parser.add_argument( '--wa-phone', help= 'WhatsApp phone number associated with msgstore database from which ' 'you will receive verification SMS (with prefix, ex. +393387182291)') parser.add_argument('--wa-verify', choices=['sms', 'call'], help='Phone verification method to use') parser.add_argument('--verbose', action='store_true', help='Show verbose (debug) output') parser.add_argument('--show-emulator', action='store_true', help='Show emulator screen (by default headless)') parser.add_argument( '--no-accel', action='store_true', help='Disable hardware acceleration (very slow emulator!)') args = parser.parse_args() print(''' _ _ _ _ ______ | | | | | | | | _ \ | | | | |__ __ _| |_ ___| | | |_ _ _ __ ___ _ __ | |/\| | '_ \ / _` | __/ __| | | | | | | '_ ` _ \| '_ \ \ /\ / | | | (_| | |_\__ \ |/ /| |_| | | | | | | |_) | \/ \/|_| |_|\__,_|\__|___/___/ \__,_|_| |_| |_| .__/ | | |_| v0.1 beta ''') # Setup logging logging.basicConfig(format='[%(levelname)s] %(message)s', stream=sys.stdout) logger.setLevel(logging.DEBUG if args.verbose else logging.INFO) # TODO: CHECK IF JAVA IS INSTALLED # SDK Checks is_avd_installed = sdk.is_avd_installed() if args.install_sdk: if is_avd_installed: logger.error( "WhatsDump AVD already installed! Remove android-sdk/ directory to reinstall Android SDK" ) exit(1) # download&install if not sdk.install(): logger.error('Failed to install Android SDK') exit(1) logger.info('\nAndroid AVD successfully installed') exit(0) else: if not is_avd_installed: logger.error( "Cannot find WhatsDump AVD; install Android SDK and emulator packages with --install-sdk" ) exit(1) # Connect / Start ADB server adb_client = AdbClient() try: logger.info("Connected to ADB (version %d) @ 127.0.0.1:5037" % adb_client.version()) except: logger.info("Attempting to start ADB server...") if sdk.start_adb(): logger.info("ADB server started successfully") adb_client = AdbClient() logger.info("Connected to ADB (version %d) @ 127.0.0.1:5037" % adb_client.version()) else: logger.error('Could not connect/start ADB server') exit(1) # Require msgstore or connected device if args.msgstore: # Check if file exists if not os.path.isfile(args.msgstore): logger.error( "Msgstore location is not valid (file does not exist)") exit(1) else: logger.info( "Msgstore location not provided, attempting to find connected devices with ADB...\n" ) devices = adb_client.devices() i = 0 # If no devices and no msgstore, quit if len(devices) == 0: logger.error("Cannot find any connected devices") exit(1) # Show all devices for device in devices: print("\t[%d] %s (%s)" % (i, device.serial, device.shell('getprop ro.product.name').rstrip())) i += 1 print('\n') while source_device is None: dev_index = int( raw_input( "\n>> Which device number you want to extract msgstore from?: " )) if dev_index < 0 or dev_index + 1 > len(devices): continue source_device = devices[dev_index] print('\n') # Validate required phone if not args.wa_phone: logger.error( "Please provide the phone number associated with msgstore") exit(1) else: # Add "+" if not given if args.wa_phone[0] != '+': args.wa_phone = '+' + args.wa_phone try: phone = phonenumbers.parse(args.wa_phone) except NumberParseException: pass if not phone: logger.error("Provided phone number is NOT valid") exit(1) if not args.wa_verify: logger.error("Please provide a WhatsApp verification method") exit(1) # recap if source_device: logger.info('Extract WhatsApp database from device >> %s', source_device.serial) else: logger.info('Using msgstore database from path: %s', args.msgstore) logger.info('Using WhatsApp phone number: +%d %d', phone.country_code, phone.national_number) logger.info('Using WhatsApp verification method: %s', args.wa_verify.upper()) yn = raw_input("\n>> Continue? (y/n): ") if yn != 'y': exit(0) # create phone directory tree where to store results dst_path = os.path.join(os.path.abspath('output'), str(phone.national_number)) if not os.path.exists(dst_path): try: os.makedirs(dst_path) except OSError: logging.error('Cannot create output directory tree') exit(1) log_formatter = logging.Formatter( "%(asctime)s - [%(levelname)s]: %(message)s") file_handler = logging.FileHandler(os.path.join(dst_path, 'log.txt')) file_handler.setFormatter(log_formatter) logger.addHandler(file_handler) # Extract msgstore.db from source device, if any msgstore_path = args.msgstore if msgstore_path: logger.info('Provided msgstore.db SHA-256 hash: %s', sha256(args.msgstore)) if source_device: logger.info( 'Extracting msgstore.db.crypt from phone to output/%ld/ ...' % phone.national_number) wa = WhatsApp(source_device) msgstore_path = wa.extract_msgstore(dst_path) if not msgstore_path: logger.error( 'Could not find/extract msgstore database from device (is WhatsApp installed?)' ) exit(1) logger.info('Extracted msgstore.db SHA-256 hash: %s', sha256(msgstore_path)) # Start emulator and connect to it logger.info('Starting emulator...') if args.no_accel: logger.warn( 'Hardware acceleration disabled! Device might be very slow') emulator_device = sdk.start_emulator(adb_client, args.show_emulator, args.no_accel) if not emulator_device: logger.error('Could not start emulator!') exit(1) if args.show_emulator: logger.info('Do not interact with the emulator!') logger.info( 'Trying to register phone on emulator... (may take few minutes)') # Attempt to register phone using provided msgstore wa_emu = WhatsApp(emulator_device) try: wa_emu.register_phone(msgstore_path, phone.country_code, phone.national_number, args.wa_verify, wa_code_callback) except WaException, e: logger.error('Exception in verification: %s', e.reason) exit(1)
def main(): phone = None source_device = None sdk = AndroidSDK() parser = argparse.ArgumentParser(prog="WhatsDump") parser.add_argument( "--install-sdk", action="store_true", help="Download & extract latest Android SDK emulator packages") parser.add_argument("--msgstore", help="Location of msgstore database to decrypt") parser.add_argument( "--wa-phone", help= "WhatsApp phone number associated with msgstore database from which " "you will receive verification SMS (with prefix, ex. +393387182291)") parser.add_argument("--wa-verify", choices=["sms", "call"], help="Phone verification method to use") parser.add_argument("--verbose", action="store_true", help="Show verbose (debug) output") parser.add_argument("--show-emulator", action="store_true", help="Show emulator screen (by default headless)") parser.add_argument( "--no-accel", action="store_true", help="Disable hardware acceleration (very slow emulator!)") args = parser.parse_args() print(""" _ _ _ _ ______ | | | | | | | | _ \ | | | | |__ __ _| |_ ___| | | |_ _ _ __ ___ _ __ | |/\| | '_ \ / _` | __/ __| | | | | | | '_ ` _ \| '_ \ \ /\ / | | | (_| | |_\__ \ |/ /| |_| | | | | | | |_) | \/ \/|_| |_|\__,_|\__|___/___/ \__,_|_| |_| |_| .__/ | | |_| v0.2 beta """) # Setup logging logging.basicConfig( format= "%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s]: %(message)s", datefmt="%d/%m/%Y %H:%M:%S", stream=sys.stdout) logger.setLevel(logging.DEBUG if args.verbose else logging.INFO) # TODO: CHECK IF JAVA IS INSTALLED # SDK Checks is_avd_installed = sdk.is_avd_installed() if args.install_sdk: if is_avd_installed: logger.error( "WhatsDump AVD already installed! Remove android-sdk/ directory to reinstall Android SDK" ) sys.exit(1) # download&install if not sdk.install(): logger.error("Failed to install Android SDK") sys.exit(1) logger.info("\nAndroid AVD successfully installed") sys.exit(0) else: if not is_avd_installed: logger.error( "Cannot find WhatsDump AVD; install Android SDK and emulator packages with --install-sdk" ) sys.exit(1) # Connect / Start ADB server adb_client = AdbClient() try: logger.info("Connected to ADB (version %d) @ 127.0.0.1:5037" % adb_client.version()) except: logger.info("Attempting to start ADB server...") if sdk.start_adb(): logger.info("ADB server started successfully") adb_client = AdbClient() logger.info("Connected to ADB (version %d) @ 127.0.0.1:5037" % adb_client.version()) else: logger.error("Could not connect/start ADB server") sys.exit(1) # Require msgstore or connected device if args.msgstore: # Check if file exists if not os.path.isfile(args.msgstore): logger.error( "Msgstore location is not valid (file does not exist)") sys.exit(1) else: logger.info( "Msgstore location not provided, attempting to find connected devices with ADB...\n" ) devices = adb_client.devices() i = 0 # If no devices and no msgstore, quit if len(devices) == 0: logger.error("Cannot find any connected devices") sys.exit(1) # Show all devices for device in devices: print("\t[%d] %s (%s)" % (i, device.serial, device.shell("getprop ro.product.name").rstrip())) i += 1 print("\n") while source_device is None: dev_index = int( input( "\n>> Which device number you want to extract msgstore from?: " )) if dev_index < 0 or dev_index + 1 > len(devices): continue source_device = devices[dev_index] print("\n") # Validate required phone if not args.wa_phone: logger.error( "Please provide the phone number associated with msgstore") sys.exit(1) else: # Add "+" if not given if args.wa_phone[0] != "+": args.wa_phone = "+" + args.wa_phone try: phone = phonenumbers.parse(args.wa_phone) except NumberParseException: pass if not phone: logger.error("Provided phone number is NOT valid") sys.exit(1) if not args.wa_verify: logger.error("Please provide a WhatsApp verification method") sys.exit(1) # recap if source_device: logger.info("Extract WhatsApp database from device >> %s", source_device.serial) else: logger.info("Using msgstore database from path: %s", args.msgstore) logger.info("Using WhatsApp phone number: +%d %d", phone.country_code, phone.national_number) logger.info("Using WhatsApp verification method: %s", args.wa_verify.upper()) # yn = input("\n>> Continue? (y/n): ") # if yn != 'y': # sys.exit(0) # create phone directory tree where to store results dst_path = os.path.join(os.path.abspath("output"), str(phone.national_number)) if not os.path.exists(dst_path): try: os.makedirs(dst_path) except OSError: logging.error("Cannot create output directory tree") sys.exit(1) log_formatter = logging.Formatter( "%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s]: %(message)s", datefmt="%d/%m/%Y %H:%M:%S") file_handler = logging.FileHandler(os.path.join(dst_path, "log.txt")) file_handler.setFormatter(log_formatter) logger.addHandler(file_handler) # Extract msgstore.db from source device, if any msgstore_path = args.msgstore if msgstore_path: logger.info("Provided msgstore.db SHA-256 hash: %s", sha256(args.msgstore)) if source_device: logger.info( "Extracting msgstore.db.crypt from phone to output/%ld/ ..." % phone.national_number) wa = WhatsApp(source_device) msgstore_path = wa.extract_msgstore(dst_path) if not msgstore_path: logger.error( "Could not find/extract msgstore database from device (is WhatsApp installed?)" ) sys.exit(1) logger.info("Extracted msgstore.db SHA-256 hash: %s", sha256(msgstore_path)) # Start emulator and connect to it logger.info("Starting emulator...") if args.no_accel: logger.warn( "Hardware acceleration disabled! Device might be very slow") emulator_device = sdk.start_emulator(adb_client, args.show_emulator, args.no_accel) if not emulator_device: logger.error("Could not start emulator!") sys.exit(1) if args.show_emulator: logger.info("Do not interact with the emulator!") logger.info( "Trying to register phone on emulator... (may take few minutes)") # Attempt to register phone using provided msgstore wa_emu = WhatsApp(emulator_device) sdk.adb_root() # Allowing adb as root time.sleep(10) try: wa_emu.register_phone(msgstore_path, phone.country_code, phone.national_number) # Verify by call or SMS if args.wa_verify == "sms": logger.info("You should receive a SMS by WhatsApp soon") wa_emu._verify_by_sms(wa_code_callback) else: logger.info("You should receive a call by WhatsApp soon") wa_emu._verify_by_call(wa_code_callback) wa_emu.complete_registration(phone.country_code, phone.national_number) except WaException as e: logger.info("Exception in verification: %s", e.reason) code.interact(local=locals()) sys.exit(1) logger.info("Phone registered successfully!") logger.info("Extracting key...") # Extract private key if not wa_emu.extract_priv_key(dst_path): logger.error("Could not extract private key!") sys.exit(1) logger.info("Private key extracted in %s", os.path.join(dst_path, "key"))