更新
项目地址
概述
前文通过分析Android 9
源码,定位到Hook点,然后使用Xposed Hook
,实现了Wifi热点IP的固定。
系统升级到Android 11
后,发现源码有变化,插件不起作用了。于是再来操作一波。
Hook点
安卓10
android.net.ip.IpServer
的getRandomWifiIPv4Address
函数。
1 | private String getRandomWifiIPv4Address() |
安卓11
android.net.ip.IpServer
的requestIpv4Address
函数。
1 | private LinkAddress requestIpv4Address(s) { |
由于该函数还被用于其他方式的网络共享及更换前缀,所以需要判断网络类型(mInterfaceType == TETHERING_WIFI
)和调用者(遍历堆栈查找configureIPv4
),最后进行替换。
安卓10
源码分析
通过前文可知,设置热点IP的流程如下:
在configureIPv4
函数中,首先调用getRandomWifiIPv4Address
生成字符串形式的IP,然后转换为LinkAddress
,最后调用ifcg.setLinkAddress
设置IP地址。(其中ifcg
类型为InterfaceConfiguration
)
在源码中搜索setLinkAddress
,可以发现有以下几处引用
其中/frameworks/base/services/net/java/android/net/ip/IpServer.java
调用者为configureIPv4
函数(官方文档:IP 服务重构路径)
查看源码IpServer.java#404,发现并无太大变化(增加了configureDhcp
,已更新 DHCP 服务器),仍使用getRandomWifiIPv4Address
生成随机IP地址:
1 | InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString); |
查找getRandomWifiIPv4Address
的交叉引用,发现还是只有这一处。因此,修改Hook类名为android.net.ip.IpServer
即可适配安卓10
Hook点
android.net.ip.IpServer
的getRandomWifiIPv4Address
函数,返回固定字符串即可。
1 | private String getRandomWifiIPv4Address() |
安卓11
源码分析
搜索setLinkAddress
,仍然只有几处引用
相比于安卓10,IpServer.java
和WifiP2pServiceImpl.java
的引用消失了,变成了NetdWrapper.java
的fromStableParcel
和setInterfaceLinkAddress
函数(官方文档:模块边界)
查找fromStableParcel
的交叉引用,发现NetdWrapper.java
和NetworkManagementService.java
的getInterfaceConfig
函数有调用。
查看源码,发现只有一行代码区别
1 | NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); |
两者都是调用mNetdService.interfaceGetCfg(iface)
获取配置。
查找setInterfaceLinkAddress
的交叉引用,发现并没有函数调用它
于是搜索configureIPv4
,发现只有一处引用,仍位于android.net.ip.IpServer
类中
(由/frameworks/base/services/net/java/android/net/ip/IpServer.java
移动到了/frameworks/base/packages/Tethering/src/android/net/ip/IpServer.java
)
分析该函数(源代码IpServer.java#596),发现有:
1 | if (enabled) { |
而mIpv4Address
是在configureIPv4
函数开头设置的:
1 | if (enabled) { |
查看requestIpv4Address
函数:
1 | private LinkAddress requestIpv4Address() { |
首先判断是否设置了静态IP,如果mStaticIpv4ServerAddr
不为空则直接使用(由maybeConfigureStaticIp
设置)。
然后判断是否为蓝牙,是则使用BLUETOOTH_IFACE_ADDR
(192.168.44.1/24
)。
其他情况调用mPrivateAddressCoordinator.requestDownstreamAddress(this)
后者位于frameworks/base/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
1 | public LinkAddress requestDownstreamAddress(final IpServer ipServer) { |
调用getRandomSubAddr
生成子网地址,然后判断是否存在与上下游冲突。
查找requestIpv4Address
交叉引用,发现还会被handleNewPrefixRequest
调用,向上追溯找到onNewPrefixRequest
(DHCP服务器通知前缀改变时触发)
1 | // request from DHCP server that it wants to have a new prefix |
Hook点
android.net.ip.IpServer
的requestIpv4Address
函数。
1 | private LinkAddress requestIpv4Address() |
由于该函数还被用于其他方式的网络共享及更换前缀,所以需要判断网络类型(mInterfaceType == TETHERING_WIFI
)和调用者(遍历堆栈查找configureIPv4
),最后进行替换。
PS:测试发现Android 11
设置IP的包名不再是android
,而是com.android.networkstack.tethering.inprocess
Hook代码
见GitHub:MainHook.java
参考
How can I permanently assign a static IP address to Wi-Fi clients? (Lineage OS 17.1 Android 10)