第三方App与Termux命令建立IO通道

app,termux,io · 浏览次数 : 4

小编点评

本文主要介绍了 Android 系统中的进程间通信(IPC)技术,特别关注了 Android 与 Termux 以及第三方 App 之间的 TCP/Socket 通信。文章首先概述了 Android 进程间通信的主要方式和它们的优缺点,然后详细讲解了 Netcat 网络瑞士军刀的使用方法,接着展示了如何通过 RunCommandService 与 Termux 建立 TCP/Socket 通信,最后通过一个具体的应用示例展示了如何调用 LSP 语言服务器。 1. **Android 进程间通信(IPC)**:介绍了 Android 中的进程间通信方式,包括文件、Binder、SharedMemory、Unix Domain Socket 和 Socket,以及它们的特点和使用场景。 2. **Netcat 网络瑞士军刀**:讲解了 Netcat 工具的基本用法,如何在 Termux 中建立套字节通信,并通过重定向 stdin/stdout 实现通信。 3. **第三方 App 与 Termux 建立 TCP/Socket 通信**:描述了如何通过 RunCommandService 调用 Termux 执行 nc 命令反弹某个程序,然后使用 Java.net.Socket 建立 Socket 连接,实现进程间通信。 4. **应用:调用 LSP 语言服务器**:详细说明了如何安装和使用 clangd 作为 LSP 服务器,并通过 Android 客户端建立 Socket IO 通信,以便与 LSP 服务器进行交互。 总的来说,本文通过几个具体的实例和命令,向读者展示了 Android 系统中进程间通信的多样性和灵活性,特别是在 Termux 和第三方 App 之间的 TCP/Socket 通信方面的应用。

正文

前言

继上一篇 Android 调用 Termux 执行命令,执行命令的问题基本解决,但是 bashawkclangd 这类命令可以从标准输入读取信息并维持运行,Termux 第三方调用缺乏有效支持。而 RunCommandService 可以允许命令后台运行,然后我们以某种方式取得该后台程序的标准输入/输出,便可以实现前后端的持续通信。


一、Android 进程间通信(IPC)

进程间通信(In-Process Communication, IPC)主要实现多进程间的数据通信问题。比如一个 UI 程序后台调用一个 CLI 程序执行某功能,每个程序会启动一个进程,UI 进程给 CLI 进程发送输入数据,CLI 进程接收后返回处理结果给 UI 进程。

Android 实现跨进程通信有多种方式,其各有优缺点:

文件:直接在设备上创建文件实现数据通信。原理简单,操作方便,但是效率低。

Binder:结构上 Binder 是一个虚拟的设备驱动(/dev/binder),连接 Service 进程、Client 进程和 Service Manager 进程。其数据只在内核空间与用户空间复制一次,效率较高,但是限制 1M 数据。另外,基于 Binder 的方法有 AIDL、ContentProvider、Messenger 等。

SharedMemory:共享内存在 Android SDK 27 引入,允许开辟一块共享内存空间用于进程间的数据交互。SharedMemory 配合 AIDL/Binder 使用,可以破除 1M 的限制,传输大文件。但是注意直接对内存进行操作,使用完毕需要手动销毁。

Unix Domain Socket:又叫 Local Domain Socket,本地套字节是 Linux 内核提供的功能,数据经过内核,实现本地进程间通信。其效率高,但是 Android 9+ 限制用户 App 间使用 UDS 通信。

Socket:套字节本质上是网络通信,采用 TCP 或 UDP 协议,主要用于网络通信。其中 TCP 协议较复杂,用于建立稳定的通信;UDP 则速度快而不安全。

受安卓不同应用之间的权限限制,支持进程间字节数据 IO 通信的方案较少,本次采用 Socket 实现。

二、Netcat 网络瑞士军刀

Netcat 是一个小巧强大的网络工具,用于网络监听测试等。Netcat 可建立网络通信,支持 TCP/UDP/Unix 协议。在 Termux 端使用 Netcat 建立套字节通信,并将 stdin/stdout 重定向到一个子进程,如此实现通信。

通过以下方式建立 TCP 通信。服务器端:

nc -l -s 127.0.0.1 -p 1234

客户端:

nc 127.0.0.1 1234

此时在客户端输入的内容可传至服务器端,而服务器端输入的内容可传回客户端,二者间实现通信。

另外,使用 Netcat 可以方便反弹 shell 程序。下面是服务器端命令:

nc -l -s 127.0.0.1 -p 1234 bash

用客户端登录到 127.0.0.1:1234,建立连接后,服务端会启动 bash 程序,并接收来自客户端的标准输入,将标准输出发送给客户端。

三、第三方 App 与 Termux 建立 TCP/Socket 通信

通过 RunCommandService 调用 Termux 执行 nc 命令反弹某个程序,然后通过 java.net.Socket 建立 Socket 连接,取得 Socket 的 IO 流,即可实现进程间通信。

调用 Termux。注意,Termux 可使用两个版本的 Netcat:安卓自带的 /system/bin/nc 和 Termux 仓库的 netcat-openbsd。前者随 ToyBox 在 Android Marshmallow 被引入,支持反弹 shell,而后者不支持;后者支持抽象命名空间 UDS。所以我们使用 /system/bin/nc

intent.setClassName("com.termux", "com.termux.app.RunCommandService");
intent.setAction("com.termux.RUN_COMMAND");
intent.putExtra("com.termux.RUN_COMMAND_PATH", "/system/bin/nc");
intent.putExtra("com.termux.RUN_COMMAND_ARGUMENTS", new String[]{"-l", "-s", "127.0.0.1", "-p", "1234", "bash"});
intent.putExtra("com.termux.RUN_COMMAND_WORKDIR", "/data/data/com.termux/files/home");
intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", true);
intent.putExtra("com.termux.RUN_COMMAND_SESSION_ACTION", "0");
startService(intent);

建立 Socket 连接:

Socket mSocket;
InputStream mInput;
OutputStream mOutput;
public void connect() {
  mSocket = new Socket();
  new Thread(){
    public run() {
      try {
        sk.connect(new InetSocketAddress("127.0.0.1", 1234));
        mInput = sk.getInputStream();
        // 写入命令/发出数据
        mOutput = sk.getOutputStream();
        mOutput.write("ls\n");
        mOutput.flush();
        // 读取结果
        Thread.sleep(200L);
        int l = mInput.avaliable();
        byte[] bs = new byte[l];
        mInput.read(bs);
        System.out.println(new String(bs));
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }.start();
}

四、应用:调用 LSP 语言服务器

语言服务器协议(Language Server Protocol, LSP)是微软推出的一个基于 JSONRPC 的数据协议,用于

Termux 的软件仓库里正好有 clangdccls 两个 C/C++ 的 LSP 服务器端。笔者测试 ccls 时遇到 BUG,故选用 clangd 测试。

安装 clangd

apt install clangd

nc 反弹 clangd

/system/bin/nc -l -s 127.0.0.1 -p 48455 clangd

Android 客户端建立 Socket IO 通信:

Socket sk = new Socket(new InetAddress("127.0.0.1", 48455));

注意,安卓中 Socket 的 IO 流不允许在 UI 主线程进行操作,需要另起线程,以免阻塞主线程引起卡顿。

读取线程:

new Thread() {
  public void run() {
    InputStream mIn = sk.getInputStream();
    final int L = 1024;
    byte[] buf = new byte[L];
    while (mIn.read(buf, 0, 16)!=-1) {
      if (new String(buf, 0, 16).equals("Content-Length: ")) {
        // read int c
        // skip \r\n\r\n
        // read c bytes
      }
    }
  }
}.start();

写入线程:

Thread td = new Thread() {
  public void run() {
    try {
      OutputStream mOut = sk.getOutputStream();
      byte[] s="{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"initialize\",\"params\":{}}".getBytes(StandardCharsets.UTF_8);
      mOut.write(("Content-Length: "+s.length+"\r\n\r\n").getBytes());
      mOut.write(s);
      mOut.flush();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
};
td.start();
td.join(); // 阻塞写入线程,避免同时写入

笔者的开源项目:TermuC - github.com/RainbowC0


参见

  1. android共享内存(ShareMemory)的实现 - 简书
  2. 彻底弄懂netcat命令的使用 - CSDN
  3. What is toybox? - Landley
  4. 语言服务器协议概述 - Microsoft Learn

与第三方App与Termux命令建立IO通道相似的内容:

第三方App与Termux命令建立IO通道

第三方 App 调用 Termux 执行命令基本实现,但是 bash、awk、clangd 这类命令可以从标准输入读取信息并维持运行,Termux 第三方调用缺乏有效支持。了解安卓的 IPC 机制,建立Termux 命令与第三方 App 的 TCP/Socket 连接,最终实现前后端的持续通信。

Vue第三方库与插件实战手册

这篇文章介绍了如何在Vue框架中实现数据的高效验证与处理,以及如何集成ECharts、D3.js、Chart.js等图表库优化数据可视化效果。同时,探讨了Progressive Web App(PWA)的接入与优化策略,以提升Web应用的用户体验与加载速度。

投放视频广告时,如何快速与第三方播放器兼容?

新媒体时代,广告样式越来越丰富。相较于传统的图文信息,视频类广告更具有直观性,能够让消费者在了解产品知识和功能的同时加深对产品的印象。 因此在各类网站或App上投放视频类广告是个很好的宣传方式,但广告商们如果想在网站上展示视频广告,必须确保视频广告投放协议与发布渠道的播放器兼容;如果不能兼容,广告商

iOS16新特性 | 灵动岛适配开发与到家业务场景结合的探索实践

苹果在iOS16.1系统对第三方开放了灵动岛的API,并允许开发者基于灵动岛开发相应软件,越来越多的APP开始基于灵动岛的交互进行设计和开发,本文将简单介绍灵动岛开发的流程和将其与业务场景相结合的思考。

【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)

在使用App Service服务部署业务应用,因为有些第三方的接口需要调用者携带TLS/SSL证书(X509 Certificate),在官方文档中介绍了两种方式在代码中使用证书: 1) 直接使用证书文件路径加载证书 new X509Certificate2 2) 从系统的证书库中通过指纹加载...

Springboot 实现QQ登录(界面跳转)

现在第三方登录已经变成主流app的登录方式了 今天记录一下如何给自己的网站实现第三方登录(这里以QQ登录为例)

创建framework静态库和.a静态库

在APP项目中使用的静态库有两种,一是.a静态库,另一种是framework静态库。下面分布介绍这2中静态库的创建过程,以及通过脚本工具做自动化打包的2种方式。 Framework静态库生成 如果APP项目和SDK项目都使用了pod第三方库,那么podfile文件设置如下: # App项目的Podf

FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库

​《FFmpeg开发实战:从零基础到短视频上线》一书的例程主要测试本地的音视频文件,当然为了安全起见,很多网络视频都采用了https地址。FFmpeg若要访问https视频,就必须集成第三方的openssl库,但编译FFmpeg时却默认关闭了openssl。为了让App能够播放采用https的在线视

使用doop识别最近commons text漏洞的污点信息流

本文基于笔者对doop静态程序分析框架源代码和规则学习,并结合对目前漏洞公开技术细节的学习,修改增强doop app only模式下的分析规则后,实现通过doop工具识别commons text rce漏洞(CVE-2022-42889)。内容包含三部分,第一部分简单介绍doop分析框架,第二部分简单介绍commons text漏洞的原理和代码调用栈,第三部分重点介绍如何改造doop app on

FFmpeg开发笔记(三十八)APP如何访问SRS推流的RTMP直播地址

​《FFmpeg开发实战:从零基础到短视频上线》一书在第10章介绍了轻量级流媒体服务器MediaMTX,通过该工具可以测试RTSP/RTMP等流媒体协议的推拉流。不过MediaMTX的功能实在是太简单了,无法应用于真实直播的生产环境,真正能用于生产环境的流媒体服务器还要看SRS或者ZLMediaKi