最近业务接入了xxxSDK进来,他需要了2个比较特殊的权限
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
因为这2个权限可以控制Wi-Fi的开关和关闭 代码如下
WifiManager wifi = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(false);
出去xxx考虑,我肯定不想给xx人发现我们带了xxxSDK会执行这个操作,但是为了提高xxx,只能允许他这样做,但是为了xxx,我必须要控制下他这个行为
因为Wi-Fi打开了,是没办法判断数据是否打开,所以需要通过setWifiEnabled把Wi-Fi关闭了,才能读取当前Wi-Fi情况把,或者考虑是什么情况下,具体我就假装不知道,但是我手机上没有sim卡,他还执行关闭Wi-Fi这操作,是非常影响我测试的,
所以找了下资料,我需要对他进行hook判断,限制他的行为,就有如下代码:
/**
* Copyright (C), 2018-2020
* Author: ziqimo
* Date: 2020/7/18 8:00 AM
* Description:
* History:
* <author> <time> <version> <desc>
* 作者姓名 修改时间 版本号 描述
*/
public class WifiHook {
private static Class iWifiManager;
private static Field serviceField;
private volatile static boolean isHook;
public static void hook(Context context) {
try {
if (isHook) {
return;
}
iWifiManager = Class.forName("android.net.wifi.IWifiManager");
serviceField = WifiManager.class.getDeclaredField("mService");
serviceField.setAccessible(true);
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Object realIwm = serviceField.get(wifi);
serviceField.set(wifi, Proxy.newProxyInstance(iWifiManager.getClassLoader(),
new Class[]{iWifiManager},
new IWMInvocationHandler(context, realIwm)));
LogUtils.e("AAA", "hook success");
isHook = true;
wifi.setWifiEnabled(false);
} catch (Exception e) {
e.printStackTrace();
}
}
private static class IWMInvocationHandler implements InvocationHandler {
private Object real;
private Context context;
public IWMInvocationHandler(Context context, Object real) {
this.context = context;
this.real = real;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtils.e("AAA", "method invoke " + method.getName() + ",args:" + Arrays.toString(args));
if ("setWifiEnabled".equals(method.getName())) {
try {
String networkOperator = SystemUtils.getNetworkOperator(context);
String networkOperatorName = SystemUtils.getNetworkOperatorName(context);
String simCountryIso = SystemUtils.getSimCountryIso(context);
String simOperator = SystemUtils.getSimOperator(context);
String simOperatorName = SystemUtils.getSimOperatorName(context);
String networkType = SystemUtils.getNetworkType(context);
} catch (Exception e) {
e.printStackTrace();
}
}
return method.invoke(real, args);
}
}
}
在执行setWifiEnabled,我可以判断下sim的状态,是否有sim卡,若没sim的卡(7.0)如下的log行为:
hook success
method invoke setWifiEnabled,args:[false]
getNetworkOperator:
getNetworkOperatorName:
getSimCountryIso:
getSimOperator:
getSimOperatorName:
getNetworkType:0
在有sim卡(8.0)的状态下:
E/AAA: hook success
E/AAA: method invoke setWifiEnabled,args:[com.xxx, false]
I/xxxxxxxx: CCC----getNetworkOperator:46001
I/xxxxxxxx: CCC----getNetworkOperatorName:CHN-UNICOM
I/xxxxxxxx: CCC----getSimCountryIso:cn
I/xxxxxxxx: CCC----getSimOperator:46006
I/xxxxxxxx: CCC----getSimOperatorName:
I/xxxxxxxx: CCC----getNetworkType:13
试了2个不同版本发现入参有区别的,所以我们需要去适配不同版本的手机
查了下看,在8.0以上增加了当前包名的这个入参,在低版本以下没有这个问题,所以我们可以安心的去hook,再判断有sim卡的情况下,才允许给xxxSDK进去hook,我们通过
StackTraceElement stack[] = Thread.currentThread().getStackTrace();
获取调用栈信息,根据xxxSDK的包名进去拦截,实际情况在说把
最终判断
if ("setWifiEnabled".equals(method.getName())) {
try {
boolean arg = true;
String networkOperator = SystemUtils.getNetworkOperator(context);
String simCountryIso = SystemUtils.getSimCountryIso(context);
String simOperator = SystemUtils.getSimOperator(context);
if (StringUtils.isEmpty(simCountryIso) ||
StringUtils.isEmpty(networkOperator) ||
StringUtils.isEmpty(simOperator)) {
arg = true;
} else {
//如果这3个地方有值才允许,不管true或者false
arg = (boolean) args[args.length - 1];
}
args[args.length - 1] = arg;
return method.invoke(real, args);
} catch (Exception e) {
e.printStackTrace();
}
}
最后:
判断手机是否有sim的代码,其实没必要危险权限来判断的,我使用的代码如下:
public static String getSimCountryIso(Context context) {
String sn = "";
try {
sn = getTelephonyManager(context).getSimCountryIso();
} catch (Exception e) {
LogUtils.e("getSimCountryIso", e);
}
LogUtils.ii("getSimCountryIso:" + sn);
return sn;
}
public static String getNetworkOperatorName(Context context) {
String sn = "";
try {
sn = getTelephonyManager(context).getNetworkOperatorName();
} catch (Exception e) {
LogUtils.e("getNetworkOperatorName", e);
}
LogUtils.ii("getNetworkOperatorName:" + sn);
return sn;
}
/**
* https://blog.csdn.net/android_ls/article/details/8672442
* @param context
* @return
*/
public static String getNetworkOperator(Context context) {
String sn = "";
try {
sn = getTelephonyManager(context).getNetworkOperator();
} catch (Exception e) {
LogUtils.e("getNetworkOperator", e);
}
LogUtils.ii("getNetworkOperator:" + sn);
return sn;
}
public static String getSimOperator(Context context) {
String sn = "";
try {
sn = getTelephonyManager(context).getSimOperator();
} catch (Exception e) {
LogUtils.e("getSimOperator", e);
}
LogUtils.ii("getSimOperator:" + sn);
return sn;
}
public static String getSimOperatorName(Context context) {
String sn = "";
try {
sn = getTelephonyManager(context).getSimOperatorName();
} catch (Exception e) {
LogUtils.e("getSimOperatorName", e);
}
LogUtils.ii("getSimOperatorName:" + sn);
return sn;
}
public static String getNetworkType(Context context) {
int sn = 0;
try {
sn = getTelephonyManager(context).getNetworkType();
} catch (Exception e) {
LogUtils.e("getNetworkType", e);
}
LogUtils.ii("getNetworkType:" + sn);
return sn + "";
}
参考的博客: blog.csdn.net/lotty_wh/ar…