基于frida-inject脚本持久化开发实战
2023-12-9 14:4:13 Author: 哆啦安全(查看原文) 阅读量:16 收藏

主要内容:

  • frida-inject脚本持久化的方案

  • App开关文件目录以及脚本存储文件目录selinux配置

  • 封装和超级Root权限后台进程通信的java Api接口以及封装访问脚本相关目录文件的Java接口

  • 系统源码中添加App启动的时候执行frida-inject命令的逻辑代码

  • 开发控制App实现对第三方App 持久化的配置

1.frida-inject脚本持久化方案原理

方案原理:

在系统源码App启动入口的地方,找一个合适的时机。将frida-inject组装执行附加的命令通过Socket连接发送到超级Root权限后台进程中执行,达到实现App启动就加载js脚本的功能。App启动入口加载时机我们选择ActivityThread.java中的handleBindApplication方法。以下是该方案的一个图示:

在这里插入图片描述

2.持久化相关目录文件创建及selinux配置

2.1 文件及目录设计

在该方案中,设计以下的文件目录用来判断App是否需要开启frida inject持久化以及加载的js文件路径。设计如下:

# 配置某一个App是否开启持久化功能,$PKG_NAME表示App的包名
#比如一个参考:/data/system/xsettings/frdinject/persist/com.android.jnidemo01/persist_fridainject
/data/system/xsettings/frdinject/persist/$PKG_NAME/persist_fridainject

#
配置某一个App加载的js文件路径,$PKG_NAME表示App的包名
# /data/system/xsettings/frdinject/jscfg/com.android.jnidemo01/config.js
/data/system/xsettings/frdinject/jscfg/$PKG_NAME/config.js

在涉及以上的文件或者目录中,管控端App具有system权限,需要配置系统权限的App对以上文件或者目录读写的selinux权限。普通App需要对以上文件有读的权限,所以需要配置第三方App具有读以上文件的selinux权限。

2.2  配置selinux操作

(1).创建文件类型selinux标签

在如下文件中创建文件标签frdinject_data_file,文件列表:

system\sepolicy\public\file.te
system\sepolicy\prebuilts\api\29.0\public\file.te

在以上文件中添加如下内容,需要保证两个文件添加的内容一致。不然要编译错误。

# /data/system/xsettings/
type frdinject_data_file, file_type, data_file_type, core_data_file_type,mlstrustedobject;

(2).为文件目录关联frdinject_data_file标签

在如下文件中添加关联/data/system/xsettings目录selinux标签,文件列表:

system\sepolicy\prebuilts\api\29.0\private\file_contexts
system\sepolicy\private\file_contexts

在以上文件中添加如下内容,需要保证两个文件添加的内容一致。不然要编译错误。

/data/system/xsettings(/.*)?    u:object_r:frdinject_data_file:s0

(3).配置App访问frdinject_data_file标签的权限

这个地方主要配置两种App。一种是system权限的配置端App。第二种是第三方App。

具有系统权限的配置端App selinux配置如下:

在如下文件中:

system\sepolicy\private\system_app.te
system\sepolicy\prebuilts\api\29.0\private\system_app.te

添加如下访问权限,添加之后请保持两个文件内容一致:

# add for accessing frdinject_data_file
allow system_app  frdinject_data_file:dir  { getattr setattr open read write remove_name create add_name search rmdir };
allow system_app  frdinject_data_file:file { getattr setattr open read write  create  unlink };

第三方App配置selinux如下:

在以下文件中添加app访问文件夹的selinux策略。确保相对应的文件内容一致。

在以下untrusted_app_all.te文件:

system\sepolicy\private\untrusted_app_all.te
system\sepolicy\prebuilts\api\29.0\private\untrusted_app_all.te

添加内容如下:

# add for accessing frdinject_data_file
allow untrusted_app_all  frdinject_data_file:dir  { getattr  open read  search };
allow untrusted_app_all  frdinject_data_file:file { getattr  open read };

在以下untrusted_app_27.te文件:

system\sepolicy\private\untrusted_app_27.te
system\sepolicy\prebuilts\api\29.0\private\untrusted_app_27.te

在以下文件:

# add for accessing frdinject_data_file
allow untrusted_app_27  frdinject_data_file:dir  { getattr  open read  search };
allow untrusted_app_27  frdinject_data_file:file { getattr  open read };

在以下untrusted_app_25.te文件:

system\sepolicy\private\untrusted_app_25.te
system\sepolicy\prebuilts\api\29.0\private\untrusted_app_25.te
# add for accessing frdinject_data_file
allow untrusted_app_25  frdinject_data_file:dir  { getattr  open read  search };
allow untrusted_app_25  frdinject_data_file:file { getattr  open read };

在以下untrusted_app.te文件:

system\sepolicy\private\untrusted_app.te
system\sepolicy\prebuilts\api\29.0\private\untrusted_app.te
# add for accessing frdinject_data_file
allow untrusted_app  frdinject_data_file:dir  { getattr  open read  search };
allow untrusted_app  frdinject_data_file:file { getattr  open read };

2.3  init.rc中配置开机的时候就创建对应的目录

该持久化实现中,使用了如下目录。

/data/system/xsettings/frdinject/persist
/data/system/xsettings/frdinject/jscfg

所以可以将该目录放在init进程启动的时候进行创建。由于init进程会解析init.rc文件执行配置的命令,所以可以根据init.rc创建文件夹的规则加入创建以上两个目录的操作。在system\core\rootdir\init.rc文件中添加内容如下:

# /data/system/xsettings/frdinject/persist
mkdir /data/system/xsettings 0775 system system
mkdir /data/system/xsettings/frdinject 0775 system system
mkdir /data/system/xsettings/frdinject/persist 0775 system system
mkdir /data/system/xsettings/frdinject/jscfg 0775 system system

3.系统源码中相关Java接口封装

3.1 封装和超级Root权限通信的MgskSu模块

在源码根目录中创建如下对应的目录:

frameworks\base\core\java\android\xfrd

在目录xfrd中将存放MgskSu模块的接口实现。具体实现如下:

package android.xfrd;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

public class MgskSu {

    public static  String  magiskSu(String cmd)
    
{
        String retString="";
        try {
            //创建socket
            String myCmd="do_cmd|"+cmd;
            Socket mSocket = new Socket();
            InetSocketAddress inetSocketAddress=new InetSocketAddress("127.0.0.1",11111);
            mSocket.connect(inetSocketAddress);
            BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
            bufferedWriter.write(myCmd+"\r\n");
            bufferedWriter.flush();
            retString=bufferedReader.readLine();
            bufferedReader.close();
            bufferedWriter.close();
        }catch (Exception eeeee)
        {
            eeeee.printStackTrace();
        }
        return  retString;
    }
}

3.2 封装针对App需要持久化判断和获取对应js文件路径的接口

在该方案中通过对应App的包名组装文件路径来识别是否存在来判断App是否需要启动就加载js文件。在MagiskSu.java同目录中创建FrdSettings.java模块文件。核心代码如下:

package android.xfrd;

import android.system.Os;
import java.io.File;

public class FrdSettings {

    static final String TAG=FrdSettings.class.getSimpleName();
    private static final String SETTINGS_DIR="/data/system/xsettings/frdinject/persist";
    private  static final String CONFIG_JS_DIR="/data/system/xsettings/frdinject/jscfg";
    public static  final String PERSIST_FRIDA_INJECT="persist_fridainject";
    public static final  String PERSIST_FRIDA_GADGET="persist_fridagadget";
    public static  final String PERSIST_FRIDA_GUMJS="persist_fridagumjs";
    //

    public static boolean  isAppJsPathExists(String pkgName){
           File file=new File(CONFIG_JS_DIR+"/"+pkgName+"/config.js");
           return file.exists();
       }
    public static  String  getAppJsPath(String pkgName)
       {

           File file=new File(CONFIG_JS_DIR+"/"+pkgName+"/config.js");
           return file.getAbsolutePath();
    }

     /**********************判断是否开启持久化***************************/
    //设置对应的App是否开启持久化
    public static void setEnablePersistFridaInject(String pkgName,String methodType, boolean isEnable) {
        File file = new File(SETTINGS_DIR);
        if (!file.exists()) {
            file.mkdirs();
            try {
                Os.chmod(file.getAbsolutePath(), 0775);
            } catch (Exception eeee) {

            }
        }
        File pkgFile = new File(file, pkgName);
        if (!pkgFile.exists()) {
            pkgFile.mkdirs();
            try {
                Os.chmod(pkgFile.getAbsolutePath(), 0775);
            } catch (Exception eeee) {
                eeee.printStackTrace();
            }
        }
        File enableFile = new File(pkgFile, methodType);
        if (isEnable) {
            if (!enableFile.exists()) {

                try {
                    enableFile.createNewFile();
                    //MyLog.d(TAG, "create file success");
                    Os.chmod(enableFile.getAbsolutePath(), 0775);
                } catch (Exception eeee) {
                    //MyLog.d(TAG, "file create errror:" + enableFile.getAbsolutePath());
                    eeee.printStackTrace();
                }
            } else {
                //MyLog.d(TAG, "file exists:" + enableFile.getAbsolutePath());
            }
        } else {
            if (enableFile.exists()) {
                enableFile.delete();
            }
        }

    }

    //判断app是否打开自动注入脚本功能
    public static boolean isEnablePersistFrida(String pkgName,String methodType) {
        File enableFile = new File(SETTINGS_DIR, pkgName + "/"+methodType);
        return enableFile.exists();
    }
}

4.源码中在App启动入口ActivityThread.java中添加加载js逻辑

在之前方案分析中已经找到了在frameworks\base\core\java\android\app\ActivityThread.java中的handleBindApplication方法中加入加载js的逻辑是一个比较不错的选择。在handleBindApplication中加入如下关键调用代码,实现App启动的时候就去加载执行js。核心关键代码如下:

        String curPkgName = data.appInfo.packageName;
        int mypid=Process.myPid();
        int mytempUid=Process.myUid();

        if(mytempUid>10000)
        {
           Boolean isB=FrdSettings.isEnablePersistFrida(curPkgName,FrdSettings.PERSIST_FRIDA_INJECT);
           Log.d("FridaInject","curPkgName  isEnableFridaInject:"+isB);
           if(isB)
           {
              String  jsPath=FrdSettings.getAppJsPath(curPkgName);
              if(jsPath!=null)
              {
                  //这个地方比较重要,不然App运行会奔溃。
                  //App中主线程中调用网络socket操作配置
                  android.os.StrictMode.ThreadPolicy policy = new android.os.StrictMode.ThreadPolicy.Builder().permitAll().build();
                  android.os.StrictMode.setThreadPolicy(policy);
                  String  cmdString="myfridainjectarm64  -p "+mypid+"  -s "+jsPath+"  -e";
                  String retString=MgskSu.magiskSu(cmdString);
                  try{
                     Thread.sleep(50);
                  }catch(Exception eee)
                  {
                  }
                  Log.d("FridaInject","retString is "+retString);
              }else{
                  Log.d("FridaInject","jsPath is null");
              }
          }else{

          }

        }

5.控制端App开发实现对第三方App持久化配置

控制端App中对App是否持久化开关配置以及js路径配置使用的封装接口和以上系统源码中封装的FrdSettings.java是一样的封装。这个地方就不讲接口的封装了。只说一下几个关键的地方使用。

配置界面参考:

在这里插入图片描述

主要涉及的几个接口调用如下:

(1).打开/关闭第三方App加载js功能

调用了封装的接口:setEnablePersistFridaInject

(2).将选择的js文件复制到对应App的配置js目录

调用了封装的接口:copyJsFileToAppJsPath

(3).判断App当前是否配置了加载js功能

调用了封装的接口:isEnablePersistFrida

(4).获取App配置的js文件路径

置以及js路径配置使用的封装接口和以上系统源码中封装的FrdSettings.java是一样的封装。这个地方就不讲接口的封装了。只说一下几个关键的地方使用。

配置界面参考:

[外链图片转存中…(img-L6IhssD7-1667868558625)]

主要涉及的几个接口调用如下:

(1).打开/关闭第三方App加载js功能

调用了封装的接口:setEnablePersistFridaInject

(2).将选择的js文件复制到对应App的配置js目录

调用了封装的接口:copyJsFileToAppJsPath

(3).判断App当前是否配置了加载js功能

调用了封装的接口:isEnablePersistFrida

(4).获取App配置的js文件路径

调用了封装接口:getAppJsPath

推荐阅读
frida hook(入门到入坑)

Android系统ROM定制汇总篇

Android/iOS安全和车联网安全汇总篇


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NzUzNzk1Mw==&mid=2247496570&idx=1&sn=55af968f625000b52afbba38c545f19c&chksm=ceb8b634f9cf3f22f52397b52cd03d1258a8c259a7002ba7a457f1d825c119abb5490ec6001a&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh