首页
关于
Search
1
Android 虚拟定位
186 阅读
默认分类
登录
/
注册
Search
JiyeHoo
累计撰写
1
篇文章
累计收到
9
条评论
首页
栏目
默认分类
页面
关于
搜索到
1
篇与
的结果
2023-12-29
Android 虚拟定位
1. 前言安卓虚拟定位技术已经出现很多年了,对于现在来说并不是什么新鲜技术。前段时间的“大牛助手”因为涉及到大厂的利益被抓了,目前市面上也没有什么好的免费软件可以使用了。想着自己写一个方案用于虚拟定位。2. 背景很多人可能认为虚拟定位的方式很简单,使用开发者选项中的虚拟定位即可,实际上并没有什么用,因为 app 不会使用简单的一种方式确定你的经纬度,而且这个方式也只是给开发者使用调试的。开发者模式中提供了模拟位置的接口,能够自己开发一个用于模拟位置的app,只要在Manifest中声明权限"android.permission.ACCESS_MOCK_LOCATION"后,即可在开发者选项-选择模拟位置信息应用中选择这个app,具体任何模拟位置则由app中的实现决定。3. 方案在有Root的情况下,理论上虚拟定位能够对所有app生效。不讨论某些大厂的极端情况,一般来说,应用获取位置信息的来源有3个:移动网络WIFIGPS使用的 Hook 技术可以用:XposedFrida通过 Xposed 或者 Frida 效果其实一致,通过对系统定位相关的 api 进行 Hook,使其返回一个我们自定义的数据,或者使其失效,让需要定位的 APP 虚拟定位至我们想要的位置。首先需要对 Android 定位的方式进行了解,目前市面上的打卡/定位 APP 肯定不只是通过简单的 GPS 位置来获取用户经纬度,如 GPS 定位、WIFI 定位、基站定位、AGPS 定位,而且通常会混合同时使用那么我们就需要对 Android 哪些 api 可以进行位置确认进行分析。4. 确定 Api//基站定位相关 android.telephony.TelephonyManager getCellLocation() getAllCellInfo() android.telephony.PhoneStateListener onCellLocationChanged(cellLocation) onCellInfoChanged() //WIFI定位相关 android.net.wifi.WifiManager getScanResults() getWifiState() isWifiEnabled() getMacAddress() getSSID() getBSSID() //获取网络状态 android.net.NetworkInfo isConnectedOrConnecting() isConnected() isAvailable() //下面是关键的,要修改经纬度坐标的方法 android.location.LocationManager getLastLocation() getLastKnownLocation(string) getProviders() getBestProvider(criteria, boolean) requestLocationUpdates(...) requestSingleUpdate(...)也就是我们需要对上方这些 api 进行 Hook,修改使其失效或者返回一个我们的期望数据。5. 方案一:Xposed对于 Xposed 的方案,我之前也写过好几篇文章(只不过服务器忘记续费丢完了),所以这里就不介绍 Xposed 的使用方式了。提一下,目前在高版本上的方案,最佳的就是刷入 Magisk 之后载入 LSPosed,目前可以兼容到最新版本的 Android 14,而且可以指定生效的应用,不需要全局注入包名判断,并且可以实时生效不用重启。XposedHelpers.findAndHookMethod("android.location.LocationManager", classLoader, "getGpsStatus", GpsStatus.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { if (!isOpen) return; Log.d(TAG, "getGpsStatus"); GpsStatus gss = (GpsStatus) param.getResult(); if (gss == null) return; Class<?> clazz = GpsStatus.class; Method m = null; for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals("setStatus")) { if (method.getParameterTypes().length > 1) { m = method; break; } } } if (m == null) return; //access the private setStatus function of GpsStatus m.setAccessible(true); //make the apps belive GPS works fine now int svCount = 5; int[] prns = {1, 2, 3, 4, 5}; float[] snrs = {0, 0, 0, 0, 0}; float[] elevations = {0, 0, 0, 0, 0}; float[] azimuths = {0, 0, 0, 0, 0}; int ephemerisMask = 0x1f; int almanacMask = 0x1f; //5 satellites are fixed int usedInFixMask = 0x1f; XposedHelpers.callMethod(gss, "setStatus", svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask); param.args[0] = gss; param.setResult(gss); try { m.invoke(gss, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask); param.setResult(gss); } catch (Exception e) { XposedBridge.log(e); } } });Hook 的代码比较多且都是类似的方式,这边就贴一个 api 的 Hook 演示说明,根据上方整理的 api list 自己依次实现就能完成。6. 方案二:Fridavar Latitude = 30 var Longitude = 120 Java.perform(()=>{ var telMng = Java.use("android.telephony.TelephonyManager") var ArrayList = Java.use("java.util.ArrayList") telMng.getCellLocation.implementation = function(){ console.log("getCellLocation") return null } telMng.getNeighboringCellInfo.implementation = function(){ console.log("getNeighboringCellInfo") return null } telMng.getAllCellInfo.implementation = function(){ console.log("getAllCellInfo") return null } telMng.getPhoneCount.implementation = function(){ console.log("getPhoneCount") return 1 } var phoneStateListener = Java.use("android.telephony.PhoneStateListener") phoneStateListener.onCellLocationChanged.implementation = function(){ console.log("onCellLocationChanged") } // phoneStateListener.onCellInfoChanged.implementation = function(){ // console.log("onCellInfoChanged") // return this.onCellInfoChanged.apply(this,arguments) // } var WifiManager = Java.use("android.net.wifi.WifiManager") WifiManager.getScanResults.implementation = function(){ console.log("getScanResults") return ArrayList.$new() } WifiManager.getWifiState.implementation = function(){ console.log("getWifiState") return 1 } WifiManager.isWifiEnabled.implementation = function(){ console.log("isWifiEnabled") return true } var WifiInfo = Java.use("android.net.wifi.WifiInfo") WifiInfo.getMacAddress.implementation = function(){ console.log("getMacAddress") return "00-00-00-00-00-00-00-00" } WifiInfo.getSSID.implementation = function(){ console.log("getSSID") return null } WifiInfo.getBSSID.implementation = function(){ console.log("getBSSID") return "00-00-00-00-00-00-00-00" } var NetworkInfo = Java.use("android.net.NetworkInfo") NetworkInfo.getTypeName.implementation = function(){ console.log("getTypeName") return "WIFI" } NetworkInfo.isConnectedOrConnecting.implementation = function(){ console.log("isConnectedOrConnecting") return true } NetworkInfo.isConnected.implementation = function(){ console.log("isConnected") return true } NetworkInfo.isAvailable.implementation = function(){ console.log("isAvailable") return true } var CellInfo = Java.use("android.telephony.CellInfo") CellInfo.isRegistered.implementation = function(){ console.log("isRegistered") return true } var LocationManager = Java.use("android.location.LocationManager") var Location = Java.use("android.location.Location") LocationManager.getLastLocation.implementation = function(){ console.log("getLastLocation") var location = Location.$new(LocationManager.GPS_PROVIDER.value) location.setLatitude(Latitude) location.setLongitude(Longitude) location.setAccuracy(100) location.setTime(new Date().getTime()) return location } LocationManager.getLastKnownLocation.implementation = function(){ console.log("getLastKnownLocation") var location = Location.$new(LocationManager.GPS_PROVIDER.value) location.setLatitude(Latitude) location.setLongitude(Longitude) location.setAccuracy(100) location.setTime(new Date().getTime()) return location } LocationManager.getProviders.overload('boolean').implementation = function(){ console.log("getProviders1") var array = ArrayList.$new() array.add("gps") return array } LocationManager.getProviders.overload('android.location.Criteria', 'boolean').implementation = function(){ console.log("getProviders2") var array = ArrayList.$new() array.add("gps") return array } LocationManager.getBestProvider.implementation = function(){ console.log("getBestProvider") return "gps" } LocationManager.addGpsStatusListener.implementation = function(args){ console.log("addGpsStatusListener") var ret = this.addGpsStatusListener(args) if(args != null){ args.onGpsStatusChanged(1) args.onGpsStatusChanged(3) } return ret } LocationManager.addNmeaListener.overload('android.location.GpsStatus$NmeaListener').implementation = function(){ console.log("addNmeaListener") return false } // LocationManager.getGpsStatus.implementation = function(){ // console.log("getGpsStatus") // } })这里可能没有 hook 所有的接口,有需要的可以自己补全,上方的这些对于企业微信打卡来说已经是完全够用的了。7. 结束本文的方案是在 Root 的情况下执行,但是如果想要在无 Root 的环境下完成也是可以的。方案有非常多,比如简单的可以使用 VirtualRoot、sandBox 的方式,也可以麻烦一点 objection 重新打包(注意重启签名绕过)、临时 Root、编译系统等。另外本文所述方案只是用于学习虚拟定位的方式、学习 Hook 技术,并未提供破解定位的工具。本文仅供学习使用,如果产生任何app封锁(封号)、法律问题,使用者自负
2023年12月29日
186 阅读
5 评论
2 点赞