某保护加固简单分析
2019-07-30 13:36:25 Author: bbs.pediy.com(查看原文) 阅读量:154 收藏

声明:本帖只作为技术分享,切勿用于非法用途,如果用于其他用途,本贴概不负责,如果有侵权,请管理员删除。

上一篇帖子: Android改机系列:一.Android一键新机原理刨析 主要分析的是一键新机功能,一键新机主要用于批量(恶意)注册、拉新之用。今天来介绍全息备份原理及应用。原版下载地址在https://www.lanzous.com/i5489ri 密码:Dalvik。原版是跑不起来的!跑不起来的!跑不起来的!只供技术分析之用。

什么是全息备份

一款App运行之后会在应用沙盒目录data/data/xxx或者/sdcard或者/Android/甚至Settings.Global/Secure/System(理论上是没有权限)中生成该App在运行时候产生的文件,例如登录状态,App的设置,聊天文件,游戏存档等等。全息备份就是备份该App在运行时候已经产生的所有文件,然后在一款新机器中再还原这些文件,这个时候在新机器中运行该App,你在之前手机中的所有登录状态,App的设置,聊天文件,游戏存档都会出现在这台手机中,所以就不用担心你在该App中的聊天记录或者设置信息丢失。

全息备份能做什么

普通应用场景

举个最简单的例子:你用一台用了五年的Android手机,手机上安装了高德地图、微信、抖音、旅行青蛙等App,现在你手机机已经卡的不行了打算换一台手机,但是又不想之前高德地图的离线地图和微信中的聊天记录和闯关游戏记录丢失。你想在新手机中也拥有之前的离线地图和微信中的聊天记录和闯关记录,这个时候就需要全息备份,把之前旧手机中所有的数据都搬运到新手机中。实际上miui和emui等国产第三方定制系统都具有一键换机功能(好像只能在同品牌手机中换)。

改机应用场景

之前我们说过,一键新机可以用来批量注册账号和拉新,但是有时候批量注册的账号权限比较低或者拉新的时候App厂商会看留存率给cp结算,这个时候对应的策略就是养号和做用户留存(次日留存,七日留存,半月留存,月留存),例如:一台手机可能一天中批量注册很多微信或陌陌账号,这个时候第二天就需要把之前一天的所注册的账号进行养号(发动态加人之类)操作。所以需要还原之前注册时候的一键新机的设备信息和注册时候app产生的文件信息,欺骗app服务端该账号一直是在同一台手机中操作,这样就可以慢慢提高账号权限。再例如:app拉新过程中可能会产生很多新设备,在做留存的时候就需要在之前一键新机的设备环境中和app服务器进行交互(所谓的用户行为),所以也需要还原之前拉新时候的一键新机的设备信息和app产生的文件信息,欺骗app服务端该新用户一直是在同一台手机中操作,并且有留存。通过这种操作爆破app厂商的风控。

传统实现方案

传统的实现方案是在root的情况下,通过遍历app产生的所有文件并且进行提取,然后在root的手机中进行还原。这里提到了root,为什么要root呢?因为应用沙盒目录data/data/xxx在非root情况下普通应用是没有读取权限的。喜欢玩机的朋友应该知道鼎鼎大名的"钛备份",钛备份就是基于root下的全息备份神器。当年Android手机卡成ppt的年代就是靠钛备份活命的。 怀念我的戴妃神机

免root实现方案

app必须有FLAG_ALLOW_BACKUP属性才能进行全息备份,也就是androidMannifest.xml文件中android:allowBackup属性设置为ture

第一步

直接通过AIDL获取com.android.server.backup.BackupManagerService服务,然后调用BackupManagerService的fullBackup函数进行对某个或某些app进行全息备份。

   @param file 备份文件名
   @param arrayList 需要备份的包名列表 
    private static void fullBackup(File file, ArrayList<String> arrayList, boolean z) {
        int i = 0;
        IBackupManager asInterface = Stub.asInterface(ServiceManager.getService("backup"));
        if (asInterface == null) {
            Log.e("ContentValues", "Can't obtain Backup Manager binder");
            return;
        }
        ParcelFileDescriptor parcelFileDescriptor = null;
        try {
            parcelFileDescriptor = openParcelFile(file);
            String[] strArr = new String[arrayList.size()];
            if (VERSION.SDK_INT <= 19) {
                Method[] methods = IBackupManager.class.getMethods();
                int length = methods.length;
                while (true) {
                    if (i >= length) {
                        break;
                    }
                    Method method = methods[i];
                    if ("fullBackup".equals(method.getName())) {
                        method.setAccessible(true);
                        method.invoke(asInterface, new Object[]{parcelFileDescriptor, Boolean.valueOf(z), Boolean.valueOf(false), Boolean.valueOf(false), Boolean.valueOf(false), Boolean.valueOf(false), arrayList.toArray(strArr)});
                        break;
                    }
                    i++;
                }
            } else {
                asInterface.fullBackup(parcelFileDescriptor, z, false, false, false, false, false, true, (String[]) arrayList.toArray(strArr));
            }
            if (parcelFileDescriptor != null) {
                try {
                    parcelFileDescriptor.close();
                } catch (IOException e) {
                }
            }
        } catch (Exception e2) {
            Log.e("ContentValues", "Unable to invoke backup manager for backup", e2);
            if (parcelFileDescriptor != null) {
                try {
                    parcelFileDescriptor.close();
                } catch (IOException e3) {
                }
            }
        } finally {
            if (parcelFileDescriptor != null) {
                try {
                    parcelFileDescriptor.close();
                } catch (IOException e4) {
                }
            }
        }
    }

第二步

Hook android.content.pm.PackageParser.parseBaseApplication函数赋予该app FLAG_ALLOW_BACKUP属性

    if ("parseBaseApplication".equals(name) ) 
        {
            Package packageR = (Package) methodHookParam.args[0];
            ApplicationInfo applicationInfo = packageR.applicationInfo;
            String str2 = packageR.applicationInfo.packageName;
            applicationInfo.flags |= 32768;
            applicationInfo.flags |= 131072;
        }

第三步

Hook BackupManagerService.startConfirmationUi(int token, String action) 跳过用户确认弹窗调用,然后再获取BackupManagerService服务,调用acknowledgeFullBackupOrRestore函数完成全息备份

    public void acknowledgeFB(int i) {
        try {
            Stub.asInterface(ServiceManager.getService("backup")).acknowledgeFullBackupOrRestore(i, true, "", "", new FullObserver());
                } catch (RemoteException e) {
            e.printStackTrace();
                }
            }

第四步

还原备份,这个流程和上面三步类似,就不过多赘述了。ps:现在是晚上11. 写不下去了

念念碎

1.是不是有点懵?去看反编译原版改机对照我的分析和Android源码就明白了。源码位置frameworks/base/services/backup/java/com/android/server/backup/BackupManagerService.java 和frameworks/base/core/java/android/content/pm/PackageParser.java
2.原版改机的全息备份是有点问题的,不能完整运行。不知道作者故意写错还是不小心写错的,总之我破解修改后的代码是能完美运行的,我™这分明是在给作者修BUG呀。
3.pm11.了太晚了明天再更新几张图片吧


Android改机系列:三.自动化智能养号
Android改机系列:四.设置原生vpn(mtpd)
Android改机系列:五.如何生成a16文件,a16生成算法
Android改机系列:六.市面上现存改机方案大整理
Android改机系列:七.如何防御改机之人机识别
Android改机系列:八.手把手教你写个小改机软件

[公告]看雪 2019 安全开发者峰会,圆满落幕!现场精彩回顾!

最后于 13小时前 被seandong编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-253445.htm
如有侵权请联系:admin#unsafe.sh