IPLocate DNS 方案 逆向分析

216 阅读3分钟

1. 静态分析

使用 IDA 分析可执行文件 IPLocate,在方法列表中搜索 dns,可以看到有用到 NEDNSSettingsManager 类。

image1.jpg

然后在 Strings Table 中搜索 dns,可以看到有一个关键的 URL: https://anyto-app-dns.irocketx.com/dns-query

image2.jpg

再继续查找看看有哪个类需要用到这个 URL,最终看到 NEDNSOverHTTPSSettings 类中用到了这个 URL。

image3.jpg

通过查看系统 API,可以知道这个 URL 将设置到 NEDNSOverHTTPSSettings 类的 serverURL 属性。

image4.jpg

2. 动态追踪

通过静态分析,我们找到了两个关键类:NEDNSSettingsManagerNEDNSOverHTTPSSettings。下面我们使用 Frida 来动态追踪这两个类。 打开 IPLocate App,然后使用 frade-trace 命令追踪 NEDNSSettingsManagerNEDNSOverHTTPSSettings 类的所有方法:

frida-trace -U -m "-[NEDNSSettingsManager *]" -m "-[NEDNSOverHTTPSSettings *]"  IPLocate

运行上面的命令后 会在当前目录生成名为 __handlers__ 的文件夹,其中包含为每个跟踪的函数生成的 JS 文件。可以编辑这些文件来自定义行为。 对于 NEDNSSettingsManager 类,我们主要关注的是 setDnsSettings: 这个方法, 将 setDnsSettings_.js 文件内容替换为以下内容来获取所有的 DNS 配置信息:

defineHandler({
  onEnter(log, args, state) {
    log(`-[NEDNSSettingsManager setDnsSettings:] called`);

    // 将 args[2] 转换为 ObjC 对象以便访问其属性
    const dnsSettings = new ObjC.Object(args[2]);

    // 打印各个属性值
    log(`NEDNSSettings details:`);
    log("- className: " + dnsSettings.$className);
    log(`- servers: ${dnsSettings.servers()}`);
    log(`- searchDomains: ${dnsSettings.searchDomains()}`);
    log(`- domainName: ${dnsSettings.domainName()}`);
    log(`- matchDomains: ${dnsSettings.matchDomains()}`);
    log(`- matchDomainsNoSearch: ${dnsSettings.matchDomainsNoSearch()}`);
  },

  onLeave(log, retval, state) {},
});

对于 NEDNSOverHTTPSSettings 类,我们主要关注的是 setServerURL: 这个方法, 将 setServerURL_.js 文件内容替换为以下内容:

defineHandler({
  onEnter(log, args, state) {
    // 打印 setServerURL 方法的参数
    const objcObj = new ObjC.Object(args[2]);
    log(`-[NEDNSOverHTTPSSettings setServerURL:${objcObj.toString()}]`);
  },

  onLeave(log, retval, state) {},
});

由于改动了脚本,所以需要先停止本次追踪,关闭App后重新打开,然后再次运行命令:frida-trace -U -m "-[NEDNSSettingsManager *]" -m "-[NEDNSOverHTTPSSettings *]" IPLocate ,在 IPLocate App 打开 DNS 设置,将得到如下的关键日志信息:

  3836 ms  -[NEDNSOverHTTPSSettings setServerURL:https://anyto-app-dns.irocketx.com/dns-query]
  3850 ms  -[NEDNSSettingsManager loadFromPreferencesWithCompletionHandler:0x283c0f420]
  3866 ms  -[NEDNSSettingsManager setDnsSettings:] called
  3866 ms  NEDNSSettings details:
  3866 ms  - className: NEDNSOverHTTPSSettings
  3866 ms  - servers: (
    "47.251.43.55"
)
  3866 ms  - searchDomains: null
  3866 ms  - domainName: null
  3866 ms  - matchDomains: null
  3866 ms  - matchDomainsNoSearch: false
  3877 ms     | -[NEDNSOverHTTPSSettings copyWithZone:0x0]
  3878 ms     |    | -[NEDNSOverHTTPSSettings serverURL]
  3878 ms     |    | -[NEDNSOverHTTPSSettings setServerURL:https://anyto-app-dns.irocketx.com/dns-query]
  3878 ms     |    | -[NEDNSOverHTTPSSettings identityReference]
  3878 ms     |    | -[NEDNSOverHTTPSSettings setIdentityReference:0x0]
  3878 ms     | -[NEDNSOverHTTPSSettings .cxx_destruct]
  3878 ms  -[NEDNSSettingsManager setLocalizedDescription: IPLocate
  3879 ms  -[NEDNSSettingsManager saveToPreferencesWithCompletionHandler:0x283d46f10]
  3879 ms     | -[NEDNSOverHTTPSSettings checkValidityAndCollectErrors:0x283d46a30]
  3879 ms     |    | -[NEDNSOverHTTPSSettings serverURL]
  3880 ms     |    | -[NEDNSOverHTTPSSettings serverURL]
  3880 ms  -[NEDNSOverHTTPSSettings .cxx_destruct]
           /* TID 0x1a03 */
  3881 ms  -[NEDNSOverHTTPSSettings encodeWithCoder:0x2834640c0]
  3881 ms     | -[NEDNSOverHTTPSSettings serverURL]
  3881 ms     | -[NEDNSOverHTTPSSettings identityReference]

根据上面的日志分析,可以知道 NEDNSOverHTTPSSettings 类的信息如下:

  • 设置了 DNS over HTTPS (DoH) 服务器 URL 为 anyto-app-dns.irocketx.com/dns-query
  • 配置了一个 DNS 服务器 IP 地址:47.251.43.55,查询得知这是一个阿里云服务器的地址。

通过上面的日志信息,我们也大概可以生成相应的代码:

- (void)configureDNSSettings {
    // 创建 DNS over HTTPS 设置
    NEDNSOverHTTPSSettings *dohSettings = [[NEDNSOverHTTPSSettings alloc] initWithServers:@"47.251.43.55"];
    dohSettings.serverURL = [NSURL URLWithString:@"https://anyto-app-dns.irocketx.com/dns-query"];

    NEDNSSettingsManager *dnsManager = NEDNSSettingsManager.sharedManager;
    // 加载当前设置
    [dnsManager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
        if (error) {
            NSLog(@"加载 DNS 设置失败: %@", error);
            return;
        }

        dnsManager.dnsSettings = dohSettings;
        dnsManager.localizedDescription = @"IPLocate";

        [dnsManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable saveError) {
            if (saveError) {
                NSLog(@"保存 DNS 设置失败: %@", saveError);
            } else {
                NSLog(@"DNS 设置已成功保存");
            }
        }];
    }];
}

运行上面的代码后,DNS 配置会被安装到 iOS 系统,在 系统设置 > 通用 > VPN 与设备管理 中可以看到多了一个 DNS 的配置项。