Android Frpc客户端自启方案
背景
通过Xposed模块实现Android设备上Frpc客户端的自动启动,主要解决远控手机的需求。通过将5555端口穿透出去,使用scrcpy/adb等协议稳定控制手机,当云手机用。
环境
- 系统:root、Xposed环境
方案
现成方案有frpc相关面具模块Magisk-FRPC,但是实测不太稳定,不知道哪次重启就挂了(发生过几回),而且还有个问题,安装模块需要按音量键,由于是远控,adb触发音量不能继续安装。
最终方案:通过Xposed模块注入系统桌面,实现后台运行,理论上注入android进程或systemui也行,但是测试相对麻烦,所以选了桌面。
1. 集成Frpc Android SDK
先找frpc android sdk,最终用了 frpclib,参考:
2. 解决SO库注入问题
搞定so注入,需要处理的是,frpclib源码里写死了System.loadLibrary(“gojni”),但是注入的时候是找不到的。需要先hook这个方法不执行具体load代码,然后在注入后手动load:
1hookAllBefore("java.lang.System", "loadLibrary") {
2 val libName = it.args[0]
3 LogUtil.log("loadLibrary $libName")
4 if (libName == "gojni") {
5 LogUtil.log("loadLibrary hook $libName")
6 it.result = null
7 }
8}
3. 注入时机控制
注入时机,Application 创建后和Activity 激活后,需要处理是否已经运行:
1hookAfter(Application::class.java, "onCreate") {
2 currentContext = it.thisObject as Context
3 startFrp()
4}
5
6hookAllAfter(Activity::class.java, "onResume") {
7 currentContext = it.thisObject as Activity
8 startFrp()
9}
10
11private fun startFrp() {
12 if (currentContext == null) return
13 val loadSucc = SoLoadHelper.loadSo(modulePath, currentContext!!.cacheDir.absolutePath + "/lib/", "gojni", false)
14 LogUtil.log("gojni load succ = $loadSucc")
15
16 var config = ""
17 val iniPaths = arrayListOf(
18 "/sdcard/frpc.ini",
19 "/data/local/tmp/frpc.ini",
20 currentContext!!.filesDir.absolutePath + "/frpc.ini"
21 )
22
23 for (path in iniPaths) {
24 val tmp = FileIOUtils.readFile2String(path)
25 if (tmp != null) {
26 config = tmp.trim()
27 break
28 }
29 }
30
31 val uid = "phone_frpc_uid"
32 if (!Frpclib.isRunning(uid)) {
33 LogUtil.log("frpc start run $config")
34 thread {
35 val error = Frpclib.runContent(uid, config)
36 LogUtil.log("Frpclib.runContent err = $error")
37 }
38 }
39}
4. SO库加载机制
在startFrp
方法中先通过 SoLoadHelper load so,modulePath是模块apk路径,主要做法是解析模块apk,解压出gojni.so,然后手动调用System.load,最后通过3个位置的frpc.ini路径,最后运行frpc
5. 开机自启动优化
这样一套下来能达到目的,但是重启手机后,不操作手机的前提下,还是有概率不会触发,猜测可能是桌面没有运行,解决思路有几种,要么hook android进程拿到ActivityManagerService
,然后手动启动下桌面,要么是脚本去解锁触发桌面运行。采用了后者,由于装了面具,直接在/data/adb/service.d
下新建一个xx.sh,给执行权限,内容如下:
1#!/system/bin/sh
2until test -d /sdcard/Download \
3 && test .$(getprop sys.boot_completed) = .1
4do
5 sleep 10
6done
7input keyevent 224
8input keyevent 3
9input keyevent 82
10input keyevent 3
11exit 0
后记
这样一套操作下来,只要xposed框架稳定不掉,重启手机后,会自动进入桌面,识别frpc配置并运行。