前几天,收到公司App违规收取用户隐私的邮件,说是存在收集设备MAC地点的行为。
这就让我很方了,上次已经整改过一次违规获取用户隐私的问题了,这次又来。。
因为上次整改的时候,已将所有的第三方库移到用户同意了隐私协议后,才去初始化的,自己的代码又不会去获取这些数据,理应不会再出现获取,所以就很希奇,不知道那边出了问题。
厥后想到,既然是去获取了MAC地点,肯定要调用系统的API,那么我只要去HOOK系统的方法,就可以知道在什么时候,去获取了MAC地点了。
由于各个系统版本获取MAC地点的方式差别,所以特意拿了个Android5.1的手机举行测试。
- /** * Android 6.0 之前(不包括6.0)获取mac地点 * 必须的权限 * * @param context * @return */ private String getMacDefault(Context context) { String mac = "0"; if (context == null) { return mac; } WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo info = null; try { info = wifi.getConnectionInfo(); } catch (Exception e) { e.printStackTrace(); } if (info == null) { return null; } mac = info.getMacAddress(); return mac; }
复制代码 可以看到,我们在Android6.0以前是通过WifiManager.getConnectionInfo()的方式来获取相关数据的。
我们来看下这个方法。
- IWifiManager mService; public WifiInfo getConnectionInfo() { try { return mService.getConnectionInfo(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
复制代码 可以看到,这里调用的是IWifiManager.getConnectionInfo(),IWifiManager是一个接口
- interface IWifiManager{ WifiInfo getConnectionInfo(String callingPackage); ... }
复制代码 那么这个IWifiManager是什么时候被赋值的呢?我们回到context.getSystemService(Context.WIFI_SERVICE);
我们知道,context的实现类实在是ContextImpl.java,我们直接来看ContextImpl.getSystemService()
- @Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); }
复制代码 我们可以看到,这里调用了SystemServiceRegistry.getSystemService(this, name);
我们再来看这个类
- public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; }
复制代码
这里的SYSTEM_SERVICE_FETCHERS是一个Map iWifiManager = Class.forName("android.net.wifi.IWifiManager"); Field serviceField = WifiManager.class.getDeclaredField("mService"); serviceField.setAccessible(true); WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); // real mService Object realIwm = serviceField.get(wifi); // replace mService with Proxy.newProxyInstance serviceField.set(wifi, Proxy.newProxyInstance(iWifiManager.getClassLoader(), new Class[]{iWifiManager}, new InvocationHandler(tag, "getConnectionInfo", realIwm))); Log.i(tag, "wifiManager hook success"); } catch (Exception e) { Log.e(tag, "printStackTrace:" + e.getMessage()); e.printStackTrace(); } } public static class InvocationHandler implements java.lang.reflect.InvocationHandler { private final String tag; private final String methodName; private Object real; public InvocationHandler(String tag, String methodName, Object real) { this.real = real; this.methodName = methodName; this.tag = tag; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Log.d(tag, "method invoke " + method.getName()); if (methodName.equals(method.getName())) { if (cacheWifiInfo != null) { Log.d(tag, "cacheWifiInfo:" + cacheWifiInfo); return cacheWifiInfo; } WifiInfo wifiInfo = null; try { Class cls = WifiInfo.class; wifiInfo = (WifiInfo) cls.newInstance(); Field mMacAddressField = cls.getDeclaredField("mMacAddress"); mMacAddressField.setAccessible(true); mMacAddressField.set(wifiInfo, ""); cacheWifiInfo = wifiInfo; Log.d(tag, "wifiInfo:" + wifiInfo); } catch (Exception e) { Log.e(tag, "WifiInfo error:" + e.getMessage()); } return wifiInfo; } else { return method.invoke(real, args); } } }}[/code] 然后举行Hook
- HookUtils.hookMacAddress("Z-Application",getApplicationContext()); HookUtils.hookMacAddress("Z-Activity",MainActivity.this); HookUtils.hookMacAddress("Z-Service",MyService.this);
复制代码 最后,运行步伐,可以看到,当获取Mac地点的时候,会打印相关日志。
- method invoke getConnectionInfo
复制代码 至此,我们就Hook乐成了。
然后,我们就可以在App出现这个日志的时候,定位到是哪个功能调用了Mac地点。
我们这最终定位到是点击了隐私协议,通过腾讯X5 WebView显示H5页面的时候,调用了Mac地点。
最终,通过Hook MAC地点方法,当获取MAC地点的时候,举行全局的拦截,返回一个空的MAC地点,使其无法获取到真正的MAC地点。
参考 Hook之WifiManager
来源:https://blog.csdn.net/EthanCo/article/details/111544333
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |