Esempio n. 1
0
    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()
Esempio n. 2
0
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
Esempio n. 3
0
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)
Esempio n. 4
0
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
Esempio n. 5
0
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)
Esempio n. 6
0
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)
Esempio n. 7
0
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)
Esempio n. 8
0
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"))