android手机免root修改hosts

6,718 阅读3分钟

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显得有点重,作为备选方案吧。

V**Service

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

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

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

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

Virtual-Hosts 分析

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

1、拦截DNS请求

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

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

2、构造DNS回包并返回

接下来处理拦截到的包。

    FileChannel V**Input = new FileInputStream(V**FileDescriptor).getChannel();
    ByteBuffer bufferToNetwork = ByteBufferPool.acquire();
    //取出一个拦截到的请求包
    int readBytes = V**Input.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);
    //写入到队列,用于返回给V**Service
    this.outputQueue.offer(packet_buffer);

回包给V**Service:

    FileChannel V**Output = new FileOutputStream(V**FileDescriptor).getChannel();
    ByteBuffer bufferFromNetwork = networkToDeviceQueue.poll();
    V**Output.write(bufferFromNetwork);

转自:cloud.tencent.com/developer/a…