Android 不会像 iOS 那样简单。没有 Bonjour 等价物。
Android 4.0 Ice Cream Sandwich 引入了Wi-Fi Direct Peer to Peer 网络。起初我希望它可以按照你的想法进行扫描,但它可以帮助 Android 设备在没有接入点的情况下进行通信,因此它们并不是真正“在你的网络上”。此外,ICS 仅在一小部分 Android 设备上运行。
与主动 netscan 方法不同,您将获得被动监控方法。如果您的网络是安全的,则可以嗅探加密数据包,但不方便。你必须
- 将您的网络接口置于监控模式
- 捕捉四次握手
- 使用网络的预共享密钥对其进行解密
- 这将为您提供解密流量所需的密钥
如果您想看到这一点,Wireshark支持WPA 解密。
一旦您能够查看 Wi-Fi 流量,您会注意到 Android 设备倾向于与某些 Google 服务器进行通信,并且它们的 HTTP 连接具有可以识别的用户代理字符串。这是可行的被动解决方案的基础。
Tenable Network Security提供的产品似乎采用了这种方法。
另一个想法
@Michelle Cannon 提到了 Libelium 的 Meshlium Xtreme,它的方法不会让你一路走好(如果没有最新的 MAC 地址范围表的话)。但这可能是实现较小目标的一部分。你可以:
- 检测所有无线设备
- 使用 MAC 的组织唯一标识符 (OUI) 消除 Apple 设备
- 通过监控信号强度来判断它是移动设备,从而判断它是移动设备(移动设备往往会出现并消失)
- 您也许可以使用 MAC OUI 作为 Android 的提示
- 您可以使用 MAC OUI 作为提示,它不是 Android(而是笔记本电脑或无线网卡等)。
如果您愿意检测可能是Android 的设备,这可能是可行的。
DHCP 指纹识别
@Michelle Cannon 建议使用 DHCP 指纹。一开始我并不确定,但我必须感谢他提出了简单被动扫描的最佳选择。作为一个警示性的尾巴,我想解释一下我为什么迟到了。
有些事情我们知道,认为我们不知道,有些事情我们认为我们知道但错了。
在很多方面,Android 使用 Linux 内核是件好事。但是,如果您想在网络上发现 Android 设备,那就不好了。Android 的 TCP/IP 堆栈是 Linux 的,因此 Android 设备看起来像 Linux 设备,或者我一开始是这么想的。但后来我意识到 Linux 有很多构建配置参数,所以当在网络上看到 Android 时可能会有一些与众不同的东西,但是什么?
DHCP 指纹识别使用设备请求的确切 DHCP 选项加上时间。为此,您通常需要一个最新的指纹数据库进行匹配。起初,fingerbank 似乎在寻找这些数据,但后来我注意到他们的文件已经将近一年没有更新了。对于所有不同的 Android 设备类型,我认为为单个项目保留更新的指纹是不切实际的。
但后来我查看了 Android 的实际 DHCP 签名,我注意到了这一点:
Android 1.0: dhcpvendorcode=dhcpcd 4.0.0-beta9
Android 1.5-2.1: dhcpvendorcode=dhcpcd 4.0.1
Android 2.2: dhcpvendorcode=dhcpcd 4.0.15
Android 3.0: dhcpvendorcode=dhcpcd-5.2.10
Linux 通常使用 dhclient 作为其 DHCP 客户端,但 Android 使用的是 dhcpcd。Android 强烈倾向于尽可能使用以 BSD 风格许可的软件,而 dhcpcd 使用 BSD 许可。似乎 dhcpvendorcode 可以用作移动设备运行 Android 的有力指标。
DHCP 监控
客户端在加入网络时使用 DHCP 获取 IP 地址,因此它在没有 IP 地址的情况下启动。它通过使用 UDP 广播进行初始交换来解决这个问题。在 Wi-Fi 上,即使使用 WPA,广播流量也不会加密。因此,您可以只在 UDP 端口 67 上侦听客户端到服务器的流量,而在 68 端口上侦听反向。您甚至不需要将网络接口置于混杂模式。您可以使用 Wireshark 等协议分析器轻松监控此流量。
我更喜欢编写代码来监控流量并决定使用 Python。我选择了 pydhcplib 来处理 DHCP 的细节。我对这个库的体验并不顺利。我需要手动下载并放置 IN.py 和 TYPES.py 支持文件。他们的数据包到字符串的转换将 dhcpvendorcode 留空。它确实正确解析了 DHCP 数据包,所以我只是编写了自己的打印代码。
下面是监控从客户端到服务器的 DHCP 流量的代码:
#!/usr/bin/python
from pydhcplib.dhcp_packet import *
from pydhcplib.dhcp_network import *
from pydhcplib.dhcp_constants import *
netopt = {
'client_listen_port':"68",
'server_listen_port':"67",
'listen_address':"0.0.0.0"
}
class Server(DhcpServer):
def __init__(self, options):
DhcpServer.__init__(
self,options["listen_address"],
options["client_listen_port"],
options["server_listen_port"])
def PrintOptions(self, packet, options=['vendor_class', 'host_name', 'chaddr']):
# uncomment next line to print full details
# print packet.str()
for option in options:
# chaddr is not really and option, it's in the fixed header
if option == 'chaddr':
begin = DhcpFields[option][0]
end = begin+6
opdata = packet.packet_data[begin:end]
hex = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
print option+':', ':'.join([(hex[i/16]+hex[i%16]) for i in opdata])
else:
opdata = packet.options_data.get(option)
if opdata:
print option+':', ''.join([chr(i) for i in opdata if i != 0])
print
def HandleDhcpDiscover(self, packet):
print "DHCP DISCOVER"
self.PrintOptions(packet)
def HandleDhcpRequest(self, packet):
print "DHCP REQUEST"
self.PrintOptions(packet)
## def HandleDhcpDecline(self, packet):
## self.PrintOptions(packet)
## def HandleDhcpRelease(self, packet):
## self.PrintOptions(packet)
## def HandleDhcpInform(self, packet):
## self.PrintOptions(packet)
server = Server(netopt)
while True :
server.GetNextDhcpPacket()
此代码基于 pydhcplib 的服务器示例,因为它像服务器一样侦听客户端请求。
当我的 Nexus 7 Android 4.2 平板电脑连接时,这个有趣的信息被捕获(编辑):
DHCP REQUEST
vendor_class: dhcpcd-5.5.6
host_name: android-5c1b97cdffffffff
chaddr: 10:bf:48:ff:ff:ff
DHCP DISCOVER
vendor_class: dhcpcd-5.5.6
host_name: android-5c1b97cdffffffff
chaddr: 10:bf:48:ff:ff:ff
主机名似乎具有固定的格式并且易于解析。如果您需要 IP 地址,您可以监控服务器到客户端的流量。注意:只有初始交换,即新客户端首次出现而没有 IP 地址时,才会被广播。不广播未来的租约延期等。
@Luis 发布了一个很棒的解决方案,它展示了越简单越好。即使在看到 Android 的 DHCP 客户端将 host_name 设置为 android-5c1b97cdffffffff 之后,我也不认为使用反向 DNS 查找向路由器询问它的名称列表。路由器将 host_name 添加到它的 DNS 服务器,因此如果设备的 IP 地址发生变化,您仍然可以访问设备。
在 DHCP 租用期间,host_name 预计将在 DNS 中保持列出。您可以通过ping来检查设备是否仍然存在。
依赖 host_name 的一个缺点是可以通过多种方式进行更改。设备制造商或运营商很容易更改主机名(尽管经过搜索,我无法找到他们曾经拥有的任何证据)。有一些应用程序可以更改主机名,但它们需要 root,所以这最多是一个边缘情况。
最后还有一个开放的Android 问题 6111:允许指定当前有 629 颗星的主机名。在将来的某个时候,也许很快,在 Android 设置中看到可配置的 host_name 也就不足为奇了。因此,如果您开始依赖 host_name 来识别 Android 设备,请意识到它可能会从您下面被拉出来。
如果您正在进行实时跟踪,反向 DNS 查找的另一个潜在问题是您必须决定扫描的频率。(当然,如果您只是拍摄一次性快照,这不是问题。)频繁扫描会消耗网络资源,不频繁扫描会给您留下陈旧的数据。以下是添加 DHCP 监控的帮助:
- 启动时使用反向 DNS 查找查找设备
- ping 设备以查看它们是否仍处于活动状态
- 监控 DHCP 流量以立即检测新设备
- 偶尔重新运行 DNS 查找以查找您可能错过的设备
- 如果您需要注意设备离开,请以所需的时间分辨率 ping 设备
虽然这并不容易(也不是 100% 准确),但有几种技术可以在您的网络上发现 Android 设备。