NEPacketTunnelProvider Sniffer iOS

18

最近我找到了一篇论文, 描述了使用苹果的NEPacketTunnelProvider扩展来进行iOS嗅探机制,这引起了我的好奇心并让我想从技术角度理解它。由于我通常不在如此深层次的网络层工作,因此我无法以我想要的细节理解它。由于Charles Proxy for iOS必须执行非常相似的操作而不需要监督设备,因此我认为作者在2016年提出的方法可能仍然适用于现在。

作者声称,“像IP数据包解析、构建IP数据包或解析DNS响应等所有内容都必须自己实现。”为了完全理解这一点,我试图自己构建它。我构建了一个NetworkExtension和一个消息循环,用于NEPacketTunnelProviderpacketFlow。我能够获取IP数据报并尝试解析它们。我为源IP、目标IP、传输协议和IP版本使用相应大小的无符号整数,但我不确定如何处理有效载荷。我的解析器使用ptr.load(fromByteOffset: <offset>, as:<DataType>.self),其中ptr是访问数据包流信息的UnsafeRawPointer。由于data可能超出UInt64的存储范围,我不知道如何以正确的方式访问和存储有效载荷。
此外,我发现源IP始终为192.168.20.1(设置为我的接口的NEIPv4Settings地址),而目标IP始终为192.168.2.1(我的虚拟NEDNSSettings服务器)。这引出了我的第一个问题:这些是DNS查询吗?数据包是否会声称有关实际目标的任何其他信息?这是否意味着我必须以某种方式执行对DNS服务器的请求并重新路由数据包以获取从该DNS查询中获取的目标?
下一步将是实现TCP / UDP处理,对吗?我的当前解析方法能够区分UDPTCPICMP(尽管我尚未调查最后一种)。因此,我将遍历数据报并查找它们是否需要UPDTCP会话/连接并传输数据报。我目前从概念上看到的问题是:我如何知道要用于TCP / UPD连接/会话的哪个源/目标端口?据我所知,这些信息不是IP数据包本身的一部分(因为这是我们在传输层级别上需要的一些信息,而不是在网络层级别上需要的信息)。
此外,我在Github上找到了一个名为Specht的项目。它使用了一个自己编写的库NEKit,该库以某种方式也使用了NEPacketTunnelProvider方法。如果我正确理解他们的方法,他们成功地通过编写一些观察机制来构建了一个本地代理服务器,以处理请求,但由于我对网络和Swift相对较新,我不确定我是否完全正确地理解了这一点,或者我是否只是没有找到所有那些TCP / UDP和/或DNS逻辑。这个项目与论文和Charles代理的方法相比如何?
最后一个问题:在大多数情况下,Charles代理能够显示目标主机名。我目前只能看到目标IP地址(这些不是真实的目标IP地址,而是我的DNS服务器的地址)。我如何能够看到主机名作为人类可读文本?Charles是否以某种方式执行nslookup?Charles是否从数据报中获取信息?
我知道在这个主题上有很多缺失的知识,建立类似的东西进行测试是相当雄心勃勃的,但我仍然有动力深入研究这个主题,并且也有感觉我已经理解了一些关键点,但不幸的是不足以解决难题...也许你能给我一些更多的提示,以获得更好的理解。如果可能有一种更简单的方法来实现类似的行为(查看主机名级别的传出连接),我也会对此感兴趣 :-)

既然你已经对NEPacketTunnelProvider做了足够的研究,能否花些时间帮忙解决以下两个问题:https://stackoverflow.com/questions/51178454/is-there-a-way-to-inject-a-basic-authorization-header-using-the-networkextensi 和 https://stackoverflow.com/questions/53852899/ios-keep-showing-proxy-authentication-required-dialog-even-after-passing-usern? - Mrug
1
你好!我希望能够帮助你。我打算花一周时间来完成这个挑战。当从应用程序(而不是扩展)创建NETunnelProviderProtocol时,你将服务器地址设置为什么?我假设是127.0.0.1,但我甚至无法加载网络扩展并调用startTunnel。 - wheresmycookie
1个回答

3
我发布了一个Beta Proxyman iOS网站)-使用NEPacketTunnelProvider和Network Extension的网络嗅探器,所以我可能已经有经验回答您的一些问题。

IP包、IP图表、DNS,如何解析它?

幸运的是,还有另一种方法可以设置NEPacketTunnelProvider,以提供HTTP消息而不是IP包(这太底层了,您必须处理解析器、DNS等)。
HTTP消息更容易解析,因为有很多可靠的库(例如来自nodeJS的http-parser
  1. 如何在iOS上构建网络嗅探器?
这是一个复杂的问题,我会将其分解成小块:

MitM /代理服务器

首先,您需要一个工作的MitM代理服务器,能够代理和拦截HTTP/HTTPS流量。您可以使用SwiftNIOCocoaAsyncSocket来实现它。

它是如何工作的?

一般来说,数据流可能是这样的:
互联网 -> iPhone -> 您的网络扩展(VPN) -> 转发到本地代理服务器(在网络扩展中) -> Mitm/代理服务器开始拦截或监视流量 -> 保存到本地数据库(在共享容器组中) -> 再次转发到目标服务器。
从主应用程序中,您可以通过读取本地数据库来接收数据。
我们需要一个本地数据库的原因是,网络扩展和主应用程序是两个不同的进程,因此它们无法像普通应用程序那样直接通信。

给我看代码?

在网络扩展中,让我们在Host:Port上启动一个代理服务器,然后初始化NetworkSetting,就像示例中的样子:
    private func initTunnelSettings(proxyHost: String, proxyPort: Int) -> NEPacketTunnelNetworkSettings {
    let settings: NEPacketTunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1")

    /* proxy settings */
    let proxySettings: NEProxySettings = NEProxySettings()
    proxySettings.httpServer = NEProxyServer(
        address: proxyHost,
        port: proxyPort
    )
    proxySettings.httpsServer = NEProxyServer(
        address: proxyHost,
        port: proxyPort
    )
    proxySettings.autoProxyConfigurationEnabled = false
    proxySettings.httpEnabled = true
    proxySettings.httpsEnabled = true
    proxySettings.excludeSimpleHostnames = true
    proxySettings.exceptionList = [
        "192.168.0.0/16",
        "10.0.0.0/8",
        "172.16.0.0/12",
        "127.0.0.1",
        "localhost",
        "*.local"
    ]
    settings.proxySettings = proxySettings

    /* ipv4 settings */
    let ipv4Settings: NEIPv4Settings = NEIPv4Settings(
        addresses: [settings.tunnelRemoteAddress],
        subnetMasks: ["255.255.255.255"]
    )
    ipv4Settings.includedRoutes = [NEIPv4Route.default()]
    ipv4Settings.excludedRoutes = [
        NEIPv4Route(destinationAddress: "192.168.0.0", subnetMask: "255.255.0.0"),
        NEIPv4Route(destinationAddress: "10.0.0.0", subnetMask: "255.0.0.0"),
        NEIPv4Route(destinationAddress: "172.16.0.0", subnetMask: "255.240.0.0")
    ]
    settings.ipv4Settings = ipv4Settings

    /* MTU */
    settings.mtu = 1500

    return settings
}

然后开始使用VPN。
let networkSettings = initTunnelSettings(proxyHost: ip, proxyPort: port)

// Start
setTunnelNetworkSettings(networkSettings) { // Handle success }

然后将包转发到您本地的代理服务器:
let endpoint = NWHostEndpoint(hostname: proxyIP, port: proxyPort)
self.connection = self.createTCPConnection(to: endpoint, enableTLS: false, tlsParameters: nil, delegate: nil)

    packetFlow.readPackets {[weak self] (packets, protocols) in
        guard let strongSelf = self else { return }
        for packet in packets {
            strongSelf.connection.write(packet, completionHandler: { (error) in
            })
        }

        // Repeat
        strongSelf.readPackets()
    }

从那里,您的本地服务器可以接收包并转发到目标服务器。
不要忘记将所有流量日志保存到本地数据库,然后通知主应用程序重新加载它。

最后一个问题:Charles代理在大多数情况下能够显示目标主机名。我目前只能看到目标IP地址(这些不是真正的目标IP地址,而是我的DNS服务器的地址)。我如何能够看到主机名作为人类可读的文本?Charles是否通过某种方式进行nslookup?Charles是否从数据报中获取该信息?

由于我们不处理IP包,因此我们不需要实现DNS解析器。如果您需要DNS,请像以下代码一样配置:
        let dnsSettings = NEDNSSettings(servers: ["8.8.8.8", "1.1.1.1"])
    settings.dnsSettings = dnsSettings

当我们接收到HTTP消息包时,您可以免费获取主机名(来自请求的URL或主机头)。
希望我的回答能对您有所帮助。

连接到VPN后,我的互联网无法正常工作。我该如何解决这个问题?你能帮我吗? - undefined
你应该检查一下你的HTTP服务器。它还能正常工作吗? - undefined
你是在说网络扩展隧道吗?我已经使用网络服务器创建了代理服务器,同时也在尝试通过SwiftNIO获取流量。我还在这个问题上发布了相关的问题:https://stackoverflow.com/questions/77301272/established-the-vpn-connection-for-network-sniffer 还有一件事,当我获取网络流量时,我们没有获得互联网连接,反之亦然(当获取互联网连接时,我们没有获得网络流量)。我正在使用OpenVPNAdapter进行VPN连接。 - undefined

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