基于autojs的群控插件

  1. autojs4.1端,打包成apk。upd服务自动发现,websocket命令中转,服务自检。
//引入需要用到的安卓包
importClass("java.net.InetAddress");
importClass("java.net.Inet6Address");
importClass("java.net.NetworkInterface");
importClass("java.net.InetSocketAddress");
importClass("java.net.DatagramPacket");
importClass("java.net.DatagramSocket");


// websocket全局对象,本地IP(用于终端验证)
let ws, localIP;
// 全局检测,ws服务端中断以后,需要重新自启组播服务,扫描服务用于子发现
let isConnect;


// 等待获取无障碍权限
auto.waitFor();

// 服务监控
let serverListenser = setInterval(function () {
    log("服务侦听…");
    initServer();
}, 3000);
// initServer();

//监听log事件,发送给服务端
events.broadcast.on("log", function (words) {
    try {
        if (!localIP) {
            localIP = getIntranetIP();
        }
        log(words);
        ws.send(JSON.stringify({ "type": "msg", "ip": localIP, "result": words }));
    } catch (err) {
        log(err);
    }
});


function initServer() {
    // 服务未连接
    if (isConnect != true) {
        // 临时暂停监听服务
        clearInterval(serverListenser);
        let ds = initDs();
        log("服务端发现…")
        while (true) {
            try {
                log("尝试通信…")
                // 发送组播消息,检测ws服务端口
                sendDs(ds, '255.255.255.255', 8061, JSON.stringify({ "type": "initAuto.js" }));
                // 等待消息响应
                let msg = getDsMsg(ds);
                log(msg);
                if (msg["msg"]["statues"] === "success") {
                    ds.close();
                    log("检测到服务,尝试链接…")
                    log("ws:/" + msg["ip"] + ":" + msg["msg"]["port"])
                    // 创建websocket链接
                    ws = initWs("ws:/" + msg["ip"] + ":" + msg["msg"]["port"] + "/worker");
                    // 服务器启动成功,更新标记位
                    isConnect = true;
                    log("链接成功!!")
                    // 重启监听服务
                    serverListenser = setInterval(function () {
                        initServer();
                    }, 3000);
                    break;
                }
            } catch (error) {
                log("未检测到服务…");
            }
        }
    }
}


// 创建组播
function initDs() {
    // 构造数据报套接字并将其绑定到本地主机上任何可用的端口
    log("初始化服务…")
    let ds = new DatagramSocket();
    ds.setBroadcast(true);
    return ds;
}

// 发送组播消息
function sendDs(ds, ip, port, msg) {
    ip = InetAddress.getByName(ip);
    let bts = new java.lang.String(msg).getBytes("UTF-8");
    ds.send(new DatagramPacket(bts, bts.length, ip, port));
}

// 接收组播消息
function getDsMsg(ds) {
    let bts = util.java.array('byte', 1024);
    let packet = new DatagramPacket(bts, bts.length);
    ds.setSoTimeout(2000);
    ds.receive(packet);
    return { "ip": packet.getAddress().toString(), "msg": JSON.parse(new java.lang.String(packet.getData(), 0, packet.getLength(), "UTF-8")) };
}
7
// 创建websocket
function initWs(url) {
    global
    let mClient = new OkHttpClient();
    let request = new Request.Builder().get().url(url).build();
    let globalWebsocket = null;

    mClient.newWebSocket(request, new JavaAdapter(WebSocketListener, {
        onOpen: function (webSocket, response) {
            globalWebsocket = webSocket;
        },
        onMessage: function (webSocket, text) {
            // 接收到消息后,这里转发到引擎执行脚本
            log("收到消息…");
            try {
                autojsHandle(text);
            } catch (error) {
                log(error);
                events.broadcast.emit('log', error + "");
            }

        },
        onClosed: function (webSocket, code, reason) {
            // 这里更新全局连接标记位,用于重新拉起服务检测
            isConnect = false;
            globalWebsocket = null;
            log("服务错误…");
            try {
                webSocket.close();
            } catch (error) {
                log(error);
            }
        },
        onFailure: function (webSocket, throwable, response) {
            isConnect = false;
            globalWebsocket = null;
            log("服务链接中断…");
            try {
                webSocket.close();
            } catch (error) {
                log(error);
            }
        }
    }));

    while (true) {
        try {
            if (globalWebsocket != null) {
                break;
            }
            sleep(1000)
        } catch (e) {
        }
    }
    return globalWebsocket;
}

function autojsHandle(text) {
    let msg = JSON.parse(text);
    // log(msg)
    // 所有的log都加上events.broadcast.emit("log",)来发送结果给websocket
    // msg["source"] = msg["source"].replace(/(log\(((?:['"]?).*\1)\)[;\n])/ig, "$1;events.broadcast.emit('log',$2);\n");
    msg["source"] = msg["source"].replace(/log\(/ig, "events.broadcast.emit(\"log\",");
    // log(msg);
    switch (msg["type"]) {
        case "main":
            eval(msg["source"]);
            break;
        default:
            engines.execScript(msg["title"], msg["source"], msg["config"]);
            break;
    }
}

function getIntranetIP() {
    // 获取所有网卡信息
    let networkInterfaces = NetworkInterface.getNetworkInterfaces();
    while (networkInterfaces.hasMoreElements()) {
        // 遍历网卡
        let networkInterface = networkInterfaces.nextElement();
        // 获取网卡地址
        let inetAddresses = networkInterface.getInetAddresses();
        while (inetAddresses.hasMoreElements()) {
            let inetAddress = inetAddresses.nextElement();
            // 判断网卡地址类型是不是IPV6,IPV6的舍弃
            if (inetAddress instanceof Inet6Address) {
                continue;
            }
            // 获取IP地址
            let ip = inetAddress.getHostAddress();
            // 非本地IP就绑定组播到网卡
            if (!"127.0.0.1".equals(ip)) {
                // 绑定网卡组播
                return ip;
            }
        }
    }
}
  1. 服务端用python,udp广播服务,websocket服务端。打包成exe。
    服务端代码
# coding=utf-8
'''
Created on 2022年5月23日

@author: 瞌睡蟲子
'''
import asyncio
from http import client
import websockets
import json
import click


wsWorkerClents = set()
wsCommanderClents = set()
WS_PORT = None


class EchoServerProtocol:
    def connection_made(self, transport):
        self.transport = transport

    def datagram_received(self, data, addr):
        message = data.decode("utf-8")
        # print(message)
        message = json.loads(message)
        print('Received %r from %s' % (message, addr))
        if "type" in message and message["type"] == "initAuto.js":
            # 重新组合数据打印数据
            msg = json.dumps({"statues": "success", "port": WS_PORT})
            self.transport.sendto(msg.encode('utf-8'), addr)
        else:
            msg = json.dumps(
                {"statues": "error", "port": None, "msg": "type error"})
            self.transport.sendto(msg.encode('utf-8'), addr)


async def echo(websocket, path):
    # print(path)
    # print('%s:%d' % websocket.remote_address)
    cnt = '%s:%d' % websocket.remote_address
    if path == "/worker":
        print('[Worker %s] online' % (cnt))
        wsWorkerClents.add(websocket)
        try:
            async for message in websocket:
                print('[Worker %s] Received: %r' % (cnt, message))
                if wsCommanderClents:
                    [await user.send(message) for user in wsCommanderClents]
        except:
            print("[Worker %s] offline" % (cnt))
        finally:
            wsWorkerClents.remove(websocket)
    elif path == "/commander":
        print('[Commander %s] online' % (cnt))
        wsCommanderClents.add(websocket)
        try:
            async for message in websocket:
                print('[Commander %s] Received: %r' % (cnt, message))
                if wsWorkerClents:
                    [await user.send(message) for user in wsWorkerClents]
        except:
            print("[Commander %s] offline" % (cnt))
        finally:
            wsCommanderClents.remove(websocket)


@click.command()
@click.option('--port', default=5432, type=int, help='port of websocket server.')
def server(port):
    global WS_PORT
    WS_PORT = port

    loop = asyncio.get_event_loop()
    print("Starting server")
    # One protocol instance will be created to serve all client requests
    listen = loop.create_datagram_endpoint(
        EchoServerProtocol, local_addr=('0.0.0.0', 8061))
    transport, protocol = loop.run_until_complete(listen)

    wsServer = websockets.serve(echo, "0.0.0.0", port)
    loop.run_until_complete(wsServer)

    try:
        loop.run_forever()
    except:
        pass
    finally:
        transport.close()
        loop.close()


if __name__ == "__main__":
    server()

打包脚本入口:install.bat

@echo off

rem conda的python引擎库名字
set env=p38_x64

cd %~dp0
%~d0

conda create -n %env% python=3.7 && conda activate %env% && package.bat %env%
@echo package ok!!
pause

打包脚本:package.bat

@echo off
@echo package start...
echo %1
FOR /F "delims=/ tokens=1" %%i IN ('conda env list ^| find "%1"') DO @set pkg=%%i
SET PADDLEOCR_PATH=%pkg:~25%\Lib\site-packages
echo %PADDLEOCR_PATH%
SET CODE_PATH=%~dp0
echo %CODE_PATH%
cd %~dp0
%~d0

@REM pip install websockets
@REM pip install click
@REM pip install pyinstaller

pyinstaller -F --clean -y -i logo.ico autoServer.py 

@echo package ok!!
pause

  1. uibot python插件,控制端。通过websocket发送autojs命令。
# coding=utf-8
'''
Created on 2022年5月23日

@author: 瞌睡蟲子
'''
from time import sleep
import websocket
import threading
import json
import os
import re
from queue import Queue
from os.path import join, dirname

q = Queue()
ws_port = None
ws_client = None


def on_message(ws, message):
    # print(message)
    message = json.loads(message)
    # if "message" in message:
    q.put(message)


def on_close(wss):
    global ws_port
    server(ws_port)
    print("### closed ###")


def server(port=5432):
    global ws_client
    global ws_port
    ws_port = port
    p = checkServer()
    if p == 0:
        cmd = "cd /d \"" + join(dirname(__file__), 'autoServer') + \
            "\"&start autoServer.exe --port " + str(port)
        print(cmd)
        os.system(cmd)
        sleep(2)
    websocket.enableTrace(True)
    ws_client = websocket.WebSocketApp(
        "ws://127.0.0.1:" + str(port) + "/commander", on_message=on_message, on_close=on_close)
    # ws.run_forever()
    threading.Thread(target=ws_client.run_forever, daemon=True).start()
    sleep(2)


def run(source, config={}, title="uibot.js", tp="main"):
    ws_client.send(json.dumps(
        {"source": source, "type": tp, "title": title, "config": config}))


def checkServer(pname="autoServer.exe"):
    data = _command("tasklist | findstr " + pname)
    if data == "":
        return 0
    print(data)
    data = re.findall("(\\d+)\\s+Console", data)
    print(data)
    for pid in data:
        temp = _command(
            "netstat -ano | findstr LISTENING | findstr " + pid + "$")
        if len(temp) > 0:
            temp = re.findall(
                "TCP\\s+[\\d.]+:(\\d+)\\s+[\\d.]+:\\d+\\s+LISTENING", temp)
            if len(temp) > 0:
                return int(temp[0])
    return 0


def _command(sCommand):
    with os.popen(sCommand, 'r') as f:
        res = f.read()
    return res


def getMsg(timeout=1000):
    # 获取执行结果的消息
    msg = None
    try:
        msg = q.get(True, timeout/1000)
    except Exception:
        msg = None
    return msg


if __name__ == "__main__":
    server()
    # run("log(\"你好\");")
    # print(q.get())
    # while True:
    # print(q.get())
    for i in range(1, 5):
        run("log('你好')")
        print(getMsg())
        sleep(1)
    # print(checkServer())

只做了基础框架,没有做任何安全方面设计。

你可能感兴趣的:(基于autojs的群控插件)