Toavxxx/android-tcpdump-adb-capture

GitHub: Toavxxx/android-tcpdump-adb-capture

通过 NDK 交叉编译 tcpdump 到 Android 并用 adb 离线抓包,绕开 Wireshark Windows 版 androiddump 的 2 秒断流 bug。

Stars: 0 | Forks: 0

# Android tcpdump 自编译 + adb 离线抓包工具 在 Android 14(已 root)设备上,通过 NDK 交叉编译 tcpdump,配合 adb 实现稳定的离线抓包,绕开 Wireshark 在 Windows 上通过 androiddump 实时抓包时的已知 bug。 ## 背景 Wireshark 自带的 `androiddump` extcap 可以通过 adb 调用手机端 tcpdump 实时抓包,但: 1. 很多手机系统自带的 tcpdump 残缺或不可用(仅返回错误码,无任何功能)。 2. Windows 平台的 Wireshark(截至 4.6.6 仍存在)有一个已知 bug:如果某个 Android 接口连续 **2 秒没有新数据包**,会直接报 `Broken socket connection` 并断开抓包。详见 [wireshark/wireshark#20386](https://gitlab.com/wireshark/wireshark/-/issues/20386)。 解决思路:自己交叉编译一份 tcpdump 推到手机上,**放弃实时抓包,改用离线抓包(写文件 + adb pull)**,完全绕开这个 Windows 限制。 ## 环境 - Windows 10/11 - [MSYS2](https://www.msys2.org/)(提供 bash 环境 + 编译工具链) - [Android NDK r29](https://developer.android.com/ndk/downloads) - 已 root 的 Android 14 设备(本例使用 KernelSU / SukiSU Ultra) - adb(platform-tools) ## 一、准备 MSYS2 编译环境 打开 **MSYS2 UCRT64** 终端(开始菜单搜索 MSYS2,选 UCRT64 或 MINGW64): pacman -Syu # 如提示重启终端,关闭重新打开后再执行一次 pacman -S make autoconf automake libtool ## 二、设置交叉编译环境变量 export NDK="/d/android-ndk-r29" # 换成你自己的 NDK 解压路径,注意盘符写法 D:\ -> /d/ export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/windows-x86_64 export TARGET=aarch64-linux-android export API=34 # 对应 Android 14 export CC=$TOOLCHAIN/bin/$TARGET$API-clang export AR=$TOOLCHAIN/bin/llvm-ar export RANLIB=$TOOLCHAIN/bin/llvm-ranlib export STRIP=$TOOLCHAIN/bin/llvm-strip export LDFLAGS="-Wl,-z,max-page-size=4096" # NDK r28+ 默认 16KB 页对齐,加这个保证兼容性 ## 三、下载并编译 libpcap git clone https://github.com/the-tcpdump-group/libpcap.git cd libpcap ./autogen.sh # git clone 下来的源码没有 configure,需要先生成 ./configure --host=$TARGET --with-pcap=linux --disable-shared make cd .. 成功后会在目录下生成 `libpcap.a`。 ## 四、下载并编译 tcpdump git clone https://github.com/the-tcpdump-group/tcpdump.git cd tcpdump ./autogen.sh ./configure --host=$TARGET \ CPPFLAGS="-I../libpcap" \ LDFLAGS="-L../libpcap $LDFLAGS" \ --without-crypto make cd .. 成功后 `tcpdump/tcpdump` 就是编译好的 ARM64 可执行文件,用 `file tcpdump` 可以确认架构。 ## 五、推送到手机并验证 adb push tcpdump/tcpdump /data/local/tmp/tcpdump adb shell chmod 755 /data/local/tmp/tcpdump adb shell su -c "chown root:root /data/local/tmp/tcpdump" # 验证 adb shell su -c "/data/local/tmp/tcpdump --version" 正常应输出类似: tcpdump version 5.0.0-PRE-GIT libpcap version 1.11.0-PRE-GIT (64-bit time_t, with TPACKET_V3) 64-bit build, 64-bit time_t ### 常见报错 | 报错 | 原因 / 解决 | |---|---| | `su: inaccessible or not found` | Root 管理器没有给 adb shell(Shell 身份)授予 root 权限,需要在 KernelSU / SukiSU / Magisk 管理界面里手动开启 | | `/data/local/tmp/tcpdump: Permission denied` | 部分 ROM 把 `/data/local/tmp` 设为 noexec,执行 `adb shell su -c "mount -o remount,exec /data/local/tmp"` | ## 六、一键抓包脚本 `capture.sh` 把下面内容保存为 `capture.sh`,放在任意目录下。 #!/bin/bash # ========================================================== # Android tcpdump 抓包脚本 # # 用法: # ./capture.sh # 默认抓 wlan0 全部流量 # ./capture.sh wlan0 # 同上,显式指定接口 # ./capture.sh wlan0 "host 1.2.3.4" # 只抓和指定 IP 通信的流量 # ./capture.sh any "port 443" # 抓所有接口上 443 端口流量 # # 按 Ctrl+C 停止抓包,脚本会自动: # 1. 给手机端的 tcpdump 发 SIGINT,让它正常结束并把 pcap 文件写完整 # 2. 把文件拉取到本地 ./captures/ 目录(始终相对脚本自身所在位置) # 3. 删除手机上的临时文件 # ========================================================== set -u # 只排除手机端路径(/data、/sdcard)不被自动转换成 Windows 路径 # 本地保存路径(如 /c/Users/.../captures/xxx.pcap)仍会被正常转换成 Windows 格式 # 注意:多个前缀之间必须用分号 ; 分隔,不能用冒号 export MSYS2_ARG_CONV_EXCL="/data;/sdcard" # 始终以脚本文件自身所在目录为基准保存文件,不受调用时所在目录影响 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" IFACE="${1:-wlan0}" FILTER="${2:-}" TCPDUMP_PATH="/data/local/tmp/tcpdump" TIMESTAMP=$(date +%Y%m%d_%H%M%S) REMOTE_PCAP="/sdcard/capture_${TIMESTAMP}.pcap" LOCAL_DIR="${SCRIPT_DIR}/captures" LOCAL_PCAP="${LOCAL_DIR}/capture_${TIMESTAMP}.pcap" mkdir -p "$LOCAL_DIR" echo "==========================================" echo " Android tcpdump 抓包" echo " 接口 : $IFACE" echo " 过滤条件 : ${FILTER:-(无,抓全部流量)}" echo " 手机文件 : $REMOTE_PCAP" echo " 本地保存到: $LOCAL_PCAP" echo " 按 Ctrl+C 停止抓包" echo "==========================================" # 检查设备连接 if ! adb get-state >/dev/null 2>&1; then echo "错误:未检测到已连接的设备,请检查 adb devices" exit 1 fi # 检查手机上 tcpdump 是否存在 if ! adb shell "[ -f $TCPDUMP_PATH ]" 2>/dev/null; then echo "错误:手机上找不到 $TCPDUMP_PATH,请先确认已推送 tcpdump" exit 1 fi cleanup() { echo "" echo ">> 正在停止手机端 tcpdump 进程..." adb shell su -c "killall -2 tcpdump" >/dev/null 2>&1 sleep 1 echo ">> 正在拉取抓包文件到本地..." adb pull "$REMOTE_PCAP" "$LOCAL_PCAP" if [ -f "$LOCAL_PCAP" ]; then echo ">> 完成!文件已保存到: $LOCAL_PCAP" adb shell su -c "rm -f $REMOTE_PCAP" >/dev/null 2>&1 else echo ">> 拉取失败,手机上的文件可能还在: $REMOTE_PCAP" fi exit 0 } trap cleanup INT adb shell su -c "$TCPDUMP_PATH -i $IFACE -w $REMOTE_PCAP $FILTER" 赋予执行权限后运行: chmod +x capture.sh ./capture.sh wlan0 按 `Ctrl+C` 停止,文件会自动出现在 `capture.sh` 同级目录下的 `captures/` 文件夹里,可直接用 Wireshark 打开。 ## 七、按 App 过滤流量(可选) tcpdump 不识别"应用"概念,但可以先找到目标 App 的 UID,再反查它正在通信的远程 IP,针对性抓包: # 1. 确认包名对应的 UID adb shell pm list packages -U | grep <包名> # 2. 查看该 UID 当前的 TCP 连接(远程 IP:端口,十六进制小端序) adb shell su -c "cat /proc/net/tcp" | awk '$8 == "" {print $2, $3}' # 3. 拿到远程 IP 后,针对性抓包 ./capture.sh wlan0 "host <远程IP>" ## 踩坑记录(MSYS2 / Windows 特有问题) 1. **路径自动转换坑**:MSYS2/Git Bash 会把以 `/` 开头的参数自动转换成 Windows 路径再传给原生 exe(比如 `adb.exe`)。导致 `/data/local/tmp/tcpdump` 被错误转换成 `C:/msys64/data/local/tmp/tcpdump`。 解决:设置 `MSYS2_ARG_CONV_EXCL` 排除指定前缀,**注意多个前缀之间用分号 `;` 分隔,不是冒号 `:`**。 export MSYS2_ARG_CONV_EXCL="/data;/sdcard" 2. **Wireshark Windows 版 2 秒断流 bug**:见上文背景说明,目前(4.6.6)仍未修复,建议直接用本仓库的离线抓包方案规避。 3. **PowerShell 无法运行 .sh 脚本**:必须在 MSYS2 / Git Bash 终端里执行 `./capture.sh`,CMD/PowerShell 只能跑 `adb` 单条命令。 ## License MIT
标签:adb, Android, DSL, NDK, Wireshark, 交叉编译, 句柄查看, 情报分析, 网络抓包, 网络诊断