仅用Android手机拯救Linux主机,带你深入了解USB Gadget

Chongxi admin

0. 引

首先介绍一下本期主角,Chongxi之前购入过一台玩客云小主机,并给他刷了Ubuntu armv7,当作一个轻量的服务器来使用,在上面跑跑AdguardHome这种小玩意。在爆改的过程中,因为配置文件错误,导致主机的网卡死了,无法进行ssh连接,由于所处环境没有实体键盘以及HDMI显示器用,主机也没有reset按钮,使这台主机成了半残废的状态。

0.1 食材准备

首先介绍下救砖工具:

  • 一台root过的Android手机
  • USB数据线
    所需软件:
  • USB Gadget Tool
  • Android HID Keyword

所需文件均已给出其GitHub链接,您也可以通过Atlas快递站一键下载所需文件。

1. 原理讲解

其实非常简单,就是拿Android设备模拟成键盘,输入到主机中。至于无HDMI可视化是如何判断命令输出的?答案是,IO灯
对,你没听错,大多数人可能听说过靠主板IO灯来debug,很少听说过靠IO灯来判断输入输出并拯救ubuntu主机吧,当你输入操作和主机输出时,IO灯会闪烁,本文就是靠IO灯来诊断的

既然知道了原理,那么接下来救砖就一定很简单了…吧?

1.1 拦路虎

首先,绝对不是你想的「把数据线一接,然后打开Gboard就能输入」这么简单。
USB协议有严格的主从关系,你插上主机后,大概率是被主机作为要被调试的设备,而不是反过去调试主机。
再者就是BadUSB风险,这里简单过一下基本知识

BadUSB

BadUSB是最经典的攻击手段之一,USB协议有一个信任漏洞,主机会无条件信任设备对自己身份的声明,你说你是键盘他就会相信,没有额外的校验过程。一个简单的BadUSB攻击过程如下

  1. 将攻击设备插入主机
  2. 攻击设备向主机声明他是U盘,主机信任并加载
  3. 攻击设备主动断开连接,并以HID的声明重新连接,主机并不会校验他到底是不是键盘,会直接加载驱动,无任何防备接受一切来自此设备的输入
  4. 攻击设备开始向主机注入命令(如启动powershell下载木马),而在主机看来,这可能是一个打字飞快的人类,所以不会有任何阻拦

这和你的android手机又有什么关系?

如果你的android设备有完整的USB Gadget权限,他就能变成OURWORLD里最强大最隐蔽的BadUSB,谁会怀疑一个毫无威胁的正在充电的手机呢?
你可以使用Termux写攻击脚本来对目标设备注入,对方以为你在充电,实则模拟成键盘,甚至USB网卡劫持流量来发起中间人攻击,NetHunter就是一个专门为Android设备定制的渗透用rom,可以随意控制手机USB接口,伪装成各种设备

OEM厂商 Google Android社区都明白,对于这么巨大的安全隐患,做决策就非常简单了,直接砍掉
因为对于普通消费者来说,他们用USB传输顶多就是互传照片文件和网络共享,直接干掉Gadget无疑是OEM厂商的必然选择,风险实在过于严重

那么,我是如何让Android设备成功模拟成HID对Ubuntu进行输入的呢

2. 实现原理

Talk is cheap, show me the code.

我们直接来看 Linux 内核的官方configfs.txt来解释,为什么用户空间程序能够控制内核级别的硬件行为

2.1 内核提供蓝图 而不是成品

1
Where sysfs is a filesystem-based view of kernel objects, configfs is a filesystem-based manager of kernel objects

也就是说,sysfs 是让你看内核已经创建好的东西(比如你的 CPU 温度),而 configfs 是让你要求内核为你创建新的东西。
当 Android 内核被编译时,开启了 CONFIG_USB_GADGETCONFIG_USB_HID 选项后,内核并不会立刻创建一个USB键盘设备。它只是在 /config/usb_gadget/ 目录下,准备好了基础工具,等着你来超级拼装

2.2 mkdir

1
A configfs config_item is created via an explicit userspace operation: mkdir(2).

你在 configfs 里每创建一个目录,就等于在调用一个内核函数

比如

1
mkdir /config/usb_gadget/g1
  • 这个命令执行时,configfs会通知USB Gadget:用户想创建一个新的 Gadget 实例 g1
  • 内核模块后在内存里分配了一块空间,用来描述这个即将被创建的USB设备

2.3 目录与文件

1
The item's attributes will also appear at this time.

mkdir 成功后,内核会立刻在这个新目录里,为你生成一堆配置文件,这些文件就是这个新对象的可配置属性

比如我们 mkdir g1 之后,ls /config/usb_gadget/g1 可能会看到类似这样的东西:

1
2
3
4
5
6
idVendor     # 厂商ID
idProduct # 产品ID
strings/ # 各种字符串描述,比如厂商名
functions/ # 定义了这个 Gadget 能扮演什么设备
configs/ # 具体的USB配置绑定
UDC # 把配置好的 Gadget 绑定到物理 USB 控制器上

2.4 写入配置

1
write(2) can store new values.

也就是你用 echo 往这些属性文件里写东西,就等于在设置内核里那个对象的参数

比如让它模拟成键盘

1
2
3
4
5
6
7
8
mkdir /config/usb_gadget/g1/functions/hid.usb0

# 配置参数
echo "..." > /config/usb_gadget/g1/functions/hid.usb0/report_desc

# 创建一个USB配置,绑定键盘功能
mkdir /config/usb_gadget/g1/configs/c.1
ln -s /config/usb_gadget/g1/functions/hid.usb0 /config/usb_gadget/g1/configs/c.1

2.5 激活

1
[configfs handles] the filesystem representation... allowing the subsystem to ignore all but the basic show/store interaction.

内核模块本身不关心你是怎么创建和配置的,它只在最后一步,等待激活

1
2
# 找到你手机的 USB 控制器名称 (比如 a12345.dwc3),然后把它写入 UDC 文件
echo "a12345.dwc3" > /config/usb_gadget/g1/UDC

当 UDC 文件被写入时,内核的 USB Gadget 模块会收到一个Commit信号
它会读取你刚才在 g1 目录下做的所有配置,把它们组装成一个完整的 USB 设备描述符
然后,它会命令物理 USB 控制器断开当前的连接,并以键盘身份重新连接到主机

这样,就完成了 Android设备模拟成键盘输入设备的操作。

3. 我是如何救砖的

  1. 确保你的android手机已root,安装前文的两个开源工具,在Gadget Tool中授予su权限,并勾选启用HID Keyboard,便完成了Android设备模拟成键盘的操作

  2. 使用数据线将Android设备接入ubuntu主机,此时手机会被识别成输入设备,当你按下HID Keyboard提供的软键盘时,是能够看到IO灯闪烁的,接下来的诊断完全是靠IO灯判断的

  3. 尝试输入密码并等待十秒,建议直接使用root账号,可以省去sudo的麻烦,这种情况在乎用户组安全没啥必要,随后执行ls观察IO灯是否剧烈闪烁,如果剧烈闪烁则说明ls成功提供了输出,为了稳妥起见,这里决定reboot一下,主机重启,说明我们登录操作没问题

  4. Chongxi这里是提前准备过一个恢复脚本,防止这种铸币情况,主要功能是恢复原来的网卡备份的内容。再次通过io灯判断输入,直接执行恢复命令,主机重启,打开openwrt,发现ubuntu对应的LAN口开始有正常流量通信,ssh可以正常连接,救砖成功

4. 结

本文确实已经超出了普通Linux桌面版使用的范畴,可以说是纯粹的炫技,需要你的设备内核支持且已root,可以说是天时地利人和都很考验的一种解决方案

对于Linux玩家来说,没有绝对的死局,只有你还未发现的后门,这就是卓越的开放性

  • 标题: 仅用Android手机拯救Linux主机,带你深入了解USB Gadget
  • 作者: Chongxi
  • 创建于 : 2025-12-16 16:34:26
  • 更新于 : 2026-01-03 03:01:44
  • 链接: https://blog.chongxi.us/2025/12/16/aKeyboardHsf/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。