通常意义上来说,app 可以读取 mac 地址,但仅限于用户已经阅读了隐私内容,并且隐私内容中也告知了用户,app 会运行期间采集 wlan mac 地址等信息。所以如果没等用户同意隐私政策中的内容,就开始提前读取 mac 地址,这是不合法的行为。工信部抽查中如果发现此类行为,app 会被通告整改,整改不力的将强制从应用市场下架,后果还是很严重的。
但这里忽略一个问题,如果我们的 app 本身代码没有读取 mac 地址,那如何是好?自己的代码心中有数,实在不行可以全局搜索,如果第三方库偷偷摸摸的读取 mac 地址,这问题解决起来就有点棘手了。首先我们要复现出来确实存在读取 mac 地址的行为,这里最好的办法就是直接在 android framework 和 Linux kernel 层面截获读取 mac 地址的信息。当然还可以通过安装 VirtualXposed 的方法来定位。
我这里使用 NanoPC-T4 单板搭载 Android 8.0 系统进行实验,对于有android源码来说才能这样定位问题,如果只是 app 开发者,建议参考使用VirtualXposed的方法。
一、获取 mac 地址
你要截获获取 mac 地址信息,当然先要知道哪些接口可以读取 mac 地址,可以在调用接口处加入 log 输出。
1.方法一
先拿到 WifiManager,接着获取到 WifiInfo,通过 WifiInfo 对象的 getMacAddress() 方法得到 mac 地址。
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo winfo = wifi.getConnectionInfo();
String mac = winfo.getMacAddress();
2.方法二
使用 cat 命令,或者其他方式读取 /sys/class/net/wlan0/address 节点或 /sys/class/net/eth0/address 下的 mac 地址信息。
cat /sys/class/net/wlan0/address
cat /sys/class/net/eth0/address
二、截获获取 mac 地址方法
以下代码中+号表示需要增加的代码。
1. WifiInfo getMacAddress()
对于通过 WifiInfo 对象的 getMacAddress() 方法得到 mac 地址的方法,在 framework java 类 WifiInfo 中直接写入 log,可以清楚的知道那个 app 调用了此接口。
/frameworks/base/wifi/java/android/net/wifi/WifiInfo.java
...
+ import android.util.Log;
...
public String getMacAddress() {
+ Log.d(TAG, "getMacAddress mac=" + mMacAddress, new RuntimeException("lhw"));
return mMacAddress;
}
这会直接打印出调用堆栈的。比如下面是系统进程在调用(system_process) getMacAddress 方法。
2020-12-08 10:56:13.166 490-810/system_process D/WifiInfo: getMacAddress mac=d4:12:43:86:69:88
java.lang.RuntimeException: lhw
at android.net.wifi.WifiInfo.getMacAddress(WifiInfo.java:478)
at com.android.server.wifi.WifiStateMachine.syncRequestConnectionInfo(WifiStateMachine.java:1781)
at com.android.server.wifi.WifiServiceImpl.getConnectionInfo(WifiServiceImpl.java:1752)
at android.net.wifi.IWifiManager$Stub.onTransact(IWifiManager.java:320)
at android.os.Binder.execTransact(Binder.java:697)
2. cat 节点
这要花一些功夫,要到 Linux 内核中找到供读取节点实现的方法。最后可以查到要在 net-sysfs.c 中相应修改。
kernel/net/core/net-sysfs.c
/* use same locking rules as GIFHWADDR ioctl's */
static ssize_t address_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
ssize_t ret = -EINVAL;
read_lock(&dev_base_lock);
if (dev_isalive(ndev))
ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len);
read_unlock(&dev_base_lock);
+ printk(KERN_ALERT "mac address_show");
return ret;
}
编译系统整体烧写一下,再来运行app查看是否存在读取 mac 地址违规的问题。下面 mac address_show 这句 log 就表示有 app 读取了获取 mac 地址的节点了。下面的 Log 是通过串口读取的。
三、总结
真实排查过程中发现,经过 360 加固后,首次运行 app 必现读取 mac 地址,当然这是违规行为了!最后更换为腾讯加固再试,问题得以解决。
另外,我们使用的第三方sdk一定要注意,比如友盟在它的开发文档中有提到如何使用才能合规,我们需要参照 sdk 的指导去使用。
最后,保护个人隐私任重而道远,需要开发者和监管部门共同努力!
参考资料:
1.https://blog.csdn.net/chaozhung_no_l/article/details/78329371
2.https://www.jianshu.com/p/84127032d15a