主要内容:
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,文件列表:
systemsepolicypublicfile.te systemsepolicyprebuiltsapi29.0publicfile.te
在以上文件中添加如下内容,需要保证两个文件添加的内容一致。不然要编译错误。
#/data/system/xsettings/ typefrdinject_data_file,file_type,data_file_type,core_data_file_type,mlstrustedobject;
(2).为文件目录关联frdinject_data_file标签
在如下文件中添加关联/data/system/xsettings目录selinux标签,文件列表:
systemsepolicyprebuiltsapi29.0privatefile_contexts systemsepolicyprivatefile_contexts
在以上文件中添加如下内容,需要保证两个文件添加的内容一致。不然要编译错误。
/data/system/xsettings(/.*)?ufrdinject_data_file:s0
(3).配置App访问frdinject_data_file标签的权限
这个地方主要配置两种App。一种是system权限的配置端App。第二种是第三方App。
具有系统权限的配置端App selinux配置如下:
在如下文件中:
systemsepolicyprivatesystem_app.te systemsepolicyprebuiltsapi29.0privatesystem_app.te
添加如下访问权限,添加之后请保持两个文件内容一致:
#addforaccessingfrdinject_data_file allowsystem_appfrdinject_data_file:dir{getattrsetattropenreadwriteremove_namecreateadd_namesearchrmdir}; allowsystem_appfrdinject_data_file:file{getattrsetattropenreadwritecreateunlink};
第三方App配置selinux如下:
在以下文件中添加app访问文件夹的selinux策略。确保相对应的文件内容一致。
在以下untrusted_app_all.te文件:
systemsepolicyprivateuntrusted_app_all.te systemsepolicyprebuiltsapi29.0privateuntrusted_app_all.te
添加内容如下:
#addforaccessingfrdinject_data_file allowuntrusted_app_allfrdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_app_allfrdinject_data_file:file{getattropenread};
在以下untrusted_app_27.te文件:
systemsepolicyprivateuntrusted_app_27.te systemsepolicyprebuiltsapi29.0privateuntrusted_app_27.te
在以下文件:
#addforaccessingfrdinject_data_file allowuntrusted_app_27frdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_app_27frdinject_data_file:file{getattropenread};
在以下untrusted_app_25.te文件:
systemsepolicyprivateuntrusted_app_25.te systemsepolicyprebuiltsapi29.0privateuntrusted_app_25.te
#addforaccessingfrdinject_data_file allowuntrusted_app_25frdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_app_25frdinject_data_file:file{getattropenread};
在以下untrusted_app.te文件:
systemsepolicyprivateuntrusted_app.te systemsepolicyprebuiltsapi29.0privateuntrusted_app.te
#addforaccessingfrdinject_data_file allowuntrusted_appfrdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_appfrdinject_data_file:file{getattropenread};
2.3 init.rc中配置开机的时候就创建对应的目录
该持久化实现中,使用了如下目录。
/data/system/xsettings/frdinject/persist /data/system/xsettings/frdinject/jscfg
所以可以将该目录放在init进程启动的时候进行创建。由于init进程会解析init.rc文件执行配置的命令,所以可以根据init.rc创建文件夹的规则加入创建以上两个目录的操作。在systemcore ootdirinit.rc文件中添加内容如下:
#/data/system/xsettings/frdinject/persist mkdir/data/system/xsettings0775systemsystem mkdir/data/system/xsettings/frdinject0775systemsystem mkdir/data/system/xsettings/frdinject/persist0775systemsystem mkdir/data/system/xsettings/frdinject/jscfg0775systemsystem
3.系统源码中相关Java接口封装
3.1 封装和超级Root权限通信的MgskSu模块
在源码根目录中创建如下对应的目录:
frameworksasecorejavaandroidxfrd
在目录xfrd中将存放MgskSu模块的接口实现。具体实现如下:
packageandroid.xfrd; importjava.io.BufferedReader; importjava.io.BufferedWriter; importjava.io.InputStreamReader; importjava.io.OutputStreamWriter; importjava.net.InetSocketAddress; importjava.net.Socket; publicclassMgskSu{ publicstaticStringmagiskSu(Stringcmd) { StringretString=""; try{ //创建socket StringmyCmd="do_cmd|"+cmd; SocketmSocket=newSocket(); InetSocketAddressinetSocketAddress=newInetSocketAddress("127.0.0.1",11111); mSocket.connect(inetSocketAddress); BufferedWriterbufferedWriter=newBufferedWriter(newOutputStreamWriter(mSocket.getOutputStream())); BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(mSocket.getInputStream())); bufferedWriter.write(myCmd+" "); bufferedWriter.flush(); retString=bufferedReader.readLine(); bufferedReader.close(); bufferedWriter.close(); }catch(Exceptioneeeee) { eeeee.printStackTrace(); } returnretString; } }
3.2 封装针对App需要持久化判断和获取对应js文件路径的接口
在该方案中通过对应App的包名组装文件路径来识别是否存在来判断App是否需要启动就加载js文件。在MagiskSu.java同目录中创建FrdSettings.java模块文件。核心代码如下:
packageandroid.xfrd; importandroid.system.Os; importjava.io.File; publicclassFrdSettings{ staticfinalStringTAG=FrdSettings.class.getSimpleName(); privatestaticfinalStringSETTINGS_DIR="/data/system/xsettings/frdinject/persist"; privatestaticfinalStringCONFIG_JS_DIR="/data/system/xsettings/frdinject/jscfg"; publicstaticfinalStringPERSIST_FRIDA_INJECT="persist_fridainject"; publicstaticfinalStringPERSIST_FRIDA_GADGET="persist_fridagadget"; publicstaticfinalStringPERSIST_FRIDA_GUMJS="persist_fridagumjs"; // publicstaticbooleanisAppJsPathExists(StringpkgName){ Filefile=newFile(CONFIG_JS_DIR+"/"+pkgName+"/config.js"); returnfile.exists(); } publicstaticStringgetAppJsPath(StringpkgName) { Filefile=newFile(CONFIG_JS_DIR+"/"+pkgName+"/config.js"); returnfile.getAbsolutePath(); } /**********************判断是否开启持久化***************************/ //设置对应的App是否开启持久化 publicstaticvoidsetEnablePersistFridaInject(StringpkgName,StringmethodType,booleanisEnable){ Filefile=newFile(SETTINGS_DIR); if(!file.exists()){ file.mkdirs(); try{ Os.chmod(file.getAbsolutePath(),0775); }catch(Exceptioneeee){ } } FilepkgFile=newFile(file,pkgName); if(!pkgFile.exists()){ pkgFile.mkdirs(); try{ Os.chmod(pkgFile.getAbsolutePath(),0775); }catch(Exceptioneeee){ eeee.printStackTrace(); } } FileenableFile=newFile(pkgFile,methodType); if(isEnable){ if(!enableFile.exists()){ try{ enableFile.createNewFile(); //MyLog.d(TAG,"createfilesuccess"); Os.chmod(enableFile.getAbsolutePath(),0775); }catch(Exceptioneeee){ //MyLog.d(TAG,"filecreateerrror:"+enableFile.getAbsolutePath()); eeee.printStackTrace(); } }else{ //MyLog.d(TAG,"fileexists:"+enableFile.getAbsolutePath()); } }else{ if(enableFile.exists()){ enableFile.delete(); } } } //判断app是否打开自动注入脚本功能 publicstaticbooleanisEnablePersistFrida(StringpkgName,StringmethodType){ FileenableFile=newFile(SETTINGS_DIR,pkgName+"/"+methodType); returnenableFile.exists(); } }
4.源码中在App启动入口ActivityThread.java中添加加载js逻辑
在之前方案分析中已经找到了在frameworksasecorejavaandroidappActivityThread.java中的handleBindApplication方法中加入加载js的逻辑是一个比较不错的选择。在handleBindApplication中加入如下关键调用代码,实现App启动的时候就去加载执行js。核心关键代码如下:
StringcurPkgName=data.appInfo.packageName; intmypid=Process.myPid(); intmytempUid=Process.myUid(); if(mytempUid>10000) { BooleanisB=FrdSettings.isEnablePersistFrida(curPkgName,FrdSettings.PERSIST_FRIDA_INJECT); Log.d("FridaInject","curPkgNameisEnableFridaInject:"+isB); if(isB) { StringjsPath=FrdSettings.getAppJsPath(curPkgName); if(jsPath!=null) { //这个地方比较重要,不然App运行会奔溃。 //App中主线程中调用网络socket操作配置 android.os.StrictMode.ThreadPolicypolicy=newandroid.os.StrictMode.ThreadPolicy.Builder().permitAll().build(); android.os.StrictMode.setThreadPolicy(policy); StringcmdString="myfridainjectarm64-p"+mypid+"-s"+jsPath+"-e"; StringretString=MgskSu.magiskSu(cmdString); try{ Thread.sleep(50); }catch(Exceptioneee) { } Log.d("FridaInject","retStringis"+retString); }else{ Log.d("FridaInject","jsPathisnull"); } }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
审核编辑:刘清
-
JAVA
+关注
关注
19文章
2978浏览量
105290 -
API接口
+关注
关注
1文章
84浏览量
10531
原文标题:基于frida-inject脚本持久化开发实战
文章出处:【微信号:哆啦安全,微信公众号:哆啦安全】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
Windows/Ubuntu安装frida和objection
frida-inject工具使用及说明 内置frida-inject工具到手机系统
自动化测试脚本开发技巧
JavaScript模块化开发实验---webpack入门
![JavaScript模块<b class='flag-5'>化开发</b>实验---webpack入门](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
评论