fl3xbl0w项目标志

备份您的控制台内容 - fl3xbl0w

发布于 2022年5月28日

逆向工程项目。起初是针对Bowflex Treadmill 22,但后来泛化为适用于Nautilus Inc.(Nautilus、Bowflex、Schwinn)销售的任何Android设备。

在从 AppMonitorService 释放(或收到任何 OTA 更新)后,首先要做的是尽可能多地备份数据。

确保您已经连接到控制台:

> adb connect <控制台 IP 地址>

/sdcard 内容的备份

它可能包含一些在出厂重置后机器正常工作所必需的文件(主要在 /sdcard/Android/sdcard/Nautilus 文件夹中)。我们将使用以下命令备份所有内容:

> adb pull /sdcard/ .

APK 备份

首先,获取控制台上安装的所有包的列表(仅供参考):

> adb shell pm list packages -f

它们将以以下格式出现:package:<APK 位置>=<包名>

您将需要找到您想要备份的应用程序。并非所有应用程序都是必需的,大多数是标准的 Android 应用程序,所以我们将只寻找“非标准应用程序”,使用一些过滤器:

> adb shell pm list packages -f | grep -wviE 'com.android|com.google|framework-res|/vendor/overlay'

您将看到来自 com.nautiluscom.redbendcom.netflixcom.amazoncom.disney 的应用程序记录,也许将来还会有更多。我们将想要备份我们在该列表上看到的所有内容(隐藏的唯一 ID,请使用您自己的结果):

> adb shell pm list packages -f | grep -wviE 'com.android|com.google|framework-res|/vendor/overlay'
package:/data/app/com.nautilus.sbctest-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.sbctest
package:/data/app/com.redbend.client-XXXXXXXXXXXXXXXX/base.apk=com.redbend.client
package:/data/app/com.nautilus.nlssbcsystemsettings-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.nlssbcsystemsettings
package:/system/priv-app/RBDualPartService/RBDualPartService.apk=com.redbend.dualpart.service.app
package:/data/app/com.netflix.mediaclient-XXXXXXXXXXXXXXXX/base.apk=com.netflix.mediaclient
package:/data/app/com.nautilus.nautiluslauncher-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.nautiluslauncher
package:/data/app/com.amazon.avod.thirdpartyclient-XXXXXXXXXXXXXXXX/base.apk=com.amazon.avod.thirdpartyclient
package:/data/app/com.nautilus.sbc_demo_app-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.sbc_demo_app
package:/data/app/com.nautilus.UtilityApp-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.UtilityApp
package:/data/app/com.nautilus.g4assetmanager-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.g4assetmanager
package:/data/app/com.nautilus.platform_hardwaretest-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.platform_hardwaretest
package:/data/app/com.nautilus.webviewer-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.webviewer
package:/data/app/com.nautilus.bowflex.usb-XXXXXXXXXXXXXXXX/base.apk=com.nautilus.bowflex.usb
package:/data/app/com.disney.disneyplus-XXXXXXXXXXXXXXXX/base.apk=com.disney.disneyplus

注意:com.redbend.dualpart.service.app 来自 /system/priv-app/,这意味着即使在出厂重置后它也会保持安装状态。如果您对逆向工程应用程序感兴趣,我们可以无论如何都备份它。

以 Disney Plus 为例(隐藏的唯一 ID)

package:/data/app/com.disney.disneyplus-XXXXXXXXXXXXXXXX/base.apk=com.disney.disneyplus

根据我提到的格式,那行将是:

包位置:/data/app/com.disney.disneyplus-XXXXXXXXXXXXXXXX/base.apk
包名:com.disney.disneyplus

我们将根据这些信息查找我们拥有的应用程序版本。使用我们刚刚识别的包名运行:

> adb shell dumpsys package com.disney.disneyplus | grep versionName

在我的案例中,我收到:

> adb shell dumpsys package com.disney.disneyplus | grep versionName
    versionName=2.4.2-rc2

现在,为 Disney Plus 包创建备份的过程将是:

> adb pull /data/app/com.disney.disneyplus-XXXXXXXXXXXXXXXX/base.apk .

立即完成后,转到您的文件资源管理器并将新备份的 base.apk 文件重命名为 com.disney.disneyplus-2.4.2-rc2.apk

我建议的 APK 格式,以该示例为准,是:<包名>-<版本>.apk

现在重复其他应用程序的过程。

AppData 备份

它似乎能够备份 一些(我不确定是否全部) 应用程序数据。

请记住,并非所有已安装的应用程序都会生成应用程序数据,或者我们作为 shell 用户可能没有权限备份所有内容。

创建所有用户安装的应用程序的完整备份:

> adb backup -f appdata.adb -all -noapk -nosystem

或者,您可以从另一个命令获得相同的结果:

> adb shell 'bu backup -all -noapk -nosystem' > appdata.adb

两个命令都会请求一个“屏幕确认”,您想要进行备份。点击“备份我的数据”:

备份确认屏幕

如果您想要提取内容(在 Linux、macOS 上),您将需要来自 qpdfzlib-flate 并运行:

> dd if=appdata.adb bs=24 skip=1 | zlib-flate -uncompress | tar xf -

对于 com.nautilus.bowflex.usb 有一些迷人的数据。 里面有个人身份信息(PII),所以确保检查好您分享的文件

这些备份和提取方法来自这个 Gist。我只测试了那里列出的备份方法,这些方法是安全的。如果您使用 Gist 中的恢复功能,您将自行承担风险。如果它有效,请告诉我们!

脚本

我开发了一个快速而简陋的 Python 脚本来备份一些内容(现在还不包括 AppData)。 仅在 macOS 上测试过,通过 brew 安装了 android-platform-tools。 在运行之前阅读脚本并确保它对您有意义。

import sys
import os
import subprocess
from datetime import datetime

# 检查是否给出了参数
if len(sys.argv) != 2:
    print("使用方法:python3 dump.py <控制台 IP 地址>")
    sys.exit(1)

ipaddr = sys.argv[1]

# 检查 shell 是否可以使用 adb
adb_path = subprocess.check_output(["which", "adb"]).decode("utf-8").strip()
if not os.path.exists(adb_path):
    print("未找到 adb")
    exit()

# 设置当前日期和时间的备份文件夹
dump_folder = os.path.join(
    os.environ["HOME"],
    "Desktop",
    "nautilus_dump",
    "{}".format(datetime.now().strftime("%Y-%m-%d_%H-%M-%S")),
)
if not os.path.exists(dump_folder):
    os.makedirs(dump_folder)

# 连接 adb
print("正在连接到 {}...".format(ipaddr))
subprocess.call(["adb connect {}".format(ipaddr)], shell=True)

# 备份 /sdcard 的内容
print("正在备份 /sdcard 的内容...")
subprocess.call(["adb pull /sdcard/ {}".format(dump_folder)], shell=True)

# 获取 APK 信息
print("正在备份 APKs...")
packages = (
    subprocess.check_output(["adb shell pm list packages -f"], shell=True)
    .decode("utf-8")
    .split("\n")
)

# 过滤掉空行
packages = [x for x in packages if x.strip()]

# 过滤掉包含 "com.android", "com.google", "framework-res" 的行
packages = [package for package in packages if package.find("com.android") == -1]
packages = [package for package in packages if package.find("com.google") == -1]
packages = [package for package in packages if package.find("framework-res") == -1]

print("找到 {} 个 APKs".format(len(packages)))

for package in packages:
    package_name = package.split("=")
    package_name = package_name[len(package_name) - 1].strip()
    package_version = (
        subprocess.check_output(
            ["adb shell dumpsys package {} | grep versionName".format(package_name)],
            shell=True,
        )
        .decode("utf-8")
        .split("=")[1]
        .strip()
    )

    package_path = package.split(":")[1].split(".apk=")[0].strip()
    package_path = "{}.apk".format(package_path)
    print("正在备份 {} v{}...".format(package_name, package_version))

    subprocess.call(["adb pull {} {}".format(package_path, dump_folder)], shell=True)

    os.rename(
        os.path.join(dump_folder, os.path.basename(package_path)),
        os.path.join(dump_folder, "{}-{}.apk".format(package_name, package_version)),
    )

# 备份 appdata
print("正在备份 appdata.adb ...")
print('现在请在屏幕上点击“备份我的数据”按钮!!!')
subprocess.call(
    ["adb backup -f {}/appdata.adb -all -noapk -nosystem".format(dump_folder)],
    shell=True,
)

# 断开 adb 连接
print("正在断开连接...")
subprocess.check_output(["adb disconnect"], shell=True)
内容翻译者 gpt-4-1106-preview

©2022-2024 Sebastian Barrenechea. 保留所有权利.

构建于 Astro v4.16.13.