在App使用域名访问网络时,域名解析是网络请求的第一步,该过程有时候会出现解析慢或域名劫持的情况。
我们可以通过拦截域名解析直接返回自定义的IP或者使用HTTPDNS解析域名,如果App使用的是OKHttp,可以直接使用OKHttp的DNS接口进行拦截。
如果App访问网络的库没有提供类似OKHttp的DNS接口,我们还可以通过hook getaddrinfo和android_getaddrinfofornet来实现域名解析拦截。
#include <jni.h>
#include <string>
#include <time.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <map>
#include <malloc.h>
#include <mutex>
#include <string.h>
#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<string,string> 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<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> guard(g_mtx);
g_hosts[nameRawValue]=hostRawValue;
}
}
extern "C" JNIEXPORT void JNICALL Java_com_xxxx_clearHosts(
JNIEnv *env,jclass) {
lock_guard<recursive_mutex> 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<void **>(&g_origGetAddrInfo));
xhook_register(".*\\.so$", "android_getaddrinfofornet",(void *)fakeAndroidGetAddrInfoForNet,
reinterpret_cast<void **>(&g_origAndroidGetAddrInfoForNet));
xhook_ignore(".*/libxxxx.so$", NULL);
xhook_refresh(0);
g_hooked= true;
}
return 0;
}
网友评论