美文网首页python随记
基于autojs的群控插件

基于autojs的群控插件

作者: LCSan | 来源:发表于2022-05-31 11:50 被阅读0次
    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的群控插件

        本文链接:https://www.haomeiwen.com/subject/fyrzprtx.html