Android客户端数据备份和恢复

1 问题点

最近一直在尝试在root情况下完成数据的备份和恢复,早期的时候rsync和cp -rp命令勉强够用。后来突然发现通过以上两条命令恢复数据无效。一度怀疑是APP做了限制,但是偶然间试用了一下钛备份,其备份和恢复功能正常,那么说明肯定是自己的备份和恢复手法出了问题,最终猜想可能是由于selinux引起的。

2 钛备份的数据备份和恢复方法

2.1 钛备份客户端

打开jeb,直接载入apk文件。在jeb中看一看到资源文件夹中包含了各个版本的busybox执行文件。

busybox.png

图1  加载文件

2.2 功能试用

在客户端中尝试进行数据备份。

taibeifen.png

图2  功能使用截图

每次使用备份功能备份抖音数据的时候大约会持续两分钟左右,期间通过ps获取进程好,可以从 /proc/pid/cmdline 中印证钛备份确实使用 busybox tar 来实现数据的备份和恢复的。 但是我直接通过tar -xvf命令直接使用钛备份之前生成的备份文件来恢复数据确失败了。

ps.png

图3  进程截图

cmdline.png

图4  进程启动参数

至于失败原因暂时无法追溯,可以肯定的是钛备份在使用tar命令备份和恢复之前肯定做了其他特殊操作。

3 获取所用的busybox执行命令

busybox命令集成了各种常见命令,并且以参数的方式传递。可以直接将钛备份中使用的busybox替换为我们的自定义文件,打印其中的参数,既可看到钛备份中所有的busybox命令操作。直接将 /data/data/com.keramidas.TitaniumBackup/files 下的busybox文件进行备份,并将busybox替换为如下内容。

echo $@ >> /sdcard/taibeifen.txt
/data/data/com.keramidas.TitaniumBackup/files/busybox_bck $@

raplace-busybox.png

图5  修改busybox

busybox_bck为钛备份中的原始文件busybox,此处将其重命名为busybox_bck。

4 所有的备份和恢复命令

所有的busybox命令参数被我们重定向到 /sdcard/taibeifen.txt 中,可以直接观察到钛备份是使用了哪些命令来进行数据备份和恢复的。

4.1 数据备份

du -H -s /storage/emulated/0/Android/data/com.ss.android.ugc.aweme
ln -s /storage/emulated/0/Android/data/com.ss.android.ugc.aweme /data/data/.external.com.ss.android.ugc.aweme
tar -c /data/data/com.ss.android.ugc.aweme/. /data/data/.external.com.ss.android.ugc.aweme/. --exclude data/data/com.ss.android.ugc.aweme/./lib --exclude data/data/com.ss.android.ugc.aweme/./cache
gzip
rm /data/data/.external.com.ss.android.ugc.aweme
ls --color=never -d /data/app/com.ss.android.ugc.aweme-1/base.apk
chown media_rw:media_rw /data/media/0/TitaniumBackup/com.ss.android.ugc.aweme-20200210-074643.tar.gz

4.2 数据恢复

mv /data/data/com.ss.android.ugc.aweme /data/data/.com.ss.android.ugc.aweme
rm -R /storage/emulated/0/Android/data/com.ss.android.ugc.aweme
ln -s /storage/emulated/0/Android/data/com.ss.android.ugc.aweme /data/data/.external.com.ss.android.ugc.aweme
tar -C / -x --exclude data/data/com.ss.android.ugc.aweme/lib --exclude data/data/com.ss.android.ugc.aweme/./lib
cat /storage/emulated/0/TitaniumBackup/com.ss.android.ugc.aweme-20200210-060327.tar.gz
gunzip
rm /data/data/.external.com.ss.android.ugc.aweme
chown -R media_rw:media_rw /data/media/0/Android/data/com.ss.android.ugc.aweme
chown -hR 10124:10124 /data/data/com.ss.android.ugc.aweme
chmod -R u+rwx /data/data/com.ss.android.ugc.aweme
mv /data/data/.com.ss.android.ugc.aweme/lib /data/data/com.ss.android.ugc.aweme
rm -R /data/data/.com.ss.android.ugc.aweme 

通过以上分析,大致逻辑已经清晰,但是通过ps的结果看,明显是使用了管道。所以还是需要完整命令。

5 利用xposed获取完整命令

5.1 定位代码

在jeb中搜索 tar -c 可以定位到命令生成出,最终通过 en类的构造函数的第二个参数进行传递 ,那么我们可以通过 hook en类的构造函数 ,然后打印参数即可。

code.png

图6  命令构造

5.2 插件开发

单独开发一个xposed插件,用来hook en的构造函数,然后直接把String参数打印出来即可,如果xposed开发不熟悉的话可以参考我之前的文章Xposed学习-插件开发(一)

if ("com.keramidas.TitaniumBackup".equals(lpparam.packageName)) {
          XposedBridge.log("ready to hook method.");
          Class clazz = XposedHelpers.findClass("o.es.if", lpparam.classLoader);
          XposedHelpers.findAndHookConstructor("o.en",
                                               lpparam.classLoader, clazz, String.class,
                                               new XC_MethodHook() {
                                                   @Override
                                                   protected void beforeHookedMethod(
                                                       MethodHookParam param) throws Throwable {
                                                       if (param.args.length >= 2) {
                                                           XposedBridge.log(
                                                               "command is " + param.args[1]);
                                                       } else {
                                                           XposedBridge.log(
                                                               "command is " + param.args[0]);
                                                       }
                                                   }
                                               });
}
02-10 18:51:03.211 25912 25912 I Xposed  : command is /system/bin/am force-stop com.ss.android.ugc.aweme
02-10 18:51:04.357 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox du -H -s "/storage/emulated/0/Android/data/com.ss.android.ugc.aweme"
02-10 18:51:04.407 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox ln -s "/storage/emulated/0/Android/data/com.ss.android.ugc.aweme" "/data/data/.external.com.ss.android.ugc.aweme"
02-10 18:51:04.480 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox tar -c "/data/data/com.ss.android.ugc.aweme/." "/data/data/.external.com.ss.android.ugc.aweme/." --exclude "data/data/com.ss.android.ugc.aweme/./lib" --exclude "data/data/com.ss.android.ugc.aweme/./cache" | /data/user/0/com.keramidas.TitaniumBackup/files/busybox gzip > "/storage/emulated/0/TitaniumBackup/com.ss.android.ugc.aweme-20200210-105104.tar.gz"
02-10 18:55:21.044 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox rm "/data/data/.external.com.ss.android.ugc.aweme"
02-10 18:55:21.081 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox ls --color=never -d "/data/app/com.ss.android.ugc.aweme-1/base.apk"
02-10 18:55:21.102 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox ls --color=never "/data/data/com.android.vending/databases/"
02-10 18:55:21.134 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/sqlite3 "/data/data/com.android.vending/databases/localappstate.db" 'pragma table_info ( appstate );'
02-10 18:55:21.174 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/sqlite3 "/data/data/com.android.vending/databases/localappstate.db" 'SELECT appstate.package_name,auto_update,desired_version,download_uri,delivery_data_timestamp_ms,installer_state,first_download_ms,referrer,account,title,flags,continue_url,last_notified_version,last_update_timestamp_ms,account_for_update,auto_acquire_tags,external_referrer_timestamp_ms,persistent_flags,permissions_version,delivery_token,completed_split_ids,active_split_id,request_id FROM appstate WHERE installer_state = "0" AND appstate.package_name = "com.ss.android.ugc.aweme" LIMIT 1;'
02-10 18:55:21.194 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/sqlite3 "/data/data/com.android.vending/databases/library.db" 'SELECT doc_id,doc_type,offer_type,app_certificate_hash,document_hash,library_id FROM ownership WHERE doc_id = "com.ss.android.ugc.aweme";'
02-10 18:55:21.262 25912 27420 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox chown media_rw:media_rw "/data/media/0/TitaniumBackup/com.ss.android.ugc.aweme-20200210-105104.tar.gz"


02-10 18:56:02.434 25912 25912 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox ps -w
02-10 18:56:03.396 25912 25912 I Xposed  : command is /system/bin/am force-stop com.ss.android.ugc.aweme
02-10 18:56:04.600 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox mv "/data/data/com.ss.android.ugc.aweme" "/data/data/.com.ss.android.ugc.aweme"
02-10 18:56:04.632 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox rm -R "/storage/emulated/0/Android/data/com.ss.android.ugc.aweme"
02-10 18:56:04.734 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox ln -s "/storage/emulated/0/Android/data/com.ss.android.ugc.aweme" "/data/data/.external.com.ss.android.ugc.aweme"
02-10 18:56:04.746 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox cat "/storage/emulated/0/TitaniumBackup/com.ss.android.ugc.aweme-20200210-105104.tar.gz" | /data/user/0/com.keramidas.TitaniumBackup/files/busybox gunzip | /data/user/0/com.keramidas.TitaniumBackup/files/busybox tar -C "/" -x --exclude data/data/com.ss.android.ugc.aweme/lib --exclude data/data/com.ss.android.ugc.aweme/./lib
02-10 18:56:30.727 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox rm "/data/data/.external.com.ss.android.ugc.aweme"
02-10 18:56:30.748 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox chown -R media_rw:media_rw "/data/media/0/Android/data/com.ss.android.ugc.aweme"
02-10 18:56:30.769 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox chown -hR 10124:10124 "/data/data/com.ss.android.ugc.aweme"
02-10 18:56:30.960 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox chmod -R u+rwx "/data/data/com.ss.android.ugc.aweme"
02-10 18:56:31.117 25912 28476 I Xposed  : command is /system/bin/restorecon -R "/data/data/com.ss.android.ugc.aweme"
02-10 18:56:31.771 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox mv "/data/data/.com.ss.android.ugc.aweme/lib" "/data/data/com.ss.android.ugc.aweme"
02-10 18:56:31.789 25912 28476 I Xposed  : command is /data/user/0/com.keramidas.TitaniumBackup/files/busybox rm -R "/data/data/.com.ss.android.ugc.aweme"