安卓虚拟定位


前言

  安卓虚拟定位技术已经出现很多年了,对于现在来说并不是什么新鲜技术,但是实际上我自己并没有使用过,因为暂时没有需求。然而最近需求来了,想找个现成的工具居然要我开会员,无奈只好自己学习一下相关的知识。

无Root虚拟定位

  很多人(包括我自己)可能想当然的认为安卓上的虚拟定位必须依赖于Root权限,其实不然,在非Root的情况下也能实现一定程度上的虚拟定位,那就是借助开发者模式中的模拟位置功能。可以参考这篇文章

  开发者模式中提供了模拟位置的接口,能够自己开发一个用于模拟位置的app,只要在Manifest中声明权限"android.permission.ACCESS_MOCK_LOCATION"后,即可在开发者选项-选择模拟位置信息应用中选择这个app,具体任何模拟位置则由app中的实现决定,我暂时没有亲自试过,可以知道的是,使用这种方法能够实现百度地图的虚拟定位,但是对于其他很多主流app是无法生效的,所以其实算是比较鸡肋,因为这个功能原来就是设计给开发者使用的。

Root虚拟定位

  在有Root的情况下,理论上虚拟定位能够对所有app生效。不讨论某些大厂的极端情况,一般来说,应用获取位置信息的来源有3个:

  1. 移动网络
  2. WIFI
  3. GPS

  我们只要能够篡改这三个来源的数据就能实现虚拟定位的功能。我们需要知道的就是与这三个来源相关的所有API,并对其进行合理的篡改。参考这篇文章,我们可以知道很多相关的重要接口以及篡改思路,并且文末有个xposed插件,可以实现企业微信的虚拟定位。但是由于代码中写死了企业微信的包名,所以只能对企业微信生效,其实现在有LSPosed可以指定模块只对特定的app生效,所以已经没必要用以往的包名限定写法来写xposed插件了。这边我将其hook的对象包名改成com.tencent.mm即微信,测试后证明了该插件经久不衰,即使时隔多年也依然能对最新版本的微信生效后,我阅读了它的源码,并参考其主要hook逻辑,实现了对应的frida版本,虽然没有100%对所有的API进行hook,但是已经能够生效。

代码如下:

var 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")
    // }
    
})

文章作者: 大A
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 大A !
评论
  目录