adb 1.0.39 Windows版部署与Android安全设备画像实战
简介:面向 Android 开发、测试与安全调试场景的 adb 1.0.39 Windows 版工具包,适合需要在本机完成设备连接、应用部署与日志排查的初中级开发者使用。压缩包共收录 1716 个文件,整体约 9.53MB,除 adb、fastboot 等可执行文件与 dll 依赖库外,还包含大量 html 文档、py 辅助脚本、md 说明、js 与 css 前端资源以及 json 配置和 license 声明,并带有 atrace、systrace 等性能采集相关文件,目录层次接近官方 platform-tools 的原始组织方式。已有 416 人学习下载。读者可获得设备管理、文件双向传输、shell 命令执行、logcat 日志抓取、应用安装卸载与备份恢复等常用能力的完整命令行环境,也能借助包内脚本与说明理解 atrace 性能数据的采集流程,为自动化测试、脚本编写和问题定位提供可直接复用的工具链。
1. adb 1.0.39 windows版:三个文件撑起的设备侧入口
上周帮一个做移动端合规检测的朋友搭环境:机器是一台没 root 的样机,电脑是台干净的 Windows 笔记本,不许装 IDE,也不许装整套 SDK,只允许放一个绿色目录。要干的活很具体——把设备上装了哪些第三方包、每个包要了哪些高危权限、最近有没有异常日志刷屏,全部拉出来做成清单。这种场景下绕不开 adb 1.0.39 windows版这类裸二进制包:解压出来就是adb.exe加两个 DLL,丢进固定目录配好 PATH,adb devices认到设备,后面做 android 安全 方向的包枚举、权限比对、日志切片、文件取证就都有了落脚点。它适合谁?适合手上只有数据线和 Windows、想把调试链路压到最薄的人;不适合指望它替代 Android Studio 的人。这一版最需要先记住的边界是:它没有adb pair,Android 11 之后那套无线调试配对用不了,只能走老的adb tcpip路子。下面按“怎么装、怎么摸设备、怎么动数据、哪里翻车”四段拆。
2. 落地部署:把 adb.exe 从压缩包塞进 PATH 的三步与两个依赖
先把“能不能跑起来”这件事做干净。很多人拿到 adb 压缩包第一反应是双击adb.exe,然后看窗口一闪而过,以为文件坏了——它本来就是个命令行工具,双击必然闪退,这不是文件问题。
2.1 压缩包里真正必需的是哪几个文件
Windows 版的 adb 不是单文件程序,它至少依赖两个同目录的 DLL。常见做法是把整个目录一起解压,只把adb.exe单独拷出来是最典型的翻车起点。
| 文件 | 作用 | 少了会怎样 |
|---|---|---|
adb.exe | 客户端 + 服务端主程序 | 命令不存在 |
AdbWinApi.dll | Windows USB 通道封装 | 报“找不到 AdbWinApi.dll”,进程直接退出 |
AdbWinUsbApi.dll | USB 设备枚举与读写 | 能启动但adb devices永远空列表 |
fastboot.exe | 刷机模式工具,调试场景可选 | 不影响日常 adb 使用 |
我一般把整个目录解压到D:\tools\platform-tools,不放在桌面、不放在“下载”里,也不放在含中文或空格的路径下。原因在后面的避坑章节会展开,简单说:含空格的路径在某些批处理拼接里会被当成两个参数,报出来的错还特别误导。
提示:解压后的目录里如果还有
source.properties,那是版本描述文件,别删,出问题时靠它确认你手上到底是哪一版。
2.2 PATH 怎么加才不留后患
加环境变量的目的是省掉每次cd。图形界面走“系统属性 → 环境变量 → 用户变量 Path → 新建一行”,这是最稳的。命令行也能做,但有一个必须知道的风险。
@echo off REM 只改当前用户的 PATH,不要加 /M(改系统级需要管理员,且会覆盖式写入) set "ADB_DIR=D:\tools\platform-tools" REM 先看看当前 PATH 有多长,超过 1000 字符就别用 setx echo %PATH% REM setx 有 1024 字符截断的老毛病,稳妥做法是手工在图形界面追加 REM setx PATH "%PATH%;%ADB_DIR%"这段脚本的关键在注释里那两条:setx写入的是“用户变量”时生效范围有限,而它对超过 1024 字符的 PATH 会做截断——一旦截断,你机器上其他工具的路径一起失效,症状是“装了个 adb,结果 Python、Node 全找不到了”,排查起来非常费时间。所以我一般不用setx改 PATH,只在临时窗口里用set PATH=%PATH%;D:\tools\platform-tools做一次性验证,确认没问题再进图形界面固化。
验证只需要两条命令,注意第二条的-l参数,它会多打印设备型号、传输协议和连接方式,比裸adb devices信息量大得多。
# 确认客户端版本,输出里会有 "Android Debug Bridge version 1.0.39" adb version # 确认设备是否被识别,-l 输出型号与 transport_id adb devices -ladb version的输出一般有三行:版本号、Revision、Install path。如果 Revision 那行显示的不是你刚解压的目录,说明机器上还有另一份 adb 在抢戏——这是后面“版本不匹配”类故障的根。
2.3 第一次握手:5037 端口与 adb server
adb devices的执行过程其实是三步:客户端检查本机有没有 adb server 在跑;没有就拉起一个;然后 server 通过 5037 端口接收客户端指令并枚举 USB 设备。理解这条链路,后面一大半的连接问题都能自己定位。
# 看 5037 被谁占了(Windows 下) netstat -ano | findstr :5037 # 拿到 PID 后查进程名 tasklist | findstr <上面的PID> # 确认是自己这边状态脏了,重启 server 最省事 adb kill-server adb start-servernetstat -ano里的-a列全部连接、-n用数字端口不解析服务名、-o带上 PID,三个参数缺一不可,少了-o你只看到一个端口被占却不知道找谁。找到 PID 后tasklist查名字,如果发现是另一个版本的adb.exe(比如某 IDE 自带的),先把它退掉,否则你 kill 一次它自动拉回来一次,看起来就像“命令没用”。
设备端那一半也要配合:开发者选项打开、USB 调试打开、插线后设备弹出“允许 USB 调试吗”的授权框并勾选“一律允许”。这一步没做的话,adb devices会显示unauthorized,不是没连上,是连上了但没被信任。
3. 安全视角的设备画像:用 pm 和 dumpsys 把一台机器摸清
环境通了之后,第一件有价值的事不是装 APK,而是把设备“画像”出来。做 android 安全 评估时,最先要回答的三个问题是:这台机器上有哪些应用、这些应用各自要了什么权限、系统层面有没有异常配置。这三问用 adb 原生命令就能答完,不需要装任何东西到设备上。
3.1 包枚举:-3、-s、-d 三个开关的区别
pm list packages是最常被低估的一条命令。默认全量输出几百行,直接看没有意义,关键在过滤参数。
# 只列第三方包(用户自己装的),做资产盘点时最常用 adb shell pm list packages -3 # 只列系统包,排查预装软件、比对基线用 adb shell pm list packages -s # 只列已禁用的包,找被“藏起来”的应用 adb shell pm list packages -d # 加上 -f 会同时输出 APK 的绝对路径,做样本提取时必带 adb shell pm list packages -3 -f-3和-s的划分依据是包的安装位置与签名身份,不是“能不能卸载”,所以有些厂商预装但可卸载的应用仍然算系统包,这一点在做资产清单时容易算错。-f输出的路径形如package:/data/app/~~xxx==/com.example.demo-yyy==/base.apk,那串带~~的随机目录是 Android 11 之后引入的,别试图去猜规律,直接拿路径用。
拿到包名之后,取 APK 本体就一步:
# 查这个包由几个 APK 组成,分包应用会返回多行 adb shell pm path com.example.demo # 按返回的路径逐个 pull,不要只拉 base.apk adb pull /data/app/~~xxx==/com.example.demo-yyy==/base.apk .\samples\pm path返回多行是常态,split APK 的包里base.apk只含主逻辑,配置和资源在split_config.*.apk里。只拉 base 会导致后续静态分析时资源缺失、so 库找不到,这个坑我在第一次做样本归档时踩得很实在。
3.2 权限面:dumpsys package 该看哪几行
dumpsys package的输出非常长,直接甩到终端里翻页找等于没看。有效的做法是在设备侧先过滤,只把关键段落带回来。
# 在设备侧过滤,避免几百 KB 文本走一遍 USB adb shell "dumpsys package com.example.demo | grep -E 'requested permissions|install permissions|runtime permissions'" # 只看已经实际授予的运行时权限 adb shell "dumpsys package com.example.demo | grep -A 40 'runtime permissions'"requested permissions是清单里声明的,runtime permissions是用户实际点过同意的,两者经常对不上——一个应用声明了通讯录权限但用户拒绝了,它在runtime permissions段里会显示granted=false。做合规比对时看的是后者,看前者只能说明“它想要什么”,不能说明“它拿到了什么”。
-A 40这个参数的意思是匹配行之后再多带 40 行,因为权限段是缩进列表,光匹配标题行拿不到内容。40 不是定值,包权限多的时候可以加到 80,加多了无非是输出长一点,不影响正确性。
3.3 属性、配置与日志:三处最容易出线索的地方
系统属性里藏着设备身份和调试开关状态,getprop一次性全打印太多,按键名过滤更实用。
# 设备型号、系统版本、编译指纹 adb shell getprop | grep -E "ro.product.model|ro.build.version.release|ro.build.fingerprint" # 调试相关开关,确认 USB 调试与 ADB 授权状态 adb shell settings get global adb_enabled adb shell settings get secure adb_keyssettings get global adb_enabled返回1表示调试开关是开的。这条在排查“为什么别人的机器能连我的不能连”时特别有用——很多时候不是驱动问题,是那台机器的调试开关被策略关掉了。
日志切片是另一条主线。全量logcat是灾难,正确姿势是先清空缓冲、复现动作、再按 tag 抓。
# 清空历史缓冲,避免旧日志干扰 adb logcat -c # 抓最近 200 行并落盘,-d 表示抓完就退出不阻塞 adb logcat -d -t 200 > logcat_snapshot.txt # 按关键字过滤,多个关键字用 | 分隔(设备侧 grep) adb shell "logcat -d -t 500 | grep -iE 'crash|exception|denied'"-d是“dump 完立刻返回”,不加它终端会被日志流占住,很多人第一次用 logcat 以为命令卡死了,其实是它在持续输出。-t 200限制行数,配合-d使用才不会把几万行历史日志一次性灌进文件。
4. 数据面操作:pull、backup、run-as 三条路的边界在哪
画像做完,下一步通常是动数据:把设备上的文件取下来、把测试文件推上去、看看应用私有目录里有什么。这三件事分别对应pull/push、adb backup、run-as,它们的权限门槛完全不同,混着用就会撞墙。
4.1 pull 与 push:/data/local/tmp 是最靠谱的中转站
adb pull能取什么,取决于 adb shell 这个身份能读什么。它默认是shell用户(UID 2000),不属于任何应用,也不在 root 组。
# 取外部存储的公开目录,这是 shell 用户能读的范围 adb pull /sdcard/DCIM/Camera/ .\evidence\camera\ # 取应用的外部私有目录(Android 10 之后 shell 通常读不到) adb pull /sdcard/Android/data/com.example.demo/ .\evidence\demo\ # 推文件到临时目录,这是 shell 用户可写且不受 SELinux 限制的位置 adb push .\probe.txt /data/local/tmp/probe.txt # 推完改权限并确认落地 adb shell "chmod 644 /data/local/tmp/probe.txt && ls -lZ /data/local/tmp/probe.txt"/data/local/tmp这个路径值得单独记:它是 shell 用户可读可写、SELinux 上下文为shell_data_file的少数位置之一,几乎所有“我需要把一个二进制推上去跑一下”的场景都从这里起步。推到/sdcard会带上media_rw_data_file上下文,某些场景下反而不方便执行。
ls -lZ里的-Z是显示 SELinux 上下文,这个参数在排查“文件明明在、就是读不了”时几乎是唯一有效的手段。看不到上下文,你只能猜;看得到,你一眼就知道是权限位问题还是标签问题。
4.2 adb backup:能跑,但别把它当成取数主路
adb backup曾经是拿应用私有数据的标准手段,现在它的适用面窄了很多,理解它为什么窄比记住命令本身重要。
# 备份指定应用(-apk 带上安装包本体,-shared 带上外部存储) adb backup -f demo.ab -apk -shared com.example.demo # 全量备份,注意这会提示用户在设备上点“备份我的数据” adb backup -f full.ab -apk -shared -all命令本身没变,变化在设备侧:应用需要在清单里显式开启android:allowBackup="true",且从 Android 12 起,系统对备份范围做了更严的限制,很多应用即使开了开关,备份出来的.ab文件里也只有壳没有数据。判断方法很直接——看文件大小,几十 KB 的.ab基本是空的,正常带数据的至少几百 KB 到几 MB。
.ab文件不是标准 tar,头部的魔法字符串之后是压缩过的数据块。要拆它需要额外的解包工具,常见的做法是用支持 ab 格式的解包脚本先转成 tar 再展开。这一步属于“能拆但成本不低”,所以我的实际选择是:能做run-as的场景绝不用 backup,backup 只作为退路。
4.3 run-as 与 SELinux:为什么你的 cat 明明路径对却被拒
run-as的设计初衷是给可调试应用提供一个切身份的入口,它只对android:debuggable="true"的包有效。这一条把绝大多数线上应用直接排除了。
# 先确认这个包是否可调试,输出里有 DEBUGGABLE 才行 adb shell "dumpsys package com.example.debug | grep -i pkgFlags" # 切到应用身份后读私有目录 adb shell "run-as com.example.debug ls -l /data/data/com.example.debug/" # 直接读 shared_prefs,注意这一步不需要 root adb shell "run-as com.example.debug cat /data/data/com.example.debug/shared_prefs/config.xml"如果pkgFlags里没有DEBUGGABLE,run-as会直接返回 “Package ... is not debuggable”,这不是权限不足,是设计如此。很多人在这里反复chmod 777,纯属白费功夫——文件权限是第二道门,第一道门是 SELinux 标签和进程域,shell进程无论怎么改文件权限位,都进不了untrusted_app域可访问的目录。
注意:
run-as成功后拿到的身份是应用 UID,此时对/data/data/<包名>的读写等价于应用自身,但对其他应用的目录依然无权限。不要指望用它横穿。
想在非调试包上取私有数据,只剩两条路:设备已 root,或者应用自己把数据导出到外部存储。前者取决于设备,后者取决于应用,都不是 adb 能单方面解决的。认清这条边界,能省掉大量无效尝试。
5. 避坑清单:5037 被占、unauthorized 和 backup 空包怎么破
下面这几条是在实际交付里反复出现的,按现象、原因、解决三段记,遇到时能少走几圈。
5.1 连接侧的四类故障
现象一:adb devices列表为空,但设备管理器里能看到设备。
原因通常是驱动问题。Windows 自带的是通用 USB 驱动,adb 需要的是设备厂商提供的 ADB 接口驱动,未安装时设备会以“未知设备”或“MTP 设备”出现,adb server 枚举不到 ADB 接口。
解决:打开设备管理器,找带黄色感叹号的条目,手动更新驱动并指向解压目录;部分机型需要用厂商提供的驱动安装包。装完后adb kill-server && adb devices重试,不要只拔插数据线。
现象二:设备显示unauthorized。
原因是这台电脑的 adb 公钥没有被设备记住。首次连接时设备会弹授权框,如果当时点了“拒绝”或没勾“一律允许”,就会一直是这个状态。
解决:先adb kill-server,然后进设备“开发者选项”,找到“撤销 USB 调试授权”点一下,重新插线,等授权框弹出后勾选“一律允许”。如果授权框根本不弹,检查是不是把~/.android/adbkey删了又没重启 server——密钥文件缺失时 server 不会主动重建,adb kill-server会触发重新生成。
现象三:设备显示offline或反复在device/offline之间跳。
原因是 adb server 版本与设备端 adbd 协议协商不一致,最常见于机器上同时存在多个版本的 adb.exe(IDE 自带一个、你自己放了一个),两个 server 抢占 5037 端口。
解决:netstat -ano | findstr :5037找出占用进程,退掉多余的那份,只保留一个 adb 在 PATH 里。如果两版确实都要用,给其中一个指定独立端口:set ANDROID_ADB_SERVER_PORT=5038,让它走不同端口互不干扰。
现象四:报 “adb server version (xx) doesn't match this client (xx)”。
原因和上一条同源,但表现更明确:客户端连上了一个旧版 server。旧 server 是别的工具先启动的,一直驻留。
解决:adb kill-server后再执行任意 adb 命令,会拉起与你客户端版本匹配的 server。如果 kill 之后马上又被别人拉起来,说明有后台进程在监听,得先找到并停掉它。
5.2 版本与数据侧的三类故障
现象五:adb pair命令不存在。
这是这一版 adb 的硬边界。adb pair和adb mdns是后续版本才引入的,1.0.39 上执行会直接报未知命令。
解决:Android 11 之后的无线调试配对必须用新版 adb,这一条没有绕法。如果受限于环境只能用这个版本,就退回adb tcpip 5555的老路子:先用 USB 连上,执行adb tcpip 5555,拔线后用adb connect <设备IP>:5555连接。前提是设备和电脑在同一网段,且设备端允许该端口访问。
现象六:adb backup跑完了,.ab文件只有几十 KB。
原因有两层:应用没开allowBackup,或者系统的备份范围限制把应用数据排除了。命令返回码仍然是 0,所以看起来“成功”了。
解决:先dumpsys package <包名> | grep -i allowBackup确认开关状态;确认开了还是空包,就说明走不通,换run-as(仅调试包)或放弃这条路。不要在这个命令上反复试参数,参数不是变量。
现象七:adb shell screencap -p > screen.png出来的图打不开。
原因是adb shell会对输出做换行符转换,把\n变成\r\n,二进制数据被污染。这是 Windows 上最经典的坑之一。
解决:改用adb exec-out,它不经过 shell 的换行转换:
# 正确姿势:exec-out 直通二进制 adb exec-out screencap -p > screen.png # 老设备不支持 exec-out 时的替代方案:先落盘再 pull adb shell screencap -p /data/local/tmp/s.png adb pull /data/local/tmp/s.png .\screen.png adb shell rm /data/local/tmp/s.png顺带一个同源问题:路径里有空格或中文时,adb pull的源路径和目标路径都要加引号,否则会被拆成多个参数,报出来的错是“remote object doesn't exist”,非常容易被误导成设备上文件不存在。
6. 进阶玩法:把体检命令串成一份可复现的 bat 报告
单条命令敲多了必然漏项。我现在的习惯是把设备画像的固定几条串成一个批处理,跑一次出一份带时间戳的文本报告,归档和横向比对都省事。
@echo off setlocal enabledelayedexpansion REM 所有产物落在当前目录的 report 子目录,避免污染工作区 set "OUT=.\report" if not exist "%OUT%" mkdir "%OUT%" REM 先确认设备在线,离线就直接退出,别继续跑一堆空命令 adb devices | findstr /r /c:"device$" >nul if errorlevel 1 ( echo [FAIL] no device in device state exit /b 1 ) REM 设备基础信息 adb shell getprop > "%OUT%\props.txt" adb shell "getprop ro.build.fingerprint" > "%OUT%\fingerprint.txt" REM 第三方包清单与安装路径,-f 带上 APK 路径 adb shell pm list packages -3 -f > "%OUT%\packages_third.txt" adb shell pm list packages -s > "%OUT%\packages_system.txt" adb shell pm list packages -d > "%OUT%\packages_disabled.txt" REM 全局配置快照,调试开关与安装来源策略都在这 adb shell settings list global > "%OUT%\settings_global.txt" adb shell settings list secure > "%OUT%\settings_secure.txt" REM 日志切片,-d 抓完即退,-t 限制行数 adb logcat -d -t 1000 > "%OUT%\logcat_tail.txt" echo [OK] report written to %OUT% endlocal脚本里几个值得注意的点:findstr /r /c:"device$"用行尾锚定,是为了避免把unauthorized、offline里的device子串误判成在线,/c:保证整串匹配,/r启用正则。settings list global比逐条settings get高效得多,一次拿全,后续在本地用文本工具筛。logcat -d -t 1000限制在 1000 行是有意的——行数拉太大,USB 传输时间会明显变长,而且日志滚得快,越早的越没价值。
跑完之后我会先看packages_third.txt的行数。同一台设备两次体检,第三方包数量突然多出十几个,基本可以确定中间装过东西;settings_secure.txt里的install_non_market_apps和adb_enabled两项,是判断设备是否被人动过调试配置的第一手依据。这些判断不需要任何额外工具,文本比对就够了。
再补一个实用技巧:把两次报告放同一目录,用fc做差异比对,只关注变化行。
REM /n 显示行号,便于回查原文定位 fc /n .\report_old\packages_third.txt .\report\packages_third.txt这条命令的输出比任何图形化对比工具都直接,尤其在只有一台 Windows 干净机器可用的时候。我一般把它写进固定流程,每次体检前后各跑一次,变化项单独记录。
最后说一条教训。早些年我做设备侧排查,习惯现场敲命令,敲完就过,报告靠回忆补——结果有一次两台设备的包清单记混了,结论整个反过来,返工了大半天。从那以后我每次连上设备,第一条命令永远是那个 bat,不管多急都强制走一遍,产物落盘再动手分析。这个习惯看着笨,但它把“我以为是”变成了“文件里写着”。希望帮到你。
本文还有配套的精品资源,点击获取