Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
AndroidAuto — 开源Android Auto手机端实现,包含协议逆向工程、TLS双向认证、H.264视频投影、触摸输入注入以及通过USB AOA传输传感器数据流。 | Kitploit
工具/GitHubGitHub/mretallack/androidauto
Android安全蓝牙安全逆向工程无线安全移动安全论文与研究学习与教育
GitHubmretallack/androidauto

AndroidAuto

开源Android Auto手机端实现,包含协议逆向工程、TLS双向认证、H.264视频投影、触摸输入注入以及通过USB AOA传输传感器数据流。

查看仓库
112个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Open Android Auto

Android Auto 手机端应用的开源实现。此应用在手机上运行,通过USB将画面投射到汽车头机,替代Google专有的 com.google.android.projection.gearhead APK。

⚠️ 正在进行中

本项目处于早期开发阶段。协议握手和视频投影已在真实头机上成功运行。手机屏幕可在汽车头机上成功显示约几秒钟后断开(视频稳定性正在改进)。

功能

协议与连接

  • USB AOA 附件模式检测与连接
  • TLS 1.2 双向认证(手机作为服务器)
  • 版本协商(协议 v1.7)
  • 服务发现(请求/响应)
  • 在目标通道上打开通道(视频、音频、输入、传感器)
  • Ping/Pong 保活(双向)
  • 音频焦点请求/响应处理
  • 导航焦点请求/响应处理
  • 语音会话请求处理
  • 优雅关闭处理
  • 优先级写入队列(控制消息优先于视频)
  • 发送音频前等待音频焦点授予(每 HUIG 500ms 超时)
  • 蓝牙配对交换(BluetoothPairingRequest/Response)
  • 处理多次 USB 重连而无需重新初始化 AOAP

视频投影

  • 通过 MediaCodec 进行 H.264 编码(800x480 @ 30fps,Baseline 级别)
  • MediaProjection 屏幕捕获(显示用户权限对话框)
  • 视频通道设置(SETUP → CONFIG → FOCUS → START 流程)
  • 基于零的时间戳(微秒)
  • SPS/PPS 附加到关键帧(Annex B 格式)
  • 流控制(max_unacked 跟踪、背压)
  • 帧速率控制(一致的 33ms 间隔)
  • 稳定的长时间视频(目前约 7 秒后断开)
  • 根据头机服务发现进行分辨率协商
  • 基于连接质量的自适应比特率

触摸输入

  • 输入通道打开与绑定请求
  • 触摸事件解析(单点与多点触摸)
  • 按键事件解析(按钮、媒体键)
  • 坐标映射(头机分辨率 → 手机分辨率)
  • 使用 MotionEvent 创建的 TouchInjector
  • 将触摸事件注入到 VirtualDisplay
  • 将按键事件注入到 Android 系统

音频

  • 音频通道打开与设置
  • 发送音频前等待音频焦点授予(每 HUIG 500ms 超时)
  • 初始连接时发送 AUDIO_FOCUS RELEASE,开始播放时发送 GAIN
  • 手机音频捕获(MediaProjection AudioPlaybackCapture)
  • PCM/AAC 编码并传输到头机
  • 从头机接收麦克风输入(语音命令)
  • 多音频通道(媒体、系统、语音、导航)
  • 流式传输静音音频以保持通道活跃

传感器

  • 传感器通道打开
  • 传感器启动请求/响应处理
  • 夜间模式数据解析与发送
  • 驾驶状态数据解析与发送
  • GPS 位置转发
  • 指南针方向
  • 车速
  • RPM
  • 里程表(总里程 + 单次里程)
  • 油量及续航里程
  • 驻车制动状态
  • 挡位位置(P/R/N/D/1-10)
  • OBD-II 诊断
  • 环境(温度、气压、降雨)
  • HVAC(目标/当前温度)
  • 推估定位
  • 乘客存在
  • 车门状态(引擎盖、后备箱、各车门)

视频(附加)

  • 根据头机服务发现进行分辨率协商
  • 基于连接质量的自适应比特率
  • 支持 720p、1080p、1440p、4K 分辨率
  • 竖屏分辨率(720x1280、1080x1920 等)
  • UI 配置更新(主题、内边距)

其他

  • 蓝牙配对协调(A2DP、HFP)
  • 导航逐向指引到仪表盘
  • 导航状态(操作、车道、距离、当前位置)
  • 媒体状态(当前播放信息)
  • 媒体播放元数据(曲目、艺术家、专辑)
  • 媒体浏览器(从头机浏览手机媒体库)
  • 电话状态(通话状态通知)
  • 通用通知(订阅/取消订阅系统)
  • 供应商扩展
  • 无线 Android Auto(WiFi + 蓝牙切换)
  • 通道关闭通知
  • 汽车连接设备请求/响应
  • 用户切换请求/响应
  • 电池状态通知
  • 通话可用性状态
  • 服务发现更新(动态通道变化)
  • 输入反馈(触觉/视觉反馈到头机)
  • 麦克风请求/响应(从头机进行语音输入)

⚠️ 免责声明

请自行承担风险使用。 本软件按“原样”提供,不提供任何形式的担保。

  • 本软件可能导致您的汽车头机出现意外行为。
  • 本软件可能损坏您的手机或头机——作者不承担任何责任。
  • 请勿在驾驶时使用本应用程序
  • 请勿在操作车辆时与本应用程序交互
  • 本应用程序仅用于开发和测试目的。
  • 在操作任何手机应用程序之前,请务必靠边停车并熄火。
  • 作者对因使用本软件造成的任何事故、伤害或损害不承担责任。

架构```

USB Plug-in → MainActivity → ProjectionService ↓ UsbAoaTransport (USB AOA accessory mode) ↓ MessageFramer (16KB frame fragmentation) ↓ InBandTls (TLSv1.2 via SSLEngine) ↓ ProtocolEngine (AAP state machine) ↓ ┌───────────┼───────────┐ Video Input Audio (H.264) (touch/keys) (PCM)

root@kitploit:~
## 已知问题

- **通道分配假定顺序** — 我们分配 `SERVICE_DISCOVERY_RESPONSE` 中的第一个 `av_channel` 为视频,第二个为音频。这在车载主机上有效(通道1 = 视频),但在 openauto 上失败(通道4 = 音频,而非视频)。修复方案:解析 `av_channel` 内的 `stream_type` 字段以区分 `VIDEO(3)` 和 `AUDIO(1)`。
- **视频稳定性** — 由于车载主机 USB 缓冲区溢出,长时间流传输后连接会断开。参见下面的测试结果。
- **车载主机上设备重复显示** — 车载主机的智能手机页面将我们的应用显示为两个独立条目(一个用于 Android Auto,一个用于蓝牙),而非同时显示这两种功能的单个条目。这是由于 Android 12+ 阻止访问真实的蓝牙 MAC 地址(返回 `02:00:00:00:00:00`)。临时解决办法:通过 `adb shell "echo $(adb shell settings get secure bluetooth_address) > /sdcard/Android/data/org.openandroidauto/files/bt_address.txt"` 将真实地址写入配置文件。需要一个 UI 设置界面让用户手动输入其蓝牙 MAC 地址。
- **语音助手按钮未被处理** — 当驾驶员按下车载主机上的语音/助手按钮时,我们收到 `VOICE_SESSION_REQUEST` 并尝试启动一个语音助手(Dicio 或系统默认)。但启动的助手尚未接收到来自车载主机麦克风的音频。

### 视频稳定性测试结果

测试图案(彩条)在 800x480 分辨率下,I帧间隔 1 秒:

| FPS | 比特率 | 分片 | 持续时间 | 帧数 | 状态 |
|-----|--------|------|----------|------|------|
| 30 | 2Mbps | 否 | ~3s | ~90 | ❌ 过快 |
| 15 | 2Mbps | 否 | ~33s | ~500 | ⚠️ 较好 |
| 10 | 2Mbps | 否 | ~93s | ~930 | ⚠️ 良好 |
| 30 | 2Mbps | 是(2KB) | 5-25s | 150-750 | ⚠️ 不稳定 |
| 30 | 500Kbps | 是(2KB) | ~54s | ~1691 | ⚠️ 较好 |
| 15 | 250Kbps | 是(2KB) | ~67s+ | 1000+ | ⚠️ 良好 |
| 30 | 250Kbps | 是(2KB), I=5s | ~20s | ~600 | ❌ 较长 I帧时更差 |
| 15 | 250Kbps | 否 | ~13s | ~200 | ❌ 分片在此有帮助 |

根本原因:车载主机 USB 接收缓冲区在持续高吞吐量下溢出。较低的数据速率意味着更长的连接时间。

**最佳确认配置:** 10fps,2Mbps,无分片 = 93 秒。分片后加密的实现存在缺陷(车载主机无法重组)——需要进一步调查。

## 构建```bash
./gradlew assembleDebug

需要 Android SDK 及平台 35。

测试

单元测试```bash

./gradlew testDebugUnitTest

root@kitploit:~
113 个单元测试和集成测试,涵盖协议、帧、TLS、通道逻辑、视频状态机、传感器处理和触摸输入。

### 使用 openauto(Docker)进行集成测试

openauto 是一个第三方车机模拟器,支持完整的 Android Auto 协议。我们用它来验证我们的协议实现,无需真实车辆。

#### 前提条件

- Docker 已安装并运行
- 手机通过 ADB 连接(USB 或无线)
- 已在手机上安装应用:`./gradlew assembleDebug && adb install -r app/build/outputs/apk/debug/app-debug.apk`

#### 1. 构建 openauto Docker 镜像(一次性)```bash
cd thirdparty/openauto
docker build -f Dockerfile.headless -t openauto-headless .

此命令将在 Debian 容器中构建 openauto 及其所有依赖项(Qt5、boost、protobuf、OpenSSL)。首次构建大约需要5分钟。

2. 启动 openauto```bash

docker run --rm -p 5100:5000 -e QT_QPA_PLATFORM=offscreen
openauto-headless timeout 60 /src/build/bin/autoapp

root@kitploit:~
openauto 在容器内监听端口 5000,映射到主机的端口 5100。它以无头模式运行(无需显示器)。

#### 3. 设置 ADB 反向端口转发```bash
adb reverse tcp:5000 tcp:5100

这使得手机的 localhost:5000 隧道连接到计算机的 localhost:5100 (openauto)。当没有找到 USB 附件时,我们的应用作为 TCP 客户端连接到 localhost:5000。

4. 启动应用```bash

adb shell am start -n org.openandroidauto/.MainActivity

root@kitploit:~
该应用将会:
1. 无法找到USB配件
2. 连接到 `localhost:5000`(通过adb reverse的openauto)
3. 执行完整的协议握手(VERSION → TLS → AUTH → SERVICE_DISCOVERY)
4. 打开通道(视频、音频、输入、传感器)
5. 开始流式传输视频(测试图案)

#### 5. 在openauto日志中验证

你应该在openauto输出中看到:```
[OpenAuto] handleNewClient() - Handle WIFI Client Connection
[OpenAuto] [AndroidAutoEntity] Send Version Request.
[OpenAuto] [AndroidAutoEntity] onVersionResponse()
[OpenAuto] [AndroidAutoEntity] Beginning SSL handshake.
[OpenAuto] [AndroidAutoEntity] Handshake completed.
[OpenAuto] [AndroidAutoEntity] onServiceDiscoveryRequest()
[OpenAuto] [AndroidAutoEntity] onAudioFocusRequest()
[OpenAuto] [AudioMediaSinkService] onChannelOpenRequest()
[OpenAuto] [VideoMediaSinkService] onChannelOpenRequest() (if video focus granted)

6. 检索应用日志```bash

adb pull /sdcard/Android/data/org.openandroidauto/files/aa_log.txt cat aa_log.txt

root@kitploit:~
日志文件在 USB 切换之间持久保存在手机上(在真实车载主机上测试时很有用)。

#### 快速单行测试```bash
# Assumes openauto image already built and app installed
docker run --rm -p 5100:5000 -e QT_QPA_PLATFORM=offscreen openauto-headless timeout 20 /src/build/bin/autoapp &
sleep 3 && adb reverse tcp:5000 tcp:5100 && adb shell am start -n org.openandroidauto/.MainActivity

注意

  • openauto 使用协议 v1.6;我们的应用响应 v1.7(两者均被接受)
  • openauto 为 AUTH_COMPLETE 记录 Message Id not Handled: 4 — 这是已知的 openauto 特性,非错误
  • 连接应保持长期稳定(无超时/断开)
  • 视频不显示(无头模式),但协议交换已完全验证

协议参考

  • uglyoldbob/android-auto (Rust, LGPL-3.0) — 带 protobuf 定义的协议实现
  • opencardev/aasdk (C++, GPL-3.0) — 更新后的协议库,包含完整 protobuf 定义
  • opencardev/openauto (C++, GPL-3.0) — 车机端模拟器 (Crankshaft-NG)
  • tomasz-grobelny/AACS (C++, GPL-3.0) — 手机端 AA 实现(用于 ODROID)
  • headunit-revived (Kotlin, AGPL-3.0) — 车机端实现
  • f1xpl/aasdk (C++, GPL-3.0) — 原始协议库
  • GAL 协议研究 — 协议笔记、Wireshark 解析器和缓存的车机集成指南

Protobuf 定义演化

Android Auto 协议通过多个项目逆向工程得来。每个项目都基于前者的工作:

opencardev/aasdk 相比 AACS 新增的内容:

  • 广播服务(AM/FM/HD/DAB 调谐、预设、RDS、交通信息)
  • 导航状态(完整逐向导航:操作、车道、距离、提示)
  • 电话状态(通话状态通知)
  • 媒体浏览器(从车机浏览手机媒体库)
  • 媒体播放状态(当前播放元数据)
  • 通用通知(订阅/取消订阅系统)
  • WiFi 投射(无线 AA 凭据和热点配置)
  • GAL 验证(Google Automotive Link 测试/调试)
  • 仪表盘(辅助显示输入)
  • UI 配置(主题白天/夜间、内边距、显示配置)
  • 电池状态、用户切换、电子标签卡、EV 连接器类型
  • 服务发现更新(动态通道变更)
  • 扩展视频分辨率(1440p、竖屏变体)
  • 扩展控制消息(26 种类型 vs 13)

关键结构差异:

  • AACS 在 ChannelOpenRequest 中使用 priority + channel_id;aasdk 使用 priority (sint32) + service_id
  • AACS 的 ServiceDiscoveryResponse 仅为一个通道列表;aasdk 增加了 HeadUnitInfo、DriverPosition、PingConfiguration、ConnectionConfiguration
  • aasdk 将媒体分为 Sink(车机接收)和 Source(车机发送),具有不同的消息 ID

本项目的权威协议参考位于 thirdparty/aasdk/protobuf/ 目录。

TLS 认证

Android Auto 使用双向 TLS。手机充当 TLS 服务器,必须提供由 Google Automotive Link CA(嵌入在车机固件中)签发的证书。没有正确的私钥,车机会拒绝连接并返回 AUTH_COMPLETE status=-3。

证书链

手机呈现一个由两个证书组成的链:

  1. CarService 证书 — O=CarService,由 Google Automotive Link CA 签名
  2. Google Automotive Link CA — 自签名根证书,O=Google Automotive Link(有效期 2014-2044)

认证方式

  1. 车机固件中嵌入了 Google Automotive Link CA 的公钥并信任它
  2. 在 TLS 握手期间,手机出示 CarService 证书(由该 CA 签名)
  3. 手机通过使用对应的私钥对 TLS 握手进行签名,证明对该证书的所有权
  4. 车机验证签名是否与证书的公钥匹配,并且该证书的信任链追溯到受信任的 CA

证书轮换(理论 — 未经确认)

Google 似乎每隔约 8 个月轮换一次嵌入在 Android Auto APK 中的证书+私钥(与证书有效期一致)。这可能是限制提取密钥使用期限的刻意措施——如果车机检查证书过期时间,旧的提取密钥将失效。官方应用的用户通过应用更新获得新证书。如果该理论成立,不更新官方应用的用户最终可能会被检查过期时间的车机拒绝。并非所有车机都检查过期时间——具体行为取决于型号。

获取私钥

私钥在 Android Auto APK 内以 AES-256-CBC 加密存储。车机会验证手机的证书是否由 Google Automotive Link CA 签名——任何由该 CA 签名的证书都会被接受。

方法 A:从 APK 解密

该密钥嵌入(加密)在 Android Auto APK 中,并可使用 APK 自身的算法解密。这需要一台具有 ADB 访问权限的 Android 设备(无需 root,无需 Google Play 服务)来运行解密,因为 Android 的 Base64 解码器行为与桌面 JVM 不同。

需求:

  • Android Auto APK(通过 adb pull 从手机拉取,或从 APKPure/APKMirror 下载)
  • 任何具有 ADB 访问权限的 Android 设备来运行解密(无需 root,无需 Google Play 服务)
  • Android SDK(d8 构建工具,adb)

步骤:

  1. 从手机拉取 AA APK:adb pull $(adb shell pm path com.google.android.projection.gearhead | grep base | cut -d: -f2) aa.apk
  2. 使用 JADX 反编译以找到证书提供者类
  3. 提取二进制数据(256 字节的 KDF salt + 约 1712 字节的加密密钥 + 证书 PEM)
  4. 将解密 Java 类编译为 DEX 并使用 dalvikvm 在设备上运行

查找证书提供者类(第 2 步):

类名是混淆的,并且在不同 APK 版本之间会变化,但结构始终相同。在 JADX 中搜索 "-----BEGIN CERTIFICATE-----"——您会找到一个实现接口的小类,该接口包含三个方法:

  • a() → 返回一个 String(CarService 证书 PEM)
  • b() → 返回一个 byte[](约 1712 字节——AES 加密的私钥)
  • c() → 返回一个 byte[](256 字节——KDF salt)

按版本的已知类名:

解密函数位于附近的类中——搜索 "AES/CBC/PKCS5Padding" 即可找到。它接受证书提供者接口作为参数。

注意: 解密步骤(第 4 步)只需要 dalvikvm——任何具有 ADB 的 Android 设备都可以,无需 root 或 Google Play 服务。GApps 的要求仅适用于第 1 步(拉取 APK,因为 AA 应用通过 Play 商店分发)。

注意: 您不需要修改或运行反编译的 APK 代码。相反,您编写一个独立的 Decrypt.java 类,重新实现解密逻辑,从文件中读取提取出的字节数组,并拥有自己的 main() 入口点。反编译的源码仅用作参考,以了解算法并复制字节数组。完整的 Decrypt.java 源码请参阅 tools/decrypt_key_from_apk.md。

关键的 JADX 错误: JADX 将 KDF 辅助函数反编译为 byte b = bArr2[i2] & 255;,但必须为 int b = bArr2[i2] & 255;。byte 类型会截断回有符号数,产生垃圾输出。修复为 int 后解密即可正常工作。

KDF(tweakBytes/ap)函数:```java static void tweakBytes(byte[] bArr, byte[] bArr2, byte[] bArr3) { for (int i = 0; i < bArr.length; i++) { for (int i2 = 0; i2 < 48; i2++) { int b = bArr2[i2] & 255; // MUST be int, not byte bArr2[i2] = (byte) (((((b >> 7) | (b + b)) + 33) ^ bArr3[i2 % bArr3.length]) ^ bArr[i]); } } }

root@kitploit:~
在AES解密之后,`T()` 函数提取密钥:
- 跳过前28字节,删除最后26字节
- 对中间部分进行Base64解码(URL_SAFE,标志位=2)
- 结果是一个PKCS#8 DER编码的RSA私钥

**注意:** 由于 `android.util.Base64` 与 `java.util.Base64` 的差异,必须在Android上运行(而不是桌面JVM)。桌面JVM的 `Base64.getUrlDecoder()` 会拒绝Android解码器所接受的标准base64字符(`+`、`/`)和换行符。在桌面上使用 `Base64.getMimeDecoder()`,或者使用 `dalvikvm` 在设备上运行解密:```bash
# Compile to DEX and run on any Android device with ADB access
javac Decrypt.java -d out
d8 out/Decrypt.class --output dex_out
adb push dex_out/classes.dex /data/local/tmp/decrypt.dex
adb shell "dalvikvm -cp /data/local/tmp/decrypt.dex Decrypt"

输出 PKCS#8 私钥的 base64 形式。将其包装在 PEM 头中,并放置在 app/src/main/assets/carservice_key.pem。

完整的分步指南请参阅 tools/decrypt_key_from_apk.md。

路径 B:使用先前提取的 cert+key

由于某些车载主机可能不会检查证书过期时间,先前提取的 cert+key 对(即使已过期)可能仍然有效。来源:

  1. 联系 opengal_proxy 作者 — 发送邮件至 [email protected](参见 gamelaster/opengal_proxy)
  2. 从已 root 并安装了 GApps 的手机中提取 — 使用 Frida 钩取 KeyFactory.generatePrivate()(需要在同一设备上同时拥有 root 权限和 Google Play 服务): ```bash frida -U -n "com.google.android.projection.gearhead" -l tools/dump_key_frida.js
    root@kitploit:~
  3. 社区 — 参见 AACS#15 进行讨论

一旦获得,将证书和密钥放在 app/src/main/assets/carservice_key.pem。

参见 tools/dump_key.sh 和 tools/dump_key_frida.js 了解运行时提取脚本。

许可证

本项目基于 GNU General Public License v3.0 授权。

本项目包含来自 aasdk 的协议缓冲区定义(GPLv3, 版权所有 © 2018 f1x.studio / Michal Szwaj)作为 git 子模块。

下载工具
  • 灯光状态(前照灯、转向灯、危险警示灯)
  • 胎压
  • 加速度计(三轴)
  • 陀螺仪(三轴)
  • GPS 卫星数据
  • 主动响应头机传感器请求
  • 音频欠载通知
  • 广播服务(AM/FM/HD/DAB 调谐、预设、RDS)
  • 项目年份Proto 文件角色
    f1xpl/aasdk20181 个整体文件 (Wifi.proto)原始逆向工程 — 核心协议、视频、音频、输入、传感器
    AACS202028 个(按消息拆分)手机端实现 — 最简覆盖视频投射
    opencardev/aasdk2024254 个(按服务分层)权威参考 — 包含所有服务的完整协议
    APK 版本证书提供者类Salt+key 类解密类
    v6.4SslWrapper(字段 o、p)同一类SslWrapper.m23915f()
    v16.8ivo / rqiivq / rql(字段 b、c)ivq.d()