android手机免root修改hosts

android手机免root修改hosts

痛点在哪里

开发及测试过程中经常需要切换开发、测试、预发布等环境,切换环境是通过修改hosts实现的。

android设备修改hosts看似简单,实际却会遇上不少麻烦,特别是在公司的网络环境中。你可能会遇到这种情况:

adb shell进去修改/etc/hosts,发现只读无法修改,需要root权限。尝试各种方法还是root失败后,转而想要通过电脑代理的方法避开root,但是这种方法需要把电脑也转网到staff-wifi,转网后一堆开发软件设置的代理也得跟着改,linux环境变量也得跟着改,总之一堆麻烦,而且从staff-wifi转回开发网或办公网还需要审核,想想就放弃了。。。

总结几种方法

1、root手机,修改/etc/hosts。

缺点:手机越来越难root,比如华为已经不允许申请手机解锁码。

2、手机和电脑连到同一个wifi(比如staff-wifi),手机设置代理到电脑(fiddler启动电脑代理服务),修改电脑的hosts。

缺点:依赖于电脑,而且因为手机无法连入开发网或办公网,电脑可能需要转网。

3、拦截DNS请求,直接返回所需要的A记录。

思来想去,如果可以修改DNS的回包,不是也相当于修改hosts的效果嘛!但怎么改?会不会也有root权限问题?

如何实现方法3

经历了一番痛苦后,笔者决定写个工具来实现改hosts的效果,一劳永逸,于是一番查找:

cap

km上搜了一下,发现公司有个内部开源项目 -- cap,看介绍非常强大,基于底层hook技术随便抓包改包,看样子应该可以实现篡改DNS的需求。但是笔者只是想实现改hosts的效果,cap显得有点重,作为备选方案吧。

VpnService

后面发现android提供了vpn服务框架,基础类是VpnService,免root,能够全局拦截网络请求、修改网络包。

能够拦截,还能够修改,嗯,很好!

逮着VpnService如何修改网络请求,一番google,发现有人已经实现了笔者需要的效果而且开源了,项目 Virtual-Hosts

好吧,有人实现了,而且代码写的挺不错,就用它了。接下来分析一下这个项目。

Virtual-Hosts 分析

简单来说分两步:1、VpnService拦截DNS请求。2、构造DNS回包并写回VpnService。

1、拦截DNS请求

使用VpnService拦截DNS请求很容易实现,对VpnService简单配置,然后startService就可以了。以IPV4为例,配置如下:

    //vpn地址,可以随意设置
    private static final String VPN_ADDRESS = "192.0.2.111";
    //DNS地址,填个正常的dns地址即可
    private static final String VPN_DNS4 = "8.8.8.8";
    ...
    Builder builder = new Builder();
    builder.addAddress(VPN_ADDRESS, 32);
    //设置DNS服务器
    builder.addDnsServer(VPN_DNS4);
    //所有到VPN_DNS4的请求都走这个vpn。
    //配合builder.addDnsServer(VPN_DNS4),就实现了所有DNS请求都走vpn,因此能够拦截到所有DNS请求。
    builder.addRoute(VPN_DNS4, 32);

2、构造DNS回包并返回

接下来处理拦截到的包。

    FileChannel vpnInput = new FileInputStream(vpnFileDescriptor).getChannel();
    ByteBuffer bufferToNetwork = ByteBufferPool.acquire();
    //取出一个拦截到的请求包
    int readBytes = vpnInput.read(bufferToNetwork);
    //解析包并构造出Packet
    Packet packet = new Packet(bufferToNetwork);
    if (packet.isUDP()) {
        deviceToNetworkUDPQueue.offer(packet);
    } else if (packet.isTCP()) {
        deviceToNetworkTCPQueue.offer(packet);
    }

这里的DNS请求走UDP,因此会走到UDPOutput:

    Packet currentPacket = inputQueue.poll();
    //handle_dns_packet里面利用开源库 dnsjava 解析DNS请求并构造回包,填入需要的A记录
    ByteBuffer packet_buffer= DnsChange.handle_dns_packet(currentPacket);
    //写入到队列,用于返回给VpnService
    this.outputQueue.offer(packet_buffer);

回包给VpnService:

    FileChannel vpnOutput = new FileOutputStream(vpnFileDescriptor).getChannel();
    ByteBuffer bufferFromNetwork = networkToDeviceQueue.poll();
    vpnOutput.write(bufferFromNetwork);

传送门:dnsjava

到这里就走通了通过拦截DNS请求实现修改hosts效果的整个过程,以上只是简单分析,感兴趣可以细读代码。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 zhuanlan_guanli@qq.com 删除。

发表于

扫描关注云+社区

个人技术分享

1 篇文章2 人订阅

我来说两句

1 条评论
登录 后参与评论

相关文章

扫描关注云+社区