利用atx-agent手机反向连接电脑可用做分布式群控

最近在做一个分布式的群控.要求手机端发起请求,连接到服务器,通过服务器打洞,连通控制端电脑.这样做的好处就是,任何人可以买几十部手机就可以加入到这个网络,不需要本地电脑控制手机,简化了流程,节省了电脑的投入,最重要的是IP是分散的大大降低触发风控的几率.这种控制模式类似于向日葵,TeamView端到端的控制.开发过程比较曲折,记录一下开发思路以及遇到的坑
要实现这个工程,主要解决两个问题.
第一:选择一个成熟可靠的手机控制项目
第二:保证手机与远程电脑永远不会失联
先说第一点
这是找到的手机控制的各种现有的轮子,经过仔细研究最后决定用最后一个项目atx-server在这里插入图片描述
atx-server这个项目根据一步步更新有几个分支,但是都是手机作为服务端接收请求,电脑作为客户端发起请求的,由于手机只有内网地址,网外不能直接访问,所以就要求手机作为客户端,这就需要修改源码,由于没有接触过go语言,就开始疯狂恶补go的基础知识,goland的破解版没找到靠谱的,最后用的开源工具liteide,在这里感谢工具的作者,下载地址:
https://www.oschina.net/p/liteide?hmsr=aladdin1e1
下面这两个网站给我学习go带来很大帮助
http://c.biancheng.net/view/31.html
https://studygolang.com/
功夫不负有心人,经过N多天努力终于改好了atx-server源码,
新的atx-server基于socket编写,删除了大量本项目用不到的代码,增加了心跳包和断线重连的功能,把截图,点击,滑动,按键控制,中文输入集成到一起,截图用的是minicap,速度快而且图片大小只有100多K.
编译的时候要跨平台编译,要仔细看项目的DEVELOP.md

工作做到这一步感觉完成90%了,没想到这第二点保证手机与远程电脑永远不会失联花费的精力一点不比从头学go语言少.说第二点:
要保证手机不和远程电脑断开,最可靠的方法是把atx-server push到system下,作为手机的系统应用自带开机启动,权限最高,不会被优化进程杀掉,实在是最佳选择.然而本项目最大的限制是手机不能root,因为root过的手机会大大增加触发风控的概率,直接push的后果就是: Read-only file system.
最后实在没有办法只好放弃这条路,于是我想到自己写个apk,有开机启动功能就好,启动后再用apk启动atx,再写个脚本监控apk,防止apk挂掉.
下面是apk的主要代码

package com.jacky.myserver;import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import android.app.Notification;
import androidx.core.app.NotificationCompat;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;public class MyService extends Service
{AlarmManager mAlarmManager = null;PendingIntent mPendingIntent = null;String  data="";String CHANNEL_ID = "com.example.test";String CHANNEL_NAME = "TEST";NotificationChannel notificationChannel = null;NotificationCompat.Builder builder = null;@SuppressLint("WrongConstant")@Overridepublic void onCreate(){//start the service through alarm repeatlyIntent intent = new Intent(getApplicationContext(), MyService.class);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {notificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);notificationManager.createNotificationChannel(notificationChannel);}PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);builder = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle(getResources().getString(R.string.app_name)).setContentText("这是通知内容").setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentIntent(pendingIntent).setDefaults(NotificationCompat.FLAG_ONGOING_EVENT).setPriority(Notification.PRIORITY_MAX);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//SDK版本>=21才能设置悬挂式通知栏builder.setCategory(String.valueOf(Notification.FLAG_ONGOING_EVENT)).setVisibility(Notification.VISIBILITY_PUBLIC).setColor(getResources().getColor(R.color.white));Intent intent2 = new Intent();PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent2, 0);builder.setFullScreenIntent(pi, true);}Notification notification = builder.build();startForeground(100, notification);super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId){String str = "/system/bin/atx-agent server -d";Process process = null;try {process = Runtime.getRuntime().exec("sh");} catch (IOException e) {e.printStackTrace();}if (process == null) {process.destroy();}DataOutputStream   dataOutputStream = new DataOutputStream(process.getOutputStream());Closeable inputStream = process.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader((InputStream) inputStream));StringBuilder stringBuilder2 = new StringBuilder();stringBuilder2.append(str);stringBuilder2.append("\n");try {dataOutputStream.writeBytes(stringBuilder2.toString());} catch (IOException e) {e.printStackTrace();}try {dataOutputStream.writeBytes("exit\n");} catch (IOException e) {e.printStackTrace();}try {dataOutputStream.flush();} catch (IOException e) {e.printStackTrace();}try {process.waitFor();} catch (InterruptedException e) {e.printStackTrace();}return START_STICKY;}@Overridepublic IBinder onBind(Intent intent){return null;}@Overridepublic void onDestroy(){super.onDestroy();}
}

开机接收广播类,Android8.0以上的写法

package com.jacky.myserver;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;public class BootBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent){if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())){Intent startServiceIntent = new Intent(context, MyService.class);startServiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {context.startForegroundService(startServiceIntent);}else {context.startService(startServiceIntent);}}}
}

下面添加的权限有点多,虽然有好多是用不到的,但是我也没有删,因为这些权限是逆向向日葵得来的,留着当个文档吧,哈哈

<?xml version="1.0" encoding="utf-8"?><manifest android:compileSdkVersion="28" android:versionCode="21" package="com.jacky.myserver" xmlns:android="http://schemas.android.com/apk/res/android"><uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/><uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/><uses-permission android:name="android.intent.action.BOOT_COMPLETED" /><uses-permission android:name="android.intent.category.LAUNCHER" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.VIBRATE" /><uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="com.sec.android.provider.badge.permission.WRITE"/><application android:theme="@style/Theme.MyServer" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:persistent="true" android:allowBackup="true"><activity android:name="com.jacky.myserver.MainActivity" android:persistent="true" android:launchMode="singleTask" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><service android:name="com.jacky.myserver.MyService" android:permission="android.permission.BIND_JOB_SERVICE" android:enabled="true" android:exported="true" /><receiver android:name="com.jacky.myserver.BootBroadcastReceiver" android:exported="true" ><intent-filter android:priority="100"><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver></application></manifest>

以上就实现了开机启动,手机启动后会收到一个apk后台服务启动的推送,这是android8.0系统及以上强制要求的.
下面的代码是监控apk防止挂掉的代码,原理是10秒检测一次atx进程是否存在,如果不存在就启动atx,
这个脚本要写在apk里面,随着apk后台服务而启动.
注:ps -A这个命令在某些手机里得不到进程列表要换其他的

#!/bin/bash
(
while : ; do 
results=`ps -A | grep "atx-agent"`
if [[ "${#results}" -lt 10 ]] 
then/system/bin/atx-agent server -d
fi
sleep 10
done
)

所有流程工作都做完了,准备大功告成,然而现实狠狠教育了我:后台服务无法启动atx,用尽各种办法也无法启动,虽然打开apk可以启动,然而对这个项目来说并不适用.感觉自己瞬间苍老了几岁.一夜回到解放前啊.
经过深思熟虑我买了5种品牌的手机,开始测试,因为现在手机系统并不是原生android系统,而是经过手机厂家改造过的,我要测试一下在不同的系统下有没有可能把atx送到system下.
各种百度,google,最后通过一些shell命令,终于成功了,详细过程就不说了,就是些重体力活.
贴个图:
在这里插入图片描述
好巧不巧腾讯网弹广告了,截图成这样了,那就这样吧.

后记:这个项目的远程控制端随便写个服务端程序就可以,经测试只要屏幕不锁屏,atx一直在线,这样把手机仍给谁都不怕了,只要她会充电就行.
打洞部分没有完成,因为账号问题,项目最后没有实际上线,但是,我收获了很多知识.代码太烂请各位大神轻喷.


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部