老样子,我们首先分析该如何获得手机的IP地址。
主要分为两种获取模式:手机流量上网,即2G/3G/4G环境下获取IP;手机使用WIFI上网时获取IP。
首先贴上博主的代码:
public static String getIPAddress(Context context) {
NetworkInfo info = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info != null && info.isConnected()) {
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
try {
for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
} else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ipAddress=Formatter.formatIpAddress(wifiInfo.getIpAddress());
return ipAddress;
}
} else {
//未连接网络,提示用户
Toast.makeText(context,"无网络",Toast.LENGTH_SHORT).show();
}
return null;
}
我们先看使用流量上网获取IP的代码,关键代码为:
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
try {
for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
}
抛去多余的代码,直奔最关键的部位,我们发现在流量环境下是调用了InetAddress类的getHostAddress()方法获取了IP地址,所以我们需要Hook的目标类是InetAddress,目标方法为getHostAddress()。
流量模式下具体实现代码为:
XposedHelpers.findAndHookMethod(InetAddress.class, getHostAddress, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//拦截到后执行的逻辑
param.setResult("testing");
}
});
是不是觉得很简单,完全没有什么难点可言,只要找到目标类目标方法,进行针对拦截即可!
下面我们开始具体探索一下在WIFI模式下,该如何修改IP地址:
首先贴上WIFI模式下获取IP的关键代码:
else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址
return ipAddress;
}
/**
* 将得到的int类型的IP转换为String类型
*
* @param ip
* @return
*/
public static String intIP2StringIP(int ip) {
return (ip & 0xFF) + "." +
((ip >> 8) & 0xFF) + "." +
((ip >> 16) & 0xFF) + "." +
(ip >> 24 & 0xFF);
}
我们可以看到,首先程序获取了一个WifiManager的实例,然后调用WifiManager类的getConnectionInfo()方法获取到WifiInfo类的实例,之后调用WifiInfo类的getIpAddress()方法获取一个整形的IP,之后是一个自定义的转化格式函数,目的是把整形的IP转化成String类型。你也可以使用Formatter.formatIpAddress(wifiInfo.getIpAddress())来解析IP,这里不做具体的讲述。
通过以上的分析,我们可以看出,其中关键的代码为:wifiInfo.getIpAddress().
我们可以去看一下getIpAddress()方法的源码:
public int getIpAddress() {
int result = 0;
if (mIpAddress instanceof Inet4Address) {
result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
}
return result;
}
从源码中我们看出,返回类型是一个整型,具体调用了NetworkUtils类的inetAddressToInt()方法。
那么问题来了,我们该怎么去拦截修改WIFI模式下的IP地址呢?
很明显的是,我们需要Hook住的目标类是WifiInfo类,目标方法是getIpAddress()方法,最主要的难点是拦截到该方法后,如何返回我们自己的结果?毕竟需要返回的是一个32位的整型IP地址,用户是一点都看不懂,包括博主本人也不是很懂,所以我们不能指望用户输入一个32位的整型IP去修改掉IP,只能让他们输入新的IP地址去修改。
解决办法:拦截到方法之后,进行IP格式转换,把新的IP地址(String型)转成一个整型IP,然后返回这个整型IP即可!
下面我们就具体的去尝试一下:
首先是Hook方法,具体的代码为:
XposedHelpers.findAndHookMethod(android.net.wifi.WifiInfo.class, methodName, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//原先的整型IP
XposedBridge.log("整形IP:"+param.getResult());
//这里进行字符串分割,博主这里测试的新IP地址为“192.99.28.10”
String []str ="192.99.28.10".split("\\.");
//定义一个字符串,用来储存反转后的IP地址
String ipAdress="";
//for循环控制IP地址反转
for (int i=3;i>=0;i--){
ipAdress=ipAdress+str[i]+".";
}
//去掉最后一位的“.”
ipAdress=ipAdress.substring(0,ipAdress.length()-1);
//返回新的整型Ip地址
param.setResult((int)ipToLong(ipAdress));
}
});
具体的转化方法ipToLong()方法,代码如下:
public static long ipToLong(String strIp){
long[] ip = new long[4];
//先找到IP地址字符串中.的位置
int position1 = strIp.indexOf(".");
int position2 = strIp.indexOf(".", position1 + 1);
int position3 = strIp.indexOf(".", position2 + 1);
//将每个.之间的字符串转换成整型
ip[0] = Long.parseLong(strIp.substring(0, position1));
ip[1] = Long.parseLong(strIp.substring(position1+1, position2));
ip[2] = Long.parseLong(strIp.substring(position2+1, position3));
ip[3] = Long.parseLong(strIp.substring(position3+1));
return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
}
好了,相信你最大疑问就是IP地址(String)反转的问题了。
反转的意思是:把IP地址颠倒一下,例如博主这里测试的IP地址为“192.99.28.10”,反转变成“10.28.99.192”,然后把反转后的IP地址解析成整型IP。比较遗憾的是,我并不能告诉你为什么要这么做,因为我真的不知道为什么。。。。。。o(TヘTo)
博主一开始解析的都是正常顺序的IP地址,结果发现解析成整型总是错误的,后来搜了搜资料,意识到可能和顺序有关,于是测试了反转后的IP地址,发现解析结果才是正确的!
猜测:估计是解析算法中对域的解析顺序有关。如果你知道为什么要反转,请评论告知我,大家相互学习,非常感谢!
好了,这样我们完成了返回我们修改后的I整型IP,当然别的程序解析的时候,也就变成了我们设置的新IP地址!
以上两种模式下获取IP地址,我们都可以在自己的业务中进行拦截修改,怎么做就看你的了。
本文到此结束,如果引用本文请标明出处!