Blanke's blog

Android Frpc客户端自启方案

背景

通过Xposed模块实现Android设备上Frpc客户端的自动启动,主要解决远控手机的需求。通过将5555端口穿透出去,使用scrcpy/adb等协议稳定控制手机,当云手机用。

环境

方案

现成方案有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配置并运行。

<< Previous Post

|

Next Post >>

#Android #Frpc #Xposed #自动化 #远程控制 #So注入