拦截Android App中的域名解析

在App使用域名访问网络时,域名解析是网络请求的第一步,该过程有时候会出现解析慢或域名劫持的情况。

我们可以通过拦截域名解析直接返回自定义的IP或者使用HTTPDNS解析域名,如果App使用的是OKHttp,可以直接使用OKHttp的DNS接口进行拦截。

如果App访问网络的库没有提供类似OKHttp的DNS接口,我们还可以通过hook getaddrinfo和android_getaddrinfofornet来实现域名解析拦截。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "xhook/xhook.h"

using namespace std;

namespace {
    typedef int(*pfnAndroidGetAddrInfoForNet)(const char *hostname, const char *servname,
                                              const struct addrinfo *hints, unsigned netid,
                                              unsigned mark, struct addrinfo **res);
    typedef int(*pfnGetAddrInfo)(const char* __node, const char* __service,
                                 const struct addrinfo* __hints, struct addrinfo** __result);

    map g_hosts;
    recursive_mutex g_mtx;
    bool g_hooked=false;
    pfnAndroidGetAddrInfoForNet g_origAndroidGetAddrInfoForNet;
    pfnGetAddrInfo g_origGetAddrInfo;


    int fakeAndroidGetAddrInfoForNet(const char *hostname, const char *servname,
                                            const struct addrinfo *hints, unsigned netid,
                                            unsigned mark, struct addrinfo **res) {
        lock_guard guard(g_mtx);
        if (hints->ai_flags != AI_NUMERICHOST) {
            auto ip=g_hosts.find(hostname);
            if (ip!=g_hosts.end()){
                return g_origAndroidGetAddrInfoForNet(ip->second.c_str(),servname,hints,netid,mark,res);
            }
        }
        return g_origAndroidGetAddrInfoForNet(hostname,servname,hints,netid,mark,res);
    }


    int fakeGetaddrinfo(const char* __node, const char* __service, const struct addrinfo* __hints, struct addrinfo** __result){
        lock_guard guard(g_mtx);
        auto ip=g_hosts.find(__node);
        if (ip!=g_hosts.end()){
            return g_origGetAddrInfo(ip->second.c_str(),__service,__hints,__result);
        }
        return g_origGetAddrInfo(__node,__service,__hints,__result);
    }

}


extern "C" JNIEXPORT void JNICALL Java_com_xxxx_addHost(
        JNIEnv *env,jclass,jstring host,jstring name) {
    auto hostRawValue=env->GetStringUTFChars(host, nullptr);
    auto nameRawValue=env->GetStringUTFChars(name, nullptr);
    if (hostRawValue && nameRawValue){
        lock_guard guard(g_mtx);
        g_hosts[nameRawValue]=hostRawValue;
    }
}


extern "C" JNIEXPORT void JNICALL Java_com_xxxx_clearHosts(
        JNIEnv *env,jclass) {
    lock_guard guard(g_mtx);
    g_hosts.clear();
}



extern "C" JNIEXPORT jint JNICALL Java_com_xxxx_startHook(
        JNIEnv *env,jclass) {
    if (!g_hooked){
        //xhook_enable_debug(1);
        xhook_register(".*\\.so$", "getaddrinfo",  (void *)&fakeGetaddrinfo,
                reinterpret_cast(&g_origGetAddrInfo));
        xhook_register(".*\\.so$", "android_getaddrinfofornet",(void *)fakeAndroidGetAddrInfoForNet,
                reinterpret_cast(&g_origAndroidGetAddrInfoForNet));
        xhook_ignore(".*/libxxxx.so$", NULL);
        xhook_refresh(0);
        g_hooked= true;
    }
    return 0;
}

你可能感兴趣的:(拦截Android App中的域名解析)