예제 #1
0
 def __init__(self, id_or_adb_backend=None):
     '''获取一个Android设备,获取成功后则独占该设备。
     
     :param device_id: 获取制定设备id的Android设备。如果为空则任意获取一台空闲设备。
     '''
     self._device = None
     if isinstance(id_or_adb_backend, str):
         adb_backend = LocalADBBackend.open_device(id_or_adb_backend)
     elif not id_or_adb_backend:
         local_device_list = LocalDeviceProvider.list()
         if not local_device_list: raise RuntimeError('No local device found')
         adb_backend = LocalADBBackend.open_device(local_device_list[0])
     else:
         adb_backend = id_or_adb_backend
     self._adb = ADB.open_device(adb_backend)
     self._device_driver = DeviceDriver(self._adb)
     Device.device_list.append(self)
예제 #2
0
def copy_android_driver(device_id_or_adb,
                        force=False,
                        root_path=None,
                        enable_acc=True):
    """测试前的测试桩拷贝
    """
    from qt4a.androiddriver.adb import ADB

    if isinstance(device_id_or_adb, ADB):
        adb = device_id_or_adb
    else:
        adb = ADB.open_device(device_id_or_adb)

    if not root_path:
        current_path = os.path.abspath(__file__)
        if not os.path.exists(current_path) and ".egg" in current_path:
            # in egg
            egg_path = current_path
            while not os.path.exists(egg_path):
                egg_path = os.path.dirname(egg_path)
            assert egg_path.endswith(".egg")
            root_path = os.path.join(tempfile.mkdtemp(), "tools")
            extract_from_zipfile(egg_path, "qt4a/androiddriver/tools",
                                 root_path)
        else:
            root_path = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), "tools")
    dst_path = "/data/local/tmp/qt4a/"

    current_version_file = os.path.join(root_path, "version.txt")
    f = open(current_version_file, "r")
    current_version = int(f.read())
    f.close()

    if not force:
        version_file = dst_path + "version.txt"
        version = adb.run_shell_cmd("cat %s" % version_file)

        if (version and not "No such file or directory" in version
                and current_version <= int(version)):
            install_qt4a_helper(adb, root_path)  # 避免QT4A助手被意外删除的情况
            # 不需要拷贝测试桩
            logger.warn("忽略本次测试桩拷贝:当前版本为%s,设备中版本为%s" %
                        (current_version, int(version)))
            return

    try:
        adb.chmod(dst_path[:-1], "777")
    except:
        pass

    rooted = adb.is_rooted()

    cpu_abi = adb.get_cpu_abi()
    print("Current CPU arch: %s" % cpu_abi)
    # use_pie = False
    # if adb.get_sdk_version() >= 21 and cpu_abi != "arm64-v8a":
    #     use_pie = True

    file_list = [
        os.path.join(cpu_abi, "droid_inject"),
        os.path.join(cpu_abi, "libdexloader.so"),
        os.path.join(cpu_abi, "screenkit"),
        "inject",
        "AndroidSpy.jar",
        "SpyHelper.jar",
        "SpyHelper.sh",
    ]
    if cpu_abi == "arm64-v8a":
        file_list.append(os.path.join(cpu_abi, "droid_inject64"))
        file_list.append(os.path.join(cpu_abi, "libdexloader64.so"))
        file_list.append("inject64")
    if adb.get_sdk_version() >= 21:
        file_list.append(os.path.join(cpu_abi, "libandroidhook_art.so"))

    if rooted and adb.is_selinux_opened():
        # 此时如果还是开启状态说明关闭selinux没有生效,主要是三星手机上面
        adb.run_shell_cmd("rm -r %s" % dst_path, True)
        # adb.run_shell_cmd('chcon u:object_r:shell_data_file:s0 %slibdexloader.so' % dst_path, True)  # 恢复文件context,否则拷贝失败
        # adb.run_shell_cmd('chcon u:object_r:shell_data_file:s0 %slibandroidhook.so' % dst_path, True)

    for file in file_list:
        file_path = os.path.join(root_path, file)
        # if use_pie and not "." in file and os.path.exists(file_path + "_pie"):
        #     file_path += "_pie"
        if not os.path.exists(file_path):
            continue
        save_name = os.path.split(file)[-1]
        if save_name.endswith("_art.so"):
            save_name = save_name.replace("_art", "")
        adb.push_file(file_path, dst_path + save_name)

    adb.chmod("%sdroid_inject" % dst_path, 755)
    adb.chmod("%sinject" % dst_path, 755)
    adb.chmod("%sscreenkit" % dst_path, 755)
    adb.run_shell_cmd("ln -s %sscreenkit %sscreenshot" % (dst_path, dst_path))

    if cpu_abi == "arm64-v8a":
        adb.chmod("%sdroid_inject64" % dst_path, 755)
        adb.chmod("%sinject64" % dst_path, 755)

    try:
        print(adb.run_shell_cmd("rm -R %scache" % dst_path,
                                rooted))  # 删除目录 rm -rf
    except RuntimeError as e:
        logger.warn("%s" % e)
    # logger.info(adb.run_shell_cmd('mkdir %scache' % (dst_path), True)) #必须使用root权限,不然生成odex文件会失败

    adb.mkdir("%scache" % (dst_path), 777)

    install_qt4a_helper(adb, root_path)

    version_file_path = os.path.join(root_path, "version.txt")
    dst_version_file_path = dst_path + os.path.split(version_file_path)[-1]
    adb.push_file(version_file_path, dst_version_file_path + ".tmp")  # 拷贝版本文件

    if rooted and adb.is_selinux_opened():
        # 此时如果还是开启状态说明关闭selinux没有生效,主要是三星手机上面
        # 获取sdcars context
        if adb.get_sdk_version() >= 23:
            sdcard_path = adb.get_sdcard_path()
            result = adb.run_shell_cmd("ls -Z %s" % sdcard_path)
            # u:object_r:media_rw_data_file:s0 u:object_r:rootfs:s0
            pattern = re.compile(r"\s+(u:object_r:.+:s0)\s+")
            ret = pattern.search(result)
            if not ret:
                raise RuntimeError("get sdcard context failed: %s" % result)
            context = ret.group(1)
            logger.info("sdcard context is %s" % context)
            adb.run_shell_cmd("chcon %s %s" % (context, dst_path),
                              True)  # make app access
            adb.run_shell_cmd(
                "chcon u:object_r:app_data_file:s0 %sSpyHelper.jar" % dst_path,
                True)
            adb.run_shell_cmd(
                "chcon u:object_r:app_data_file:s0 %sSpyHelper.sh" % dst_path,
                True)
            # 不修改文件context无法加载so
            adb.run_shell_cmd(
                "chcon u:object_r:system_file:s0 %slibdexloader.so" % dst_path,
                True)
            adb.run_shell_cmd(
                "chcon u:object_r:app_data_file:s0 %slibandroidhook.so" %
                dst_path, True)
            adb.run_shell_cmd(
                "chcon %s %sAndroidSpy.jar" % (context, dst_path), True)
            adb.run_shell_cmd("chcon %s %scache" % (context, dst_path), True)
        else:
            # 不修改文件context无法加载so
            adb.run_shell_cmd(
                "chcon u:object_r:app_data_file:s0 %slibdexloader.so" %
                dst_path, True)
            adb.run_shell_cmd(
                "chcon u:object_r:app_data_file:s0 %slibandroidhook.so" %
                dst_path, True)
            adb.run_shell_cmd(
                "chcon u:object_r:app_data_file:s0 %scache" % dst_path, True)

    if rooted:
        if adb.get_sdk_version() < 24:
            # 7.0以上发现生成的dex与运行时生成的dex有差别,可能导致crash
            logger.info(
                adb.run_shell_cmd(
                    "sh %sSpyHelper.sh loadDex %sAndroidSpy.jar %scache" %
                    (dst_path, dst_path, dst_path),
                    rooted,
                ))
            adb.chmod("%scache/AndroidSpy.dex" % dst_path, 666)
    else:
        if not "usage:" in adb.run_shell_cmd("sh %sSpyHelper.sh" % dst_path):
            adb.mkdir("%scache/dalvik-cache" % dst_path, 777)

    if rooted and adb.is_selinux_opened() and adb.get_sdk_version() >= 23:
        # 提升权限
        try:
            adb.list_dir("/system/bin/app_process32")
        except RuntimeError:
            adb.copy_file("/system/bin/app_process",
                          "%sapp_process" % dst_path)
        else:
            adb.copy_file("/system/bin/app_process32",
                          "%sapp_process" % dst_path)
        adb.chmod("%sapp_process" % dst_path, 755)
        adb.run_shell_cmd(
            "chcon u:object_r:system_file:s0 %sapp_process" % dst_path, True)

    adb.run_shell_cmd(
        "mv %s %s" % (dst_version_file_path + ".tmp", dst_version_file_path),
        rooted)

    # 同步手机时间
    device_driver = DeviceDriver(adb)
    try:
        input_method = "com.test.androidspy/.service.QT4AKeyboardService"
        device_driver.modify_system_setting("secure", "enabled_input_methods",
                                            input_method)
        device_driver.modify_system_setting("secure", "default_input_method",
                                            input_method)
        if enable_acc:
            device_driver.modify_system_setting(
                "secure",
                "enabled_accessibility_services",
                "com.test.androidspy/com.test.androidspy.service.QT4AAccessibilityService",
            )
            device_driver.modify_system_setting("secure",
                                                "accessibility_enabled", 1)
    except:
        logger.exception("set default input method failed")
    try:
        device_driver.modify_system_setting("system", "time_12_24", 24)
        device_driver.modify_system_setting("system", "screen_off_timeout",
                                            600 * 1000)
    except:
        logger.exception("set system time failed")
예제 #3
0
def copy_android_driver(device_id_or_adb,
                        force=False,
                        root_path=None,
                        enable_acc=True):
    '''测试前的测试桩拷贝
    '''
    from qt4a.androiddriver.adb import ADB
    from qt4a.androiddriver.util import AndroidPackage, version_cmp

    if isinstance(device_id_or_adb, ADB):
        adb = device_id_or_adb
    else:
        adb = ADB.open_device(device_id_or_adb)

    if not root_path:
        current_path = os.path.abspath(__file__)
        if not os.path.exists(current_path) and '.egg' in current_path:
            # in egg
            egg_path = current_path
            while not os.path.exists(egg_path):
                egg_path = os.path.dirname(egg_path)
            assert (egg_path.endswith('.egg'))
            root_path = os.path.join(tempfile.mkdtemp(), 'tools')
            extract_from_zipfile(egg_path, 'qt4a/androiddriver/tools',
                                 root_path)
        else:
            root_path = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), 'tools')
    dst_path = '/data/local/tmp/qt4a/'

    current_version_file = os.path.join(root_path, 'version.txt')
    f = open(current_version_file, 'r')
    current_version = int(f.read())
    f.close()

    if not force:
        version_file = dst_path + 'version.txt'
        version = adb.run_shell_cmd('cat %s' % version_file)

        if version and not 'No such file or directory' in version and current_version <= int(
                version):
            # 不需要拷贝测试桩
            logger.warn('忽略本次测试桩拷贝:当前版本为%s,设备中版本为%s' %
                        (current_version, int(version)))
            return

    try:
        adb.chmod(dst_path[:-1], '777')
    except:
        pass

    rooted = adb.is_rooted()

    cpu_abi = adb.get_cpu_abi()
    print('Current CPU arch: %s' % cpu_abi)
    use_pie = False
    if adb.get_sdk_version() >= 21 and cpu_abi != 'arm64-v8a':
        use_pie = True

    file_list = [
        os.path.join(cpu_abi, 'droid_inject'),
        os.path.join(cpu_abi, 'libdexloader.so'),
        os.path.join(cpu_abi, 'screenkit'),
        os.path.join(cpu_abi, 'libandroidhook.so'), 'inject', 'AndroidSpy.jar',
        'SpyHelper.jar', 'SpyHelper.sh'
    ]

    if cpu_abi == 'arm64-v8a':
        file_list.append(os.path.join(cpu_abi, 'droid_inject64'))
        file_list.append(os.path.join(cpu_abi, 'libdexloader64.so'))
        file_list.append('inject64')
    if adb.get_sdk_version() >= 21:
        file_list.append(os.path.join(cpu_abi, 'libandroidhook_art.so'))

    if rooted and adb.is_selinux_opened():
        # 此时如果还是开启状态说明关闭selinux没有生效,主要是三星手机上面
        adb.run_shell_cmd('rm -r %s' % dst_path, True)
        # adb.run_shell_cmd('chcon u:object_r:shell_data_file:s0 %slibdexloader.so' % dst_path, True)  # 恢复文件context,否则拷贝失败
        # adb.run_shell_cmd('chcon u:object_r:shell_data_file:s0 %slibandroidhook.so' % dst_path, True)

    for file in file_list:
        file_path = os.path.join(root_path, file)
        if use_pie and not '.' in file and os.path.exists(file_path + '_pie'):
            file_path += '_pie'
        if not os.path.exists(file_path):
            continue
        save_name = os.path.split(file)[-1]
        if save_name.endswith('_art.so'):
            save_name = save_name.replace('_art', '')
        adb.push_file(file_path, dst_path + save_name)

    adb.chmod('%sdroid_inject' % dst_path, 755)
    adb.chmod('%sinject' % dst_path, 755)
    adb.chmod('%sscreenkit' % dst_path, 755)
    adb.run_shell_cmd('ln -s %sscreenkit %sscreenshot' % (dst_path, dst_path))

    if cpu_abi == 'arm64-v8a':
        adb.chmod('%sdroid_inject64' % dst_path, 755)
        adb.chmod('%sinject64' % dst_path, 755)

    try:
        print(adb.run_shell_cmd('rm -R %scache' % dst_path,
                                rooted))  # 删除目录 rm -rf
    except RuntimeError as e:
        logger.warn('%s' % e)
    # logger.info(adb.run_shell_cmd('mkdir %scache' % (dst_path), True)) #必须使用root权限,不然生成odex文件会失败

    adb.mkdir('%scache' % (dst_path), 777)

    qt4a_helper_package = 'com.test.androidspy'
    apk_path = os.path.join(root_path, 'QT4AHelper.apk')
    if adb.get_package_path(qt4a_helper_package):
        # 判断版本
        installed_version = adb.get_package_version(qt4a_helper_package)
        package = AndroidPackage(apk_path)
        install_version = package.version
        if version_cmp(install_version, installed_version) > 0:
            adb.install_apk(apk_path, True)
    else:
        adb.install_apk(apk_path)

    # adb.install_apk(os.path.join(root_path, 'QT4AMockApp.apk'), True)
    version_file_path = os.path.join(root_path, 'version.txt')
    dst_version_file_path = dst_path + os.path.split(version_file_path)[-1]
    adb.push_file(version_file_path, dst_version_file_path + '.tmp')  # 拷贝版本文件

    if rooted and adb.is_selinux_opened():
        # 此时如果还是开启状态说明关闭selinux没有生效,主要是三星手机上面
        # 获取sdcars context
        if adb.get_sdk_version() >= 23:
            import re
            sdcard_path = adb.get_sdcard_path()
            result = adb.run_shell_cmd('ls -Z %s' % sdcard_path)
            # u:object_r:media_rw_data_file:s0 u:object_r:rootfs:s0
            pattern = re.compile(r'\s+(u:object_r:.+:s0)\s+')
            ret = pattern.search(result)
            if not ret:
                raise RuntimeError('get sdcard context failed: %s' % result)
            context = ret.group(1)
            logger.info('sdcard context is %s' % context)
            adb.run_shell_cmd('chcon %s %s' % (context, dst_path),
                              True)  # make app access
            adb.run_shell_cmd(
                'chcon u:object_r:app_data_file:s0 %sSpyHelper.jar' % dst_path,
                True)
            adb.run_shell_cmd(
                'chcon u:object_r:app_data_file:s0 %sSpyHelper.sh' % dst_path,
                True)
            # 不修改文件context无法加载so
            adb.run_shell_cmd(
                'chcon u:object_r:system_file:s0 %slibdexloader.so' % dst_path,
                True)
            adb.run_shell_cmd(
                'chcon u:object_r:app_data_file:s0 %slibandroidhook.so' %
                dst_path, True)
            adb.run_shell_cmd(
                'chcon %s %sAndroidSpy.jar' % (context, dst_path), True)
            adb.run_shell_cmd('chcon %s %scache' % (context, dst_path), True)
        else:
            # 不修改文件context无法加载so
            adb.run_shell_cmd(
                'chcon u:object_r:app_data_file:s0 %slibdexloader.so' %
                dst_path, True)
            adb.run_shell_cmd(
                'chcon u:object_r:app_data_file:s0 %slibandroidhook.so' %
                dst_path, True)
            adb.run_shell_cmd(
                'chcon u:object_r:app_data_file:s0 %scache' % dst_path, True)

    if rooted:
        if adb.get_sdk_version() < 24:
            # 7.0以上发现生成的dex与运行时生成的dex有差别,可能导致crash
            logger.info(
                adb.run_shell_cmd(
                    'sh %sSpyHelper.sh loadDex %sAndroidSpy.jar %scache' %
                    (dst_path, dst_path, dst_path), rooted))
            adb.chmod('%scache/AndroidSpy.dex' % dst_path, 666)
    else:
        if not 'usage:' in adb.run_shell_cmd('sh %sSpyHelper.sh' % dst_path):
            adb.mkdir('%scache/dalvik-cache' % dst_path, 777)

    if rooted and adb.is_selinux_opened() and adb.get_sdk_version() >= 23:
        # 提升权限
        try:
            adb.list_dir('/system/bin/app_process32')
        except RuntimeError:
            adb.copy_file('/system/bin/app_process',
                          '%sapp_process' % dst_path)
        else:
            adb.copy_file('/system/bin/app_process32',
                          '%sapp_process' % dst_path)
        adb.chmod('%sapp_process' % dst_path, 755)
        adb.run_shell_cmd(
            'chcon u:object_r:system_file:s0 %sapp_process' % dst_path, True)

    adb.run_shell_cmd(
        'mv %s %s' % (dst_version_file_path + '.tmp', dst_version_file_path),
        rooted)

    # 同步手机时间
    device_driver = DeviceDriver(adb)
    try:
        input_method = 'com.test.androidspy/.service.QT4AKeyboardService'
        device_driver.modify_system_setting('secure', 'enabled_input_methods',
                                            input_method)
        device_driver.modify_system_setting('secure', 'default_input_method',
                                            input_method)
        if enable_acc:
            device_driver.modify_system_setting(
                'secure', 'enabled_accessibility_services',
                'com.test.androidspy/com.test.androidspy.service.QT4AAccessibilityService'
            )
            device_driver.modify_system_setting('secure',
                                                'accessibility_enabled', 1)
    except:
        logger.exception('set default input method failed')
    try:
        device_driver.modify_system_setting('system', 'time_12_24', 24)
        device_driver.modify_system_setting('system', 'screen_off_timeout',
                                            600 * 1000)
    except:
        logger.exception('set system time failed')