在你的网络上发现安卓设备的方法有哪些?

61

我希望能够在我的网络上发现Android设备,并可能检索有关它们的一些设备信息。由于Apple设备运行Bonjour服务,因此这非常容易。但是,我似乎找不到任何类似的 Android 服务。

这必须在不修改Android设备、安装某些服务或打开某些端口的情况下工作。它旨在以 Bonjour 帮助您发现香草苹果设备的方式与香草Android设备配合使用。甚至仅能验证设备是否运行 Android 也足够了。


选定答案:尽管它不是最高评级的答案(但),请看Luis的回复。正如他提到的,您可以使用DNS查找(使用本地DNS服务器)来发现Android设备。我已经发现这具有100%的成功率,因为Android强制设备使用主机名android-_____。即使是Rooted手机,这似乎也很难更改。所以我认为这是一个相当准确的方法。谢谢,Luis!

Example:
$ nslookup 192.168.1.104 192.168.1.1
Server:     192.168.1.1
Address:    192.168.1.1#53

104.1.168.192.in-addr.arpa  name = android-711c129e251f14cf.\001.

示例代码: 如果想在Java中实现此操作(例如在Android上运行),则无法轻松使用getHostName(),因为它使用外部DNS服务器。 例如,您希望使用路由器上的本地DNS服务器。 Luis在下面提到,您可以修改Wifi连接的DNS服务器,但这可能会破坏其他事情。 相反,我发现dnsjava库非常有用,可以发送定向DNS请求。 这是使用该库的一些示例代码:

        String ipAddress = "104.1.168.192";
        String dnsblDomain = "in-addr.arpa";
        Record[] records;
        Lookup lookup = new Lookup(ipAddress + "." + dnsblDomain, Type.PTR);
        SimpleResolver resolver = new SimpleResolver();
        resolver.setAddress(InetAddress.getByName("192.168.1.1"));
        lookup.setResolver(resolver);
        records = lookup.run();

        if(lookup.getResult() == Lookup.SUCCESSFUL) {
              for (int i = 0; i < records.length; i++) {
                if(records[i] instanceof PTRRecord) {
                  PTRRecord ptr = (PTRRecord) records[i];
                  System.out.println("DNS Record: " + records[0].rdataToString());
                }
              }
        } else {
            System.out.println("Failed lookup");
        }

    } catch(Exception e) { 
        System.out.println("Exception: " + e);
    }

这里是我的输出:

DNS Record: android-711c129e251f14cf.\001.

没错。


谢谢,但不完全是我要找的!我正在寻找一种在不安装任何服务的情况下发现Android客户端的方法。这意味着在它们上面安装一个Bonjour服务,然后使用mDNS。寻找已经“开放”的东西来帮助发现Android设备。 - gnychis
请不要加上“神奇”的评论……我理解技术障碍以及苹果设备预装了某些服务(例如Bonjour)。我的问题是,Android上是否存在我所缺少的类似服务。我规定不添加服务,因为否则每个人都会回答:“只需添加Bonjour服务!”我理解区别,最终答案可能只是:“没有。”没关系,我在寻求帮助。当你向他人提问时,有些你不知道存在的东西往往会出现。 - gnychis
是的,看看我的回答,我也找到了一些替代方案,然后想到了一些其他方法,使用更积极而不是被动的监控,我提供的网址上的文章非常有趣,它解释了如何测量像购物中心这样的WiFi热点上的设备渗透。我怀疑室内GPS服务以类似的方式工作,非常迷人的东西。 - Michelle Cannon
@gnychis,好问题。您知道如何在iOS中实现相同的功能吗?有任何示例代码将会很有帮助。 - Alejandro Vargas
@gnychis 只是一个简短的问题,为了让我清楚。192.168.1.104 是你的 Android 设备在 WiFi 上的 IP 地址,而 192.168.1.1 是你的 WiFi 路由器的 IP 地址?还是关于其他服务器,我使用不正确?谢谢。 - AlexAndro
显示剩余7条评论
7个回答

34

有一种非常简单的方法,在几个不同的设备上为我提供了积极的结果。

当设备连接到您的路由器时,它会收到一个IP(即DHCP)并在DNS中注册一个名称。所注册的名称似乎总是以android_nnnnnnnn的形式。

当然,您可以使用相同的方法命名任何计算机并欺骗检查,导致错误的结果...

此外,我无法保证所有设备供应商都遵循相同的方法,但我已经在我测试过的几个不同品牌的设备(包括不同的SDK级别)中发现它可以正常工作。

--编辑--

如何操作

这取决于您将在何处运行代码以发现Android设备。假设您将在Android设备中运行代码:

  1. 首先发现响应网络ping的设备。您可以使用我的回答中的代码运行ping命令:execComd()

  2. 使用以下代码获取响应设备的名称:

    InetAddress inetAddress = InetAddress.getByName(string_with_ip_addr);

    String name = inetAddress.getCanonicalHostName();

--编辑2--

概念证明

以下方法只是我上面所写内容的一个概念证明。

我使用isReachable()方法生成ICMP请求,许多文章中说这种方法只适用于已取得root权限的设备,在我测试用的设备上也是如此。但是,我没有为运行此代码的应用程序授予root权限,因此我认为它无法设置SIUD位,这就是为什么有些人声称此方法失败的原因。我想从在非root设备上测试它的人的角度来做到这一点。

调用方法:

ArrayList<String> hosts = scanSubNet("192.168.1.");

它返回一个名为hosts的列表,其中包含响应ping请求的设备的名称。

private ArrayList<String> scanSubNet(String subnet){
    ArrayList<String> hosts = new ArrayList<String>();
    
    InetAddress inetAddress = null;
    for(int i=1; i<10; i++){
        Log.d(TAG, "Trying: " + subnet + String.valueOf(i));
        try {
            inetAddress = InetAddress.getByName(subnet + String.valueOf(i));
            if(inetAddress.isReachable(1000)){
                hosts.add(inetAddress.getHostName());
                Log.d(TAG, inetAddress.getHostName());
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    return hosts;
}

敬礼。


嗨Luis,你能详细解释一下吗?如何查询网络/路由器以检查注册的DNS名称?我确实在来自Android设备的DHCP请求中看到了一个Android字符串,但我不想依赖于偶尔听到的请求来检测它。如果您有一些查询该DNS名称的方法,我很乐意听听。 - gnychis
编辑了我的答案并添加了额外的信息。 - Luis
嗨Luis,在我的本地网络中,我尝试过“nslookup 192.168.1.103”(例如),但它从未解析出主机名。我不确定本地/消费级路由器实际上支持什么类型的DNS支持。你能成功吗?我认为问题的一部分是nslookup正在使用外部DNS服务器:输出显示“Server:128.2.184.224”。 - gnychis
是的,这确实很有帮助...但速度比较慢。所以,如果有人非常注重速度,也许可以尝试在安卓上使用nmap。 - Yong
@Luis,我确认getHostName()通常会返回IP地址。更多细节请参见https://dev59.com/SlsW5IYBdhLWcg3wi32j。 - AlexAndro
显示剩余18条评论

21

Android不像iOS那么简单,没有Bonjour的等价物。

Android 4.0,冰激凌三明治,引入了Wi-Fi Direct点对点网络。起初我希望它能够被扫描以便像你所想的那样使用,但它可以帮助Android设备在没有访问点的情况下进行通信,因此它们并不真正“在您的网络上”。此外,ICS仅运行在部分Android设备上。

与其采用主动netscan方法,不如采用被动监视方法。如果您的网络是安全的,则可能会嗅探加密数据包,但这很麻烦。您需要:

  • 将您的网络接口设置为monitor mode
  • 捕获4-way handshake
  • 使用网络的预共享密钥解密它
  • 这将给您解密流量所需的密钥
如果您想实际操作,Wireshark 支持 WPA 解密
一旦您能够查看 Wi-Fi 流量,您会注意到 Android 设备倾向于与某些 Google 服务器通信,并且它们的 HTTP 连接具有可识别的用户代理字符串。这是可行被动解决方案的基础。 Tenable Network Security 提供的产品似乎采取了这种方法。

另一个想法

@Michelle Cannon提到了Libelium的Meshlium Xtreme,其方法不会让您完全达成目标(没有好的最新MAC地址范围表就不行)。但它可以成为达成较小目标的一部分。 您可以:

  • 检测所有无线设备
  • 使用MAC的组织唯一标识符(OUI)消除苹果设备
  • 通过监测信号强度来确定它是否移动,以此判断它是移动设备(移动设备会出现并消失)
  • 您可以使用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 地址时进行广播。未来的租约扩展等不会进行广播。 反向 DNS 查找 @Luis 发布了一个很好的解决方案,证明了简单就是更好。即使看到 Android 的 DHCP 客户端将 host_name 设置为 android-5c1b97cdffffffff,我也没有想到使用反向 DNS 查找向路由器请求其名称列表。路由器会将 host_name 添加到其 DNS 服务器中,因此即使其 IP 地址发生更改,仍然可以访问该设备。
预计 host_name 将在 DHCP 租用期内保留在 DNS 中。您可以通过 ping 来检查设备是否仍然存在。
依赖于host_name的一个缺点是它可能会被更改。设备制造商或运营商很容易更改host_name(尽管经过搜索,我未能找到任何证据表明他们曾经这样做)。有apps to change host name,但它们需要root权限,因此只是个例外情况。
最后,目前有629个星标的Android Issue 6111: Allow a hostname to be specified是开放的。在将来的某个时候,可能很快就会在Android设置中看到可配置的host_name。因此,如果您开始依赖host_name来识别Android设备,请意识到它可能会在您面前被撤回。
如果您正在进行实时跟踪,则使用反向DNS查找的另一个潜在问题是您必须决定扫描频率。 (当然,如果您只是进行一次性快照,则这不是问题。)频繁扫描会消耗网络资源,而不频繁则会导致数据过时。以下是如何添加DHCP监视可以帮助解决此问题:
  • 启动时使用反向DNS查找来查找设备
  • ping设备以查看它们是否仍然活动
  • 监视DHCP流量以立即检测新设备
  • 偶尔重新运行DNS查找以查找可能遗漏的设备
  • 如果您需要注意设备离开,请在所需时间分辨率下ping设备

虽然这并不容易(也不是100%准确),但有几种技术使得在网络上发现Android设备成为可能。


谢谢回复!我正在研究Wi-Fi Direct文档。被动监视方法很好,但在WPA2加密下会失效,因为您无法监视每个链接的流量。 - gnychis
这就是为什么我在你的问题下发表了一条评论,询问你的网络架构。如果发现机器是AP(虽然我知道这很不可能且有限制),那会更有帮助。 - jimhark
从我所发现的和《黑客揭秘无线网络》这些书籍来看,它们可能是最好的信息来源。一个主动扫描应该可以让你得到设备的类型或制造商,其中任何一个都应该能帮助你确定设备是否为安卓或其他系统。不确定安全性或防火墙是否会阻止此操作,而且你可能需要广播SSID或以某种方式将其提供给发现设备。蓝牙可能是最好的选择,但它的覆盖范围很短。如果所有客户端都在一个房间或汽车内,或者你有某种类型的中继器。 - Michelle Cannon
你仍然可以看到广播流量。你的Android发现系统会全天候运行吗?如果是这样,你可能能够监视WEP的4路握手(RSN协议)并收集解密会话所需的信息。Wi-Fi网络所有者将是运行发现系统的人吗?如果是这样,你可能需要伪造去认证数据包来帮助解决这个问题。 - jimhark
无论是否有赏金,这都是一场引人入胜的讨论。我建议看看这本书,里面有很多有用的信息:《网络取证:通过网络空间追踪黑客》作者:Sherri Davidoff;Jonathan Ham,出版社:Prentice Hall,出版日期:2012年6月13日,插入日期:2012年3月30日。目录 • 开始阅读,除非您能够利用蓝牙嗅探或使用专门的硬件,否则您的服务器将不得不充当一种嗅探器。 - Michelle Cannon
好观点Jimhark,即使在安全网络上,您仍然可以从描述符中获取足够的信息来确定制造商,我想问题是网络有多安全。 - Michelle Cannon

5
据我所知,Android系统在其内置的系统应用/服务堆栈中没有提供任何零配置应用/服务。为了在连接到本地网络的实际设备上启用自动发现功能,您需要安装一些第三方零配置应用程序或开发自己的应用/服务并将其安装在实际设备上,其中一些API选项包括:
  • JmDNS(适用于Apple的Bonjour协议)
  • Cling(适用于Microsoft的UPnP协议)
  • Android NSD API(自Android 4.1以来引入)
我不太清楚您的要求,如果您想在原生Android设备上实现类似的功能(即自动发现和连接),您可能可以使用 Wi-Fi Direct,该功能现在可在运行Android 4.0的某些较新设备上使用,但它需要两个设备都支持Wi-Fi Direct,并且仅在关闭Wi-Fi的情况下创建一个点对点的ad-hoc连接,就像带有更长范围的蓝牙连接一样。

enter image description here

如果需要Wi-Fi Direct API支持,请查看官方指南-无线连接设备


2

我正在查看这个并思考

http://www.libelium.com/smartphones_iphone_android_detection

请特别注意以下内容

用户需要安装特定的应用程序或以某种方式进行交互才能被检测到吗?

不需要,扫描是静默执行的,Meshlium只会检测智能手机中集成的Wifi和蓝牙无线电发出的“信标帧”。用户只需要至少打开其中一种无线接口即可。

很久以前,我曾在我的Mac上使用一个叫做Stumbler的应用程序来查找WiFi网络,我认为这很类似

其他想法

如果我需要确定本地网络上的Android手机,我该怎么办。如果没有运行DNS服务,我只有几种可能性

SSID(如果正在广播)-不能告诉我任何信息 IP地址-Android允许您对主机命名有很多控制权,因此我猜您可以将特定的IP范围定义为Android设备。 -不太有用。

或者说,假设我在网络上看到一个未知设备,如果蓝牙已打开,则我正在广播蓝牙设备签名SDPP,我可以使用它来推断我的设备类型。

如果我正在运行支持Android的服务,并且我想要在我的网络上发现特定的Android设备,那么我只需注册这些设备的MAC地址,并在网络上观察它们即可。

除此之外,您需要在设备上运行Bonjour(dns-sd)或UPnP dameon。


没有一种方法会达到100%的准确性,但通过逐步排除,您可以排除苹果,可能从笔记本电脑中推断出移动电话,因此只剩下少量手机,黑莓使用常见的 WLAN 卡。 - Michelle Cannon
没有其他方法可以嗅探,我看不到其他办法。如果这是你的网络,那就不算黑客行为,对吧?我认为整个过程的目的是减少误报,一旦你得到了候选设备列表,我想安卓设备上会有某种客户端应用程序,否则这一切都没有意义。这个应用程序到底是什么?现在你查询设备并消除不回应的设备。我认为他们使用硬件使其变得容易,但所有的“工具”已经可用,如果你自己动手做,就更难使用了。 - Michelle Cannon
重新阅读问题后,实际上可能并没有客户端应用程序。我认为我们共同概述的方法涵盖了大约99%的情况,其余的情况将是除黑莓、Windows Phone、iPhone和当然Android之外的其他平板电脑和手机。 - Michelle Cannon
如此活跃的WiFi扫描器+端口扫描器,听起来确实像是一个黑客工具,但这正是你在这里所需要的 :-) 实际上,它可以 1)扫描蓝牙 2)进行活动WiFi扫描 3)对仍未确定的设备进行端口扫描。 - Michelle Cannon
优秀的链接和针对DHCP指纹识别的好主意。这里有另外一个链接:http://www.fingerbank.org/。我正在撰写一篇关于DHCP指纹识别的文章。 - jimhark
显示剩余5条评论

1

我从这个主题中学到了很多。

还有一种叫做DHCP指纹识别的东西,显然不同的设备对我们所讨论的网络扫描方式(如使用Linux扫描器NMAP)会有不同的反应。这些探测行为的地图可以在互联网上找到。

http://www.enterasys.com/company/literature/device-profiling-sab.pdf

https://media.defcon.org/dc-19/presentations/Bilodeau/DEFCON-19-Bilodeau-FingerBank.pdf

http://community.arubanetworks.com/t5/ArubaOS-and-Mobility-Controllers/COTD-DHCP-Fingerprinting-how-to-ArubaOS-6-0-1-0-and-above/td-p/11164

http://myweb.cableone.net/xnih/


从我们正在进行的研究中可以清楚地看出一件事,没有任何方法是100%有效且容易的。此外,还有一些组织和硬件OEM已经回答了这个问题,也许最好的方法是软件和硬件的结合。 - Michelle Cannon
我几乎感觉自己要写一个网络扫描器,而不是为此想出对策 :-) - Michelle Cannon
你最近发布了一些很棒的链接。我深入研究并使用Python进行了一个DHCP指纹的概念验证。我会尝试在明天发布代码和说明文档。 - jimhark

1

更新回复

很抱歉,我没有正确理解原始问题。只有您的评论让我真正明白您不想在目标设备上安装任何东西,而是想要一种发现网络中随机手机的方法。

我不确定这是否真的可能以您想要的方式实现。如果Android上没有运行任何网络发现服务,您将无法首先找到该设备。当然,您可以使用一些低级网络协议,但这只会给您一个指示,即有某些东西存在,但不知道它是什么(是Android设备、PC还是其他什么)。

最有前途的方法是检查预安装的具有某种网络功能的应用程序。例如,三星设备有Kies Air(如果用户启用它),摩托罗拉使用UPnP作为其媒体服务器,HTC也有自己的东西,如果我记得正确的话。但是,并非所有供应商和运营商的所有Android设备都安装了同一个应用程序。因此,您不能仅依赖其中之一,而需要使用它们各自的特定协议和行为来检查各种不同的服务,以获取有关设备的其他信息。当然,用户必须启用功能,您才能使用它。

旧回复

除了yorkw的列表,另一个选择是高通的AllJoyn。这是一个我自己过去已经使用过的开源跨平台发现和点对点通信框架。

尽管高通是AllJoyn的大赞助商,但这并不意味着您需要在定义中使用高通芯片组。实际上,AllJoyn适用于任何芯片组,包括英特尔和nVidia。它不需要root手机或对Android框架进行任何其他修改,只需使用Wi-Fi和/或蓝牙作为配对方法即可“开箱即用”。


AllJoyn库的概念看起来很好,很不错。但是当我想要编码时...它根本不适用。我不知道为什么...在这里看一下:https://ask.allseenalliance.org/question/683/no-discovered-device-found-android/ - gumuruh

-1
这是一个单行命令,可以对您的网络中的所有机器进行ping操作(假设您的网络为192.168.1.x),并对它们的名称进行反向查找:
for i in {1..255}; do echo ping -t 4 192.168.1.${i} ; done | parallel -j 0 --no-notice 2> /dev/null | awk '/ttl/ { print $4 }' | sort | uniq | sed 's/://' | xargs -n 1 host 

需要GNU parallel才能工作。您可以使用“brew install parallel”在OSX上安装它

从这里,您只需查看名为android-c40a2b8027d663dd.home.或其他设备的名称。

然后,您可以尝试在设备上运行nmap -O,以查看您可以找出什么其他信息:

sudo nmap -O android-297e7f9fccaa5b5f.home.

但这并不是非常有成效的。


请注意,此解决方案可能无法适用于三星设备,因为用户可以命名主机名,并且不像其他品牌那样经常在主机名中包含“android”。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接