• [免费专栏] ATTACK安全之检测车机中ADB远程调试控制Android系统攻击



    也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大

    少走了弯路,也就错过了风景,无论如何,感谢经历


    转移发布平台通知:将不再在CSDN博客发布新文章,敬请移步知识星球

    感谢大家一直以来对我CSDN博客的关注和支持,但是我决定不再在这里发布新文章了。为了给大家提供更好的服务和更深入的交流,我开设了一个知识星球,内部将会提供更深入、更实用的技术文章,这些文章将更有价值,并且能够帮助你更好地解决实际问题。期待你加入我的知识星球,让我们一起成长和进步


    ATTACK付费专栏长期更新,本篇最新内容请前往:

    0x01 前言

    我们常说的adb,也称为Android 调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信。adb 命令可用于执行各种设备操作(例如安装和调试应用),并提供对 Unix shell(可用来在设备上运行各种命令)的访问权限。它是一种客户端-服务器程序,包括以下三个组件:

    • 客户端(adb):用于发送命令。客户端在开发机器上运行,您可以通过发出 adb 命令从命令行终端调用客户端
    • 守护程序 (adbd):用于在设备上运行命令,守护程序在每个设备上作为后台进程运行
    • 服务器(adb server):用于管理客户端与守护程序之间的通信,服务器在开发机器上作为后台进程运行

    :Android adb源码路径为:system⁩/⁨core⁩/⁨adb,根据adb运行的地方不同,可以分为PC端和Android 手机设备端两部分

    • PC端: adb clientadb server 是运行在PC端,adb就是控制台命令adb,adb server是由adb fork出的一个常驻后台的子进程,作为adb的server进程,adb kill-server就是kill掉这个进程。adb与adb server通过local socket进行通信
    • Android 手机设备端:adbd运行在Android 手机设备端,是在内核初始化完毕之后,由init进程启动

    在这里插入图片描述

    adb 包含在 Android SDK 平台工具软件包中。您可以使用 SDK 管理器下载此软件包,该管理器会将其安装在 android_sdk/platform-tools/ 下。也可以单独下载独立的 Android SDK 平台工具软件包

    1)adb工作原理

    当用户启动某个 adb 客户端时,客户端会先检查是否有 adb 服务器进程正在运行。如果没有,它将启动服务器进程。服务器在启动后会与本地 TCP 端口 5037 绑定,并监听 adb 客户端发出的命令,所有 adb 客户端均通过端口 5037 与 adb 服务器通信,adb原理图如下:

    在这里插入图片描述

    然后,服务器会与所有正在运行的设备建立连接。它通过扫描 5555 到 5585 之间(该范围供前 16 个模拟器使用)的奇数号端口查找模拟器。服务器一旦发现 adb 守护进程 (adbd),便会与相应的端口建立连接。注意,每个模拟器都使用一对按顺序排列的端口 - 用于控制台连接的偶数号端口和用于 adb 连接的奇数号端口。例如,如下:

    • 模拟器 A,控制台:5554
      • 模拟器 A,adb:5555
    • 模拟器 B,控制台:5556
      • 模拟器 B,adb:5557
    • :以此类推,如上所示,在端口 5555 处与 adb 连接的模拟器与控制台监听端口为 5554 的模拟器是同一个

    服务器与所有设备均建立连接后,用户就可以使用 adb 命令访问这些设备。由于服务器管理与设备的连接,并处理来自多个 adb 客户端的命令,因此您可以从任意客户端(或从某个脚本)控制任意设备

    2)Android APK 的root 权限和USB ADB 权限的区别

    USB adb 权限是指,当adb 连接手机时,手机中的守护进程adbd 的权限为root 权限,从而它的子进程也具有root 权限,通常如果adb shell 看到是:

    • Android 10版本 (以树莓派为例):
    D:\>adb shell
    rpi4:/ #
    
    • 1
    • 2

    在这里插入图片描述

    即表明adb 的连接是root 权限的,相反如果看到是$ 即表明是shell 权限。 Android 的APK 本身都是不具备root 权限的,如果想启用root 权限,那么就必须借助具有root 权限的进程或者具有s bit 的文件,目前比较通用的手法是,手机root 后,内置了su到system/bin, 然后普通APP 即可借助su 命令来达到root 权限切换。

    网络上已经有同仁修改su 命令,并通过一个APK 来控制su 命令的权限控制。 如常见的Superuser 即可人为的控制root 权限的使用(Superuser 因很久都没有更新了,只能用于ICS 以及以前的版本,不推荐使用), SuperSU (也老了,不推荐使用),推荐使用Magisk (更新速度快,推荐使用)

    1.1 Android 设备端开启USB调试

    在这里插入图片描述

    • 进程列表

    在这里插入图片描述

    无需特殊权限,部分高版本设备无法获取进程列表

    • 检测init.svc.adbd属性取值是否running

    在这里插入图片描述

    1.2 adbd启动流程简介

    adbd守护进程:只要是操作系统,就肯定会运行着一些守护进程(daemon)来完成重复或繁琐的工作。通过Android系统中的init.rc文件可以发现,其中每个service中就包含着系统后台服务进程。而这些服务被分为:

    • core类服务(adbd/servicemanager/healthd/lmkd/logd/vold)和main类服务
      • main类服务又分为:
        • 网络类服务(netd/mdnsd/mtpd/rild)、图形及媒体类服务(surfaceflinger/bootanimation/mediaserver/dnnserver)、其他类服务(installd/keystore/debuggerd/sdcard/Zygote

    • init.rc:Android在启动过程中读取的启动脚本文件,主要完成一些初级的初始化,在/system/core/init/init.c中解析。rc 经常被用作程序之启动脚本的文件名。它是“run commands”(运行命令)的缩写
    • init.xx.rc:与具体CPU相关的启动脚本,比如对于MTK的CPU,名字为init.usb.rc,init.trace.rc。在init.rc之后得到解析

    Android adbd:Android 系统特有的ADB功能中运行在Android设备端的守护进程,其在根目录下的/init.rc/init.usb.rc中的启动配置如下

    在这里插入图片描述

    下面是该文件的一些注释信息:

    # Copyright (C) 2012 The Android Open Source Project
    #
    # IMPORTANT: Do not create world writable files or directories.
    # This is a common source of Android security bugs.
    #
     
    "【import 一个init配置文件,扩展当前配置。】"
    import /init.environ.rc
    import /init.usb.rc
    import /init.${ro.hardware}.rc
    import /init.${ro.zygote}.rc
    import /init.trace.rc
     
    "【触发条件early-init,在early-init阶段调用以下行】"
    on early-init
        # Set init and its forked children's oom_adj.
        write /proc/1/oom_score_adj -1000
        "【打开路径为的一个文件,并写入一个或多个字符串】"
        # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
        write /sys/fs/selinux/checkreqprot 0
     
        # Set the security context for the init process.
        # This should occur before anything else (e.g. ueventd) is started.
        "【这段脚本的意思是init进程启动之后就马上调用函数setcon将自己的安全上下文设置为“u:r:init:s0”,即将init进程的domain指定为init。】"
        setcon u:r:init:s0
     
        # Set the security context of /adb_keys if present.
        "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
        restorecon /adb_keys
     
        "【执行start ueventd的命令。ueventd是一个service后面有定义】 "
        start ueventd
     
        "【mkdir  [mode] [owner] [group]   //创建一个目录,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。】"
        # create mountpoints
        mkdir /mnt 0775 root system
     
    on init
        "【设置系统时钟的基准,比如0代表GMT,即以格林尼治时间为准】"
        sysclktz 0
     
    "【设置kernel日志等级】"
    loglevel 6 ####
        write /proc/bootprof "INIT: on init start" ####
        
        "【symlink      //创建一个指向的软连接。】"
        # Backward compatibility
        symlink /system/etc /etc
        symlink /sys/kernel/debug /d
     
        # Right now vendor lives on the same filesystem as system,
        # but someday that may change.
        symlink /system/vendor /vendor
     
        "【创建一个目录,可以选择性地指定mode、owner以及group。】"
        # Create cgroup mount point for cpu accounting
        mkdir /acct
        mount cgroup none /acct cpuacct
        mkdir /acct/uid
     
        "【mount    [  ]   //在目录挂载指定的设备。 可以是以 mtd@name 的形式指定一个mtd块设备。包括 ro、rw、remount、noatime、 ...】"
        # Create cgroup mount point for memory
        mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
        mkdir /sys/fs/cgroup/memory 0750 root system
        mount cgroup none /sys/fs/cgroup/memory memory
        write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
        "【chown      //改变文件的所有者和组。】"
        
        "【后面的一些行因为类似,就省略了】"
        .....
     
    # Healthd can trigger a full boot from charger mode by signaling this
    # property when the power button is held.
    on property:sys.boot_from_charger_mode=1
        "【停止指定类别服务类下的所有已运行的服务】"
        class_stop charger
        "【触发一个事件,将该action排在某个action之后(用于Action排队)】"
        trigger late-init
     
    # Load properties from /system/ + /factory after fs mount.
    on load_all_props_action
        "【从/system,/vendor加载属性。默认包含在init.rc】"
        load_all_props
     
    # Indicate to fw loaders that the relevant mounts are up.
    on firmware_mounts_complete
        "【删除指定路径下的文件】"
        rm /dev/.booting
     
    # Mount filesystems and start core system services.
    on late-init
        "【触发一个事件。用于将一个action与另一个 action排列。】"
        trigger early-fs
        trigger fs
        trigger post-fs
        trigger post-fs-data
     
        # Load properties from /system/ + /factory after fs mount. Place
        # this in another action so that the load will be scheduled after the prior
        # issued fs triggers have completed.
        trigger load_all_props_action
     
        # Remove a file to wake up anything waiting for firmware.
        trigger firmware_mounts_complete
     
        trigger early-boot
        trigger boot
     
     
    on post-fs
        ...
        "【一些创造目录,建立链接,更改权限的操作,这里省略】"
     
    on post-fs-data
        ...
        "【一些创造目录,建立链接,更改权限的操作,这里省略】"
     
        "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
        restorecon /data/mediaserver
     
        "【将系统属性的值设置为,即以键值对的方式设置系统属性】"
        # Reload policy from /data/security if present.
        setprop selinux.reload_policy 1
     
        "【以递归的方式恢复指定目录到file_contexts配置中指定的安全上下文中】"
        # Set SELinux security contexts on upgrade or policy update.
        restorecon_recursive /data
     
        # If there is no fs-post-data action in the init.<device>.rc file, you
        # must uncomment this line, otherwise encrypted filesystems
        # won't work.
        # Set indication (checked by vold) that we have finished this action
        #setprop vold.post_fs_data_done 1
     
    on boot
        "【初始化网络】"
        # basic network init
        ifup lo
        "【设置主机名为localhost】"
        hostname localhost
        "【设置域名localdomain】"
        domainname localdomain
     
        "【设置资源限制】"
        # set RLIMIT_NICE to allow priorities from 19 to -20
        setrlimit 13 40 40
     
        "【这里省略了一些chmod,chown,等操作,不多解释】"
       ...
       
     
        # Define default initial receive window size in segments.
        setprop net.tcp.default_init_rwnd 60
        
        "【重启core服务】"
        class_start core
     
    on nonencrypted
        class_start main
        class_start late_start
     
    on property:vold.decrypt=trigger_default_encryption
        start defaultcrypto
     
    on property:vold.decrypt=trigger_encryption
        start surfaceflinger
        start encrypt
     
    on property:sys.init_log_level=*
        loglevel ${sys.init_log_level}
     
    on charger
        class_start charger
     
    on property:vold.decrypt=trigger_reset_main
        class_reset main
     
    on property:vold.decrypt=trigger_load_persist_props
        load_persist_props
     
    on property:vold.decrypt=trigger_post_fs_data
        trigger post-fs-data
     
    on property:vold.decrypt=trigger_restart_min_framework
        class_start main
     
    on property:vold.decrypt=trigger_restart_framework
        class_start main
        class_start late_start
     
    on property:vold.decrypt=trigger_shutdown_framework
        class_reset late_start
        class_reset main
     
    on property:sys.powerctl=*
        powerctl ${sys.powerctl}
     
    # system server cannot write to /proc/sys files,
    # and chown/chmod does not work for /proc/sys/ entries.
    # So proxy writes through init.
    on property:sys.sysctl.extra_free_kbytes=*
        write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
     
    # "tcp_default_init_rwnd" Is too long!
    on property:sys.sysctl.tcp_def_init_rwnd=*
        write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
     
    "【守护进程】"
    ## Daemon processes to be run by init.
    ##
    service ueventd /sbin/ueventd
        class core
        critical
        seclabel u:r:ueventd:s0
     
    "【日志服务进程】"
    service logd /system/bin/logd
        class core
        socket logd stream 0666 logd logd
        socket logdr seqpacket 0666 logd logd
        socket logdw dgram 0222 logd logd
        seclabel u:r:logd:s0
     
    "【Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信息】"
    service healthd /sbin/healthd
        class core
        critical
        seclabel u:r:healthd:s0
     
    "【控制台进程】"
    service console /system/bin/sh
        "【为当前service设定一个类别.相同类别的服务将会同时启动或者停止,默认类名是default】"
        class core
        "【服务需要一个控制台】"
        console
        "【服务不会自动启动,必须通过服务名显式启动】"
        disabled
        "【在执行此服务之前切换用户名,当前默认的是root.自Android M开始,即使它要求linux capabilities,也应该使用该选项.很明显,为了获得该功能,进程需要以root用户运行】"
        user shell
        seclabel u:r:shell:s0
     
    on property:ro.debuggable=1
        start console
     
    # adbd is controlled via property triggers in init.<platform>.usb.rc
    service adbd /sbin/adbd --root_seclabel=u:r:su:s0
        class core
        "【创建一个unix域下的socket,其被命名/dev/socket/. 并将其文件描述符fd返回给服务进程.其中,type必须为dgram,stream或者seqpacke,user和group默认是0.seclabel是该socket的SELLinux的安全上下文环境,默认是当前service的上下文环境,通过seclabel指定】"
        socket adbd stream 660 system system
        disabled
        seclabel u:r:adbd:s0
     
    # adbd on at boot in emulator
    on property:ro.kernel.qemu=1
        start adbd
     
    "【内存管理服务,内存不够释放内存】"
    service lmkd /system/bin/lmkd
        class core
        critical
        socket lmkd seqpacket 0660 system system
     
    "【ServiceManager是一个守护进程,它维护着系统服务和客户端的binder通信。
    在Android系统中用到最多的通信机制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驱动程序组成。其中Client、Service和ServiceManager运行在用户空间,而Binder驱动程序运行在内核空间。核心组件就是Binder驱动程序了,而ServiceManager提供辅助管理的功能,无论是Client还是Service进行通信前首先要和ServiceManager取得联系。而ServiceManager是一个守护进程,负责管理Server并向Client提供查询Server的功能。】"
    service servicemanager /system/bin/servicemanager
        class core
        user system
        group system
        critical
        onrestart restart healthd
        "【servicemanager 服务启动时会重启zygote服务】"
        onrestart restart zygote
        onrestart restart media
        onrestart restart surfaceflinger
        onrestart restart drm
     
    "【Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程】"
    service vold /system/bin/vold
        class core
        socket vold stream 0660 root mount
        ioprio be 2
     
    "【Netd是Android系统中专门负责网络管理和控制的后台daemon程序】"
    service netd /system/bin/netd
        class main
        socket netd stream 0660 root system
        socket dnsproxyd stream 0660 root inet
        socket mdns stream 0660 root system
        socket fwmarkd stream 0660 root inet
     
    "【debuggerd是一个daemon进程,在系统启动时随着init进程启动。主要负责将进程运行时的信息dump到文件或者控制台中】"
    service debuggerd /system/bin/debuggerd
        class main
     
    service debuggerd64 /system/bin/debuggerd64
        class main
     
    "【Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层】"
    # for using TK init.modem.rc rild-daemon setting
    #service ril-daemon /system/bin/rild
    #    class main
    #    socket rild stream 660 root radio
    #    socket rild-debug stream 660 radio system
    #    user root
    #    group radio cache inet misc audio log
     
    "【提供系统 范围内的surface composer功能,它能够将各种应用 程序的2D、3D surface进行组合。】"
    service surfaceflinger /system/bin/surfaceflinger
        class core
        user system
        group graphics drmrpc
        onrestart restart zygote
     
    "【DRM可以直接访问DRM clients的硬件。DRM驱动用来处理DMA,内存管理,资源锁以及安全硬件访问。为了同时支持多个3D应用,3D图形卡硬件必须作为一个共享资源,因此需要锁来提供互斥访问。DMA传输和AGP接口用来发送图形操作的buffers到显卡硬件,因此要防止客户端越权访问显卡硬件。】"
    #make sure drm server has rights to read and write sdcard ####
    service drm /system/bin/drmserver
        class main
        user drm
        # group drm system inet drmrpc ####
        group drm system inet drmrpc sdcard_r ####
     
    "【媒体服务,无需多说】"
    service media /system/bin/mediaserver
        class main
        user root ####
    #   google default ####
    #   user media    ####
        group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
    #   google default ####
    #   group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####
     
        ioprio rt 4
     
    "【设备加密相关服务】"
    # One shot invocation to deal with encrypted volume.
    service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
        disabled
        "【当服务退出时,不重启该服务】"
        oneshot
        # vold will set vold.decrypt to trigger_restart_framework (default
        # encryption) or trigger_restart_min_framework (other encryption)
     
    # One shot invocation to encrypt unencrypted volumes
    service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
        disabled
        oneshot
        # vold will set vold.decrypt to trigger_restart_framework (default
        # encryption)
     
    "【开机动画服务】"
    service bootanim /system/bin/bootanimation
        class core
        user graphics
    #    group graphics audio ####
        group graphics media audio ####
        disabled
        oneshot
     
    "【在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。】"
    service installd /system/bin/installd
        class main
        socket installd stream 600 system system
     
    service flash_recovery /system/bin/install-recovery.sh
        class main
        seclabel u:r:install_recovery:s0
        oneshot
     
    "【vpn相关的服务】"
    service racoon /system/bin/racoon
        class main
        socket racoon stream 600 system system
        # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
        group vpn net_admin inet
        disabled
        oneshot
     
    "【android中有mtpd命令可以连接vpn】"
    service mtpd /system/bin/mtpd
        class main
        socket mtpd stream 600 system system
        user vpn
        group vpn net_admin inet net_raw
        disabled
        oneshot
     
    service keystore /system/bin/keystore /data/misc/keystore
        class main
        user keystore
        group keystore drmrpc
     
    "【可以用dumpstate 获取设备的各种信息】"
    service dumpstate /system/bin/dumpstate -s
        class main
        socket dumpstate stream 0660 shell log
        disabled
        oneshot
     
    "【mdnsd 是多播 DNS 和 DNS 服务发现的守护程序。】"
    service mdnsd /system/bin/mdnsd
        class main
        user mdnsr
        group inet net_raw
        socket mdnsd stream 0660 mdnsr inet
        disabled
        oneshot
     
    "【触发关机流程继续往下走】"
    service pre-recovery /system/bin/uncrypt
        class main
        disabled
        "【当服务退出时,不重启该服务】"
        oneshot
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413

    • 在默认情况下,adbd是以uid root的权限启动的。不过它还会通过函数drop_privileges()主动把自己降到uid shell: shell和几个GID权限,源码地址

    在这里插入图片描述

    • user-debug版本的系统中(系统属性为ro.debuggable=0),或通过adb root命令让adbd恢复root权限(通过修改系统属性service.adb.root=1

    手机端的adbd是在init解析rc文件的时候启动的,具体可以查看init.rc中的配置信息。根据注释,可以了解到adbd的启动是根据一个属性触发器来控制的,具体的触发器在init..usb.rc文件中,如下:

    # adbd is controlled via property triggers in init.<platform>.usb.rc
    service adbd /sbin/adbd --root_seclabel=u:r:su:s0
        class core
        "【创建一个unix域下的socket,其被命名/dev/socket/. 并将其文件描述符fd返回给服务进程.其中,type必须为dgram,stream或者seqpacke,user和group默认是0.seclabel是该socket的SELLinux的安全上下文环境,默认是当前service的上下文环境,通过seclabel指定】"
        socket adbd stream 660 system system
        disabled
        seclabel u:r:adbd:s0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接着,跟进去根目录/init.usb.rc看看,看看在init..usb.rc文件中如何定义触发器。触发器根据sys.usb.config的值来决定是否启动adbd,其实就是仅当sys.usb.config的值中包含adb选项时才会启动adbd

    # adb only USB configuration
    # This is the fallback configuration if the
    # USB manager fails to set a standard configuration
    on property:sys.usb.config=adb && property:sys.usb.configfs=0
        write /sys/class/android_usb/android0/enable 0
        write /sys/class/android_usb/android0/idVendor 18d1
        write /sys/class/android_usb/android0/idProduct 4EE7
        write /sys/class/android_usb/android0/functions ${sys.usb.config}
        write /sys/class/android_usb/android0/enable 1
        start adbd
        setprop sys.usb.state ${sys.usb.config}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    :Android O新增的关于usb的三个属性【sys.usb.configfs、sys.usb.ffs.ready、sys.usb.ffs.mtp.ready】:

    • sys.usb.configfs:该属性默认为0,通过判断kernel是否支持configfs,即判断/config/usb_gadget存在设置为1,代码在init.qcom.usb.sh中(高通平台下)
    • sys.usb.ffs.ready:当sys.usb.config设置为none时,设置sys.usb.ffs.ready为0。每次设置的属性有adb时,会先start adbd。如sys.usb.config=mtp,adb时,在init.usb.configfs.rc中有(如下代码),然后在system/core/adb/daemon/main.cpp中,会调用usb_init,进而调用system/core/adb/daemon/usb.cpp的usb_ffs_open_thread()函数中,然后调用init_functionfs()初始化该属性为1。只有sys.usb.ffs.ready=1时,才能开启adb端口:
    sys.usb.config=mtp,adb && sys.usb.configfs=1
    start adbd
    
    • 1
    • 2
    • sys.usb.ffs.mtp.ready:当设置为none时,设置sys.usb.ffs.mtp.ready为0。android O新增,当功能为mtp或者ptp时,在 trySetEnableFuntction()函数中会先发送一次广播给mtpReceiver
      • 给数据库添加mtp_connected
      • 调用mtpServer.configure(),最后调用mtpServer.cpp设置sys.usb.ffs.mtp.ready属性为1,才能响应on property:sys.usb.config=mtp(ptp也是),然后收到kernel发送的uevent后,再发一次广播

    Android 手机设备端USB模式:

    • PTP:“图像传输协议【Picture Transfer Protocol】”(PTP),为文件传输模式(PTP)
      • 在接入Windows系统之后可以更好地被系统和应用程序所共享,尤其在网络传输方面,系统可以直接访问这些设备用于建立网络相册时图片的上传、网上聊天时图片的传送等
      • PTP适合多播消息的分布式网络通信系统,同时提供单播消息的支持
    • MTP:“媒体传输协议【Media Transfer Protocol】”,是基于PTP(Picture Transfer Protocol)协议的扩展,主要用于传输媒体文件。如果选择MTP模式连接的话,电脑上和手机上都可以读取内置和外置SD卡
      • 其应用分两种角色,一个是作为Initiator,另一个作为Responder。Responder都是被动的回复Initiator的命令,不会主动发命令。主要的用途是传输媒体文件,并从设备关联元数据,对设备的远程控制有可选的额外支持,读取和设置设备参数,如特别的DRM相关的受限内容设备参数
      • MTP既可以实现在USB协议上,也可以实现在TCP/IP协议上,它属于上层的应用协议,而不关心底层传输协议

    adbd的启动代码在system/core/adb/daemon/main.cpp中,其中main函数在获取了selinux标签、banner名称、版本信息参数以及设置一些调试信息后,调用了adbd_main完成启动过程。adbd是一个linux程序,通过tcp或者usb与PC端的adb server通信,调用logcat shell等等程序实现各种调试功能,源码地址如下

    int adbd_main(int server_port) {
        umask(0);
        signal(SIGPIPE, SIG_IGN);
        // 负责完成adbd接受PC端adb server连接功能的初始化工作
        init_transport_registration();
        // We need to call this even if auth isn't enabled because the file
        // descriptor will always be open.
        adbd_cloexec_auth_socket();
        if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
            auth_required = false;
        }
    	
        // 负责完成对连入的PC端身份验证功能的初始化工作
        adbd_auth_init();
        // Our external storage path may be different than apps, since
        // we aren't able to bind mount after dropping root.
        const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
        if (adb_external_storage != nullptr) {
            setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
        } else {
            D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
              " unchanged.\n");
        }
    	
        // 负责是否要去掉adbd的root权限,降级为shell权限
        drop_privileges(server_port);
        bool is_usb = false;
        if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {  
            // 如果可以usb调试,初始化usb,等待连接
            // Listen on USB.
            usb_init();
            is_usb = true;
        }
        // If one of these properties is set, also listen on that port.
        // If one of the properties isn't set and we couldn't listen on usb, listen
        // on the default port.
        char prop_port[PROPERTY_VALUE_MAX];
        property_get("service.adb.tcp.port", prop_port, "");
        if (prop_port[0] == '\0') {
            property_get("persist.adb.tcp.port", prop_port, "");
        }
        int port;
        if (sscanf(prop_port, "%d", &port) == 1 && port > 0) {
            D("using port=%d", port);
            // Listen on TCP port specified by service.adb.tcp.port property.
            // 如果开启了网络调试,初始化端口,等待连接
            local_init(port);
        } else if (!is_usb) {
            // Listen on default port.
            local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
        }
        D("adbd_main(): pre init_jdwp()");
        // 初始化 java 调试框架
        init_jdwp();
        D("adbd_main(): post init_jdwp()");
        // 对监听的fd进行消息处理(死循环)
        D("Event loop starting");
        fdevent_loop();
        return 0;
    }
    int main(int argc, char** argv) {
        while (true) {
            static struct option opts[] = {
                {"root_seclabel", required_argument, nullptr, 's'},
                {"device_banner", required_argument, nullptr, 'b'},
                {"version", no_argument, nullptr, 'v'},
            };
            int option_index = 0;
            int c = getopt_long(argc, argv, "", opts, &option_index);
            if (c == -1) {
                break;
            }
            switch (c) {
            case 's':
                root_seclabel = optarg;
                break;
            case 'b':
                adb_device_banner = optarg;
                break;
            case 'v':
                printf("Android Debug Bridge Daemon version %d.%d.%d %s\n",
                       ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
                       ADB_REVISION);
                return 0;
            default:
                // getopt already prints "adbd: invalid option -- %c" for us.
                return 1;
            }
        }
        close_stdin();
        debuggerd_init(nullptr);
        adb_trace_init(argv);
        D("Handling main()");
        return adbd_main(DEFAULT_ADB_PORT);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    1.3 adbd权限

    adbd启动过程中的权限处理,在adbd_main函数中调用了drop_privileges进行降权处理。因为由init启动的进程启动,所以同样拥有和init一样的root权限。root权限过高,如果不是非必要,就要进行降权处理。如果当ro_debuggable && adb_root为true时,可以不用降权,维持root权限。简而言之就是当ro.debuggable为1且ro.secure为0的时候不用降权

    static void drop_privileges(int server_port) {
      ScopedMinijail jail(minijail_new());
    
      // Add extra groups:
      // AID_ADB to access the USB driver
      // AID_LOG to read system logs (adb logcat)
      // AID_INPUT to diagnose input issues (getevent)
      // AID_INET to diagnose network issues (ping)
      // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
      // AID_SDCARD_R to allow reading from the SD card
      // AID_SDCARD_RW to allow writing to the SD card
      // AID_NET_BW_STATS to read out qtaguid statistics
      // AID_READPROC for reading /proc entries across UID boundaries
      gid_t groups[] = {AID_ADB,      AID_LOG,       AID_INPUT,
                        AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
                        AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
                        AID_READPROC};
      minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
    
      // Don't listen on a port (default 5037) if running in secure mode.
      // Don't run as root if running in secure mode.
      if (should_drop_privileges()) {
        drop_capabilities_bounding_set_if_needed(jail.get());
    
        minijail_change_gid(jail.get(), AID_SHELL);
        minijail_change_uid(jail.get(), AID_SHELL);
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());
    
        D("Local port disabled");
      } else {
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());
    
        if (root_seclabel != nullptr) {
          if (selinux_android_setcon(root_seclabel) < 0) {
            LOG(FATAL) << "Could not set SELinux context";
          }
        }
        std::string error;
        std::string local_name =
          android::base::StringPrintf("tcp:%d", server_port);
        if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
          LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
        }
      }
    }
    
    static bool should_drop_privileges() {
    #if defined(ALLOW_ADBD_ROOT)
      // The properties that affect `adb root` and `adb unroot` are ro.secure and
      // ro.debuggable. In this context the names don't make the expected behavior
      // particularly obvious.
      //
      // ro.debuggable:
      //   Allowed to become root, but not necessarily the default. Set to 1 on
      //   eng and userdebug builds.
      //
      // ro.secure:
      //   Drop privileges by default. Set to 1 on userdebug and user builds.
      bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
      bool ro_debuggable = __android_log_is_debuggable();
    
      // Drop privileges if ro.secure is set...
      bool drop = ro_secure;
    
      // ... except "adb root" lets you keep privileges in a debuggable build.
      std::string prop = android::base::GetProperty("service.adb.root", "");
      bool adb_root = (prop == "1");
      bool adb_unroot = (prop == "0");
      if (ro_debuggable && adb_root) {
        drop = false;
      }
      // ... and "adb unroot" lets you explicitly drop privileges.
      if (adb_unroot) {
        drop = true;
      }
    
      return drop;
    #else
      return true; // "adb root" not allowed, always drop privileges.
    #endif // ALLOW_ADBD_ROOT
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    1.4 user版本默认开启adb以及root权限

    1.4.1 修改ro.adb.secure和ro.secure属性

    修改build/core/main.mk,修改ro.secure和ro.adb.secure位0,注释掉enable_target_debugging或者将其设置为true

    --- a/core/main.mk
    +++ b/core/main.mk
    @@ -239,11 +239,11 @@ enable_target_debugging := true
    tags_to_install :=
    ifneq (,$(user_variant))
    # Target is secure in user builds.
    -  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
    +  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0
    ADDITIONAL_DEFAULT_PROPERTIES += security.perf_harden=1
    
    ifeq ($(user_variant),user)
    -    ADDITIONAL_DEFAULT_PROPERTIES += ro.adb.secure=1
    +    ADDITIONAL_DEFAULT_PROPERTIES += ro.adb.secure=0
    endif
    
    ifeq ($(user_variant),userdebug)
    @@ -251,7 +251,7 @@ ifneq (,$(user_variant))
    tags_to_install += debug
    else
    # Disable debugging in plain user builds.
    -    enable_target_debugging :=
    +   # enable_target_debugging :=
    endif
    
    # Disallow mock locations by default for user builds
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    1.4.2 修改selinux

    修改system/core/init/init.cpp,将selinux_is_enforcing的返回值调整为false。这里还有另外一种改法,就是在Boardconfig.mk里面对BOARD_KERNEL_CMDLINE进行编辑,添加androidboot.selinux=permissive

    static bool selinux_is_enforcing(void)
    {
       return false;
    }
    
    • 1
    • 2
    • 3
    • 4

    1.4.3 修改adb模块的android.mk文件

    修改system/core/adb/Android.mk中的编译选项,允许adb root,如下:

    --- a/adb/Android.mk
    +++ b/adb/Android.mk
    @@ -350,9 +350,9 @@ LOCAL_CFLAGS := \
    -D_GNU_SOURCE \
    -Wno-deprecated-declarations \
    
    -LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
    +LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter user userdebug eng,$(TARGET_BUILD_VARIANT)),1,0
    
    -ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
    +ifneq (,$(filter user userdebug eng,$(TARGET_BUILD_VARIANT)))
    LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
    LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
    endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.4.4 设置默认打开adb端口

    配置device.mk或者devicecommon.mk,设置USB配置选项,添加adb功能

    --- a/common/DeviceCommon.mk
    +++ b/common/DeviceCommon.mk
    @@ -153,7 +153,7 @@ PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
    
    # Set default USB interface
    PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
    -    persist.sys.usb.config=ptp
    +    persist.sys.usb.config=ptp,adb
    
    PRODUCT_PROPERTY_OVERRIDES += \
    persist.sys.modem.diag=,gser \
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.5 adb安全认证

    大家在通过adb连接设备的时候,是否会有提示让确认是否允某台设备要进行USB调试的确认框(如下):

    在这里插入图片描述

    ADB具有功能非常强大的调试和跟踪功能,尽管它是以shell这个UID的身份运行,但由于shell这个UID是好几个组(log、graphic等)的成员,这也使得它具有很强的能力。使用ADB可以访问到用户的个人数据,也能把任意APP、Native层可执行文件上传到设备中。因此,在Android 4.3 以后的Android系统中引入了公钥认证机制(前提条件ro.adb.secure=1),让ADB的安全性进一步提高

    AUTH消息将作为对OPEN消息的响应,发送到电脑端,要求在其执行任何命令之前,先完成认证。AUTH消息的参数总是一个TOKEN,它是由移动设备中的随机数发生器(/dev/urandom)生成的一个大小为20个字节的随机数数组。移动设备端将等待电脑端用自己的私钥(该私钥应该己经生成,并存放在$HOME/.android/adbkey这个文件中)对这个TOKEN 进行签名,然后回复一个AUTH SIGNATURE消息,把用私钥签名过的随机数数组放在这个消息里返回给移动设备端。如果移动设备知道相应的公钥,那么验证就能继续,而且如过验证通过了,该会话就会切换到online状态上去

    因为,所有这些操作都依赖于公钥,比如怎么让Android 手机设备端提前就知道这个公钥,并将其用于验证呢?

    答:允许电脑端响应一个AUTHRSAPUBLICKEY消息。因为此时这个公钥是不可信的,ADB将把这个公钥通过/dev/socket/adbd这个UDS传递给system_server(特别是由com.android.server.usb.UsbDeviceManager启动的UsbDebuggingManager),然后,system_server将会弹出一个对话框(com.android.server.usb.UsbDebuggingActivity),要求用户确认该公钥的指纹(MD5 Hash)。如果用户选择信任该公钥,这个公钥就会被添加到adb的key store(位于/data/misc/adb/adb_key)中去。作为厂商的话可以重新编译adbd,删掉这一功能(相关代码位于adb_auth_client.c中的adb_auth_confirm_key()函数中),源码地址

    在这里插入图片描述

    输入dumpsys usb命令,就能查看当前USB调试状态以及当前使用的adb_keys,如下:

    在这里插入图片描述

    0x02 Android 开启USB 调试模式检测方法

    USB调试者,可直接在PC上使用adb命令对设备进行调试,也可通过DDMS命令间接调试。在调试之前,要在系统开发者模式中打开“USB调试”的开关,其在底层(不太理解的话,可以看看0x01中的内容)其实是通过修改系统属性sys.usb.config的值为adb时打开,大家看到这里可能想问通过sys.usb.config里是否存在adb调试来判断是否开启,那么怎么判断Android 设备端是否有adb连入呢?

    先用usb.config来搜索看看,有几个能匹配:

    getprop |  grep usb.config
    
    • 1

    在这里插入图片描述

    匹配到如下几个,具体啥意思,就是字面意思:

    • [persist.sys.usb.config]: [mtp,adb]:设置当前ADB开启状态的值
    • [sys.usb.config]: [mtp,adb]:设置当前USB功能的值
    • [sys.usb.configfs]: [1]
      • 如果sys.usb.configfs其值为1,则会使用init.usb.configfs.rc文件中相关条目,否则将使用init.usb.rc文件中的相关条目

    对于Android系统,和应用,要改变usb gadget通过配置如下两个prop属性: persist.sys.usb.config【设置当前ADB开启状态的值】和sys.usb.configfs【设置当前USB功能的值】,persist.sys.usb.config【设置当前ADB开启状态的值】和sys.usb.configfs【设置当前USB功能的值】该属性的值包含adb这个字段则会触发打开adb功能,即可实现关闭或打开USB调试和文件传输功能,其中mtp表示文件传输,adb表示adb调试,none表示都不启用

    0x03 检测Android adb是否成功连入Android 设备端

    3.1 adbd 进程检测方法

    进程检测分为两种方式:

    • 【不推荐】进程对应的端口号,比如adb无线调试默认端口5555【此方法比较适合Wi-Fi adb无线调试,加上判断service.adb.tcp.port+是否默认端口来检测,跟我们后面要讲的通过网络流量形式检测adbd是否接入的规则类似】
      • :此端口是可更改的,单独以端口来判断,会超多误报,因为不能保障5555端口会不会被其它进程占用
    • 【推荐】进程名,比如监视进程里面匹配上的adbd名字的进程

    1)进程对应的端口号

    先在PC端用tasklist命令查询adb相关的进程:

    • 此处第一个标红的地方有一个3172号进程,再通过netstat命令查询3172号进程对应的端口,发现3172号进程占用的端口是5037。根据adb原理图1,得知此adb是服务端
      • taskliste | findstr adb
      • netstat -ano | findstr 3172
    • 此处第二个标红的地方有一个22344号进程,再通过netstat命令查询22344号进程对应的端口,发现22344号进程占用的端口是22630。根据adb原理图2,得知此adb是客户端
      • taskliste | findstr adb
      • netstat -ano | findstr 22344

    在这里插入图片描述

    :由上可知,adb服务端和客户端都是sdk下的adb.exe

    接下来,我们进入adb shell后使用netstat命令,发现有一个2014号进程(adbd)占用5555端口,此进程即为守护进程

    netstat -anp | grep 5555
    
    • 1

    在这里插入图片描述

    通过上面的了解,可以发现可通过netstat -anp | grep adb来定位,可以看到会有一个adbd socket连接的进程,这里就是后面要讲的域套接字形式的检测。在介绍下面一种之前,同学们肯定有一个疑问,咋是5555端口?其实这里是Wi-Fi 连接adb默认配置的端口,你配置什么端口就是什么端口,所以,就衍生到第二种通过adbd子进程来检测

    2)进程名

    聊聊通过进程名来判断adbd来确定是否有adb接入Android 设备,执行如下命令:

    netstat -anp | grep adbd
    
    • 1

    在这里插入图片描述

    :上面这里大家可能看到有个socket链接的进程,就是下面要讲的通过域套接字形式来检测adb是否连入Android 设备

    3.2 域套接字形式检测

    • 域套接字的概念:进程与进程之间通讯的一种方式,客户端与服务端建立连接,需要有相同的套接字,和相应的服务端端口号,套接字处于监控状态,监听客户端发送的请求

    这里没什么好讲的,直接晒出结果吧,如下

    • 通过检测adbd是否有子进程来确定是否有客户端连入

    为了有明显区别对比,此处我们再次新开一个cmd窗口,然后执行如下命令:

    ps  | grep adb
    ps  | grep 7873
    
    • 1
    • 2

    在这里插入图片描述

    再次查看adb的子进程,其中已经少了一个adbd的子进程,如下:

    ps  |grep adb
    ps  |grep 7873
    
    • 1
    • 2

    在这里插入图片描述

    • 最后,我们检测/proc/net/unix 中是否有dev/socket/adbd

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3.3 网络流量形式检测

    3.3.1 Wi-Fi 调试(Android 11 及更高版本,无需借助 USB)

    从 Android 11 开始支持 ADB 以无线方式连接手机调试,可以彻底摆脱 USB 线:

    • 1)手机和电脑需连接在同一 Wi-Fi 下
    • 2)保证 SDK 为最新版本(adb --version ≥ 30.0.0
    • 3)手机启用开发者选项和无线调试模式(会提示确认)
    • 4)允许无线调试后,选择使用配对码配对。记下显示的配对码、IP 地址和端口号
    • 5)运行adb pair ip:port,使用第 4 步中的 IP 地址和端口号
    • 6)根据提示,输入第 3 步中的配对码,系统会显示一条消息,表明您的设备已成功配对
    • 7)(仅适用于 Linux 或 Windows)运行 adb connect ip:port

    3.3.2 WLAN 调试(Android 10 及更低版本,需要借助 USB)

    做过Android 开发的基本都知道,平常一般都是直接通过 USB 线或者 Type C线的方式连接,来完成日常的开发和调试,这种开发模式存在几个问题点,是一个极简主义者所不能忍受的

    • 电脑的 USB 口比较少,特别是 MAC 电脑,新版的就更是少得可怜
    • 有时候有些功能模块比较耗电的时候,手机耗电的速度会比电脑充电的速度慢,比如开发直播间模块,要长时间开摄像头的情况下

    Android 10以及更低的版本,必须通过 USB 连接后,才可实现同一 WLAN 下无线调试:

    • 手机和电脑需连接在同一 WiFi 下;
    • 手机开启开发者选项和 USB 调试模式,并通过 USB 连接电脑(即adb devices -l,可以查看到手机)
    • 设置手机的监听adb tcpip 5555
    • 拔掉 USB 线,找到手机的 IP 地址
    • 通过 IP 连接到手机adb connect ip(端口默认:5555)
    • adb devices -l命令查看

    :Android 8 以上默认是开启Wi-Fi调试模式的,Android 4~Android 8默认是不开启Wi-Fi调试模式的

    1)手机和电脑通过USB方式连接

    • 输入adb tcpip PORT,PORT表示要开启WI-FI调试的端口,建议使用默认端口5555
    adb tcpip 5555
    
    • 1

    • 使用adb shell在手机端执行setprop service.adb.tcp.port PORT命令,port表示要开启WI-FI调试的端口,建议使用默认端口5555
    • 使用adb shell在手机端执行stop adbd
    • 使用adb shell在手机端执行start adbd。执行adb shell会默认启动adbd,所以adbd start不是必须执行的
    adb shell
    # ">"为在手机端shell模式中
    > setprop service.adb.tcp.port 5555
    > stop adbd # 执行完会断开"adb shell"
    adb shell adbd start
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2)不需要adb的方式

    • root的手机不需要用usb链接电脑使用adb的方式来开启WI-FI调试模式。不过需要安装一个可以执行命令的App

    • 手机需要Root,且安装了可以执行命令的App。下载安装Android-Terminal-Emulator,然后打开“模拟终端”,然后执行以下命令

      • Android-Terminal-Emulator下载地址:https://jackpal.github.io/Android-Terminal-Emulator/

    在这里插入图片描述

    TCP/IP方式:

    # 执行如下命令来,使用WI-FI调试模式
    su
    setprop service.adb.tcp.port 5555
    stop adbd
    start adbd
    
    • 1
    • 2
    • 3
    • 4
    • 5

    su && setprop service.adb.tcp.port 5555 && stop adbd && start adbd
    
    • 1

    USB方式:

    su
    setprop service.adb.tcp.port -1 # 表示打开adb的usb调试功能
    stop adbd
    start adbd
    
    • 1
    • 2
    • 3
    • 4
    • 保证手机和电脑在同一个局域网内,查看手机Wi-Fi的IP地址,并且手机开启了Wi-Fi调试功能
    • 使用adb connect HOST[:PORT]与手机进行连接,port默认5555
    # 以下两个命令都可以,不输入端口号则默认使用":5555"
    adb connect 192.168.9.5
    adb connect 192.168.9.5:5555
    
    • 1
    • 2
    • 3

    断开WI-FI调试连接的命令

    # 以下两个命令都可以,不输入端口号则默认使用":5555"
    adb disconnect 192.168.9.5
    adb disconnect 192.168.9.5:5555
    
    • 1
    • 2
    • 3

    3.3.3 网络流量形式检测是否攻击者adb接入Android 设备方法

    网络形式的ADB会监听一个端口,那有一个非常简单的方法就是判断这个端口是不是有TCP连接,只要有连接,我们就认为被ADB控制了(很简单的判断,没去管有无数据传输,就算没得数据传输,但是连接了,说明这个设备其实也被ADB控制过)

    service.adb.tcp.port表示网络无线ADB要配置的默认端口

    回到检测规则上来,如果没设置service.adb.tcp.port的话,得到的应该是空值或啥也没有回显

    在这里插入图片描述

    • 先用getprop命令去得到adb监听的端口,如果为空的话就是5555,然后就可以看adb监听的端口是否有连接,下面是统计5555端口连接次数,来判断当前有几个掉毛接入进来
    setprop service.adb.tcp.port 5555
    getprop | grep adb.tcp.port
    netstat -an | grep 5555
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    • 统计adb已连接的次数,状态为"established"
    netstat -nat | grep -i "5555" | grep ESTABLISHED | wc -l
    
    • 1

    在这里插入图片描述

    补充:还有一个方法,是获取TCP流量data数据的二进制流,来检测adbd接收到的TCP数据包中是否包含”host:version”,且相应回去的TCP数据包中包含有:"OKAY",就告警。但许多时候Android 终端因为隐私问题,数据采集受限,感兴趣的可以自行尝试一下,博主同学这里没有没有去尝试

    参考链接

    https://www.jianshu.com/p/790b29b80117

    https://cloud.tencent.com/developer/article/1809910

    https://blog.csdn.net/Xiaoma_Pedro/article/details/103919142

    https://blog.csdn.net/u014135607/article/details/80011192

    https://www.jianshu.com/p/a47e1c90b9bf

    https://zhuanlan.zhihu.com/p/472198430

    https://cczheng.blog.csdn.net/article/details/103434756

    http://www.shibaking.com/blog/2020-04-08-Android%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91user%E7%89%88%E6%9C%AC%E9%BB%98%E8%AE%A4%E5%BC%80%E5%90%AFadb%E8%B0%83%E8%AF%95.html


    你以为你有很多路可以选择,其实你只有一条路可以走


  • 相关阅读:
    2023 Google 开发者大会学习心得总结
    powerlevel10k 颜色和图标的自定义设置
    Pandas多级索引数据处理及fillna()填充方式
    数字化转型中的“数字化”
    Redis系列:使用Redis实现分布式锁及相关问题
    为什么要学习更加现代的命令行工具?
    IPC通信
    nginx源码安装
    SSH本地连接---Hadoop单词统计
    可编程数据平面(论文阅读)
  • 原文地址:https://blog.csdn.net/Ananas_Orangey/article/details/126464387