用cemu hookk模拟位置后在其他位置还能地位吗

Android之基于Xposed的模拟位置模块实现 - 简书
Android之基于Xposed的模拟位置模块实现
前段时间看到朋友圈有人在短时间内发了几条状态,定位都在不同国家的首都。问了一下,才知道用了一款能够模拟位置的软件。最近学习Xposed框架,就试着利用Xposed框架开发了一款能够模拟安卓手机位置的应用模块。
测试机:Android 4.4
Xposed框架
AndroidStudio
1.Android手机定位原理
手机常用的定位方式有:
卫星定位(GPS,北斗,伽利略,Glonass)
移动基站定位
WiFi辅助定位
* 卫星定位
GPS(Global Positioning System)即全球定位系统,是由美国建立的一个卫星导航定位系统,利用该系统,用户可以在全球范围内实现全天候、连续、实时的三维导航定位和测速;另外,利用该系统,用户还能够进行高精度的时间传递和高精度的精密定位。
* 基站定位
移动电话测量不同基站的下行导频信号,得到不同基站下行导频的TOA(到达时刻)或 TDOA(到达时间差),根据该测量结果并结合基站的坐标,一般采用三角公式估计算法,就能够计算出移动电话的位置。实际的位置估计算法需要考虑多基站(3个或3个以上)定位的情况,因此算法要复杂很多。一般而言,移动台测量的基站数目越多,测量精度越高,定位性能改善越明显。
* WiFi定位
每一个无线AP(路由器)都有一个全球唯一的MAC地址,并且一般来说无线AP在一段时间内不会移动;
设备在开启Wi-Fi的情况下,无线路由器默认都会进行SSID广播(除非用户手动配置关闭该功能),在广播帧包含了该路由器的MAC地址;
采集装置可以通过接收周围AP发送的广播信息获取周围AP的MAC信息和信号强度信息,将这些信息上传到服务器,经过服务器的计算,保存为“MAC-经纬度”的映射,当采集的信息足够多时候就在服务器上建立了一张巨大的WiFi信息网络;
当一个设备处在这样的网络中时,可以将收集到的这些能够标示AP的数据发送到位置服务器,服务器检索出每一个AP的地理位置,并结合每个信号的强弱程度,计算出设备的地理位置并返回到用户设备,其计算方式和基站定位位置计算方式相似,也是利用三点定位或多点定位技术;
位置服务商要不断更新、补充自己的数据库,以保证数据的准确性。当某些WiFi信息不在数据库中时,可以根据附近其他的WiFi位置信息推断出未知WiFi的位置信息,并上传服务器。
* AGPS定位
AGPS(AssistedGPS:辅助全球卫星定位系统)是结合GSM/GPRS与传统卫星定位,利用基地台代送辅助卫星信息,以缩减GPS芯片获取卫星信号的延迟时间,受遮盖的室内也能借基地台讯号弥补,减轻GPS芯片对卫星的依赖度。AGPS利用手机基站的信号,辅以连接远程定位服务器的方式下载卫星星历 (英语:Almanac Data),再配合传统的GPS卫星接受器,让定位的速度更快。是一种结合网络基站信息和GPS信息对移动台进行定位的技术,既利用全球卫星定位系统GPS,又利用移动基站,解决了GPS覆盖的问题,可以在2代的G、C网络和3G网络中使用。
1.伪装定位思路
在了解到上述手机定位原理后,结合平时对手机的使用我们可以得知手机定位最常用的几种方式分别是:
Xposed的便利之处就是提供方法使得我们可以改变系统函数和应用中的函数执行前和执行后的结果。所以设想是否可以利用XPosed框架提供的功能编写一个Hook模块,勾取系统调用中和定位相关的函数并篡改返回值呢?
2.相关函数
经过查阅资料和阅读安卓源码,粗略找到以下几个类和相关的方法和定位有关,并对其进行Hook操作。下面是我进行Hook的类及其中的方法名:
android.telephony.TelephonyManager
getCellLocation
getPhoneCount
getNeighboringCellInfo
getAllCellInfo
android.telephony.PhoneStateListener
onCellLocationChanged
onCellInfoChanged
android.net.wifi.WifiManager
getScanResults
getWifiState
isWifiEnabled
android.net.wifi.WifiInfo
getMacAddress
android.net.NetworkInfo
getTypeName
isConnectedOrConnecting
isConnected
isAvailable
android.telephony.CellInfo
isRegistered
LocationManager.class
getLastLocation
getLastKnownLocation
getProviders
getBestProvider
addGpsStatusListener
addNmeaListener
android.location.LocationManager
getGpsStatus
由于上述方法太多,这里只解释基本的思想。这些方法的作用及参数和返回值都能在Android开发手册中找到,逐条hook并修改返回值即可。我们要做的其实就是利用Hook手段,让手机认为gps是目前最好的位置提供器,并修改其返回值为我们想要的位置,从而达到伪装位置的目的。但是为什么上面列出如此众多的方法需要我们Hook呢?这是因为手机中的定位是一连串比较复杂的过程,是一套各参数匹配的过程。任何一个相关函数的返回值和最终我们填入的结果不吻合,都可能导致伪装定位的失败。所以我们要做的就是找到并Hook定位流程相关的方法并拦截修改返回值。附上:
4.效果截图
选择伪装地点
上图是我将核心Hook模块实现后利用百度地图做了一个简单的欺骗位置小软件。
伪装微信定位
5.核心Hook模块代码
package com.example.administrator.
import android.location.C
import android.location.GpsS
import android.location.L
import android.location.LocationL
import android.location.LocationM
import android.os.B
import android.os.SystemC
import android.telephony.CellIdentityC
import android.telephony.CellIdentityG
import android.telephony.CellIdentityL
import android.telephony.CellIdentityW
import android.telephony.CellInfoC
import android.telephony.CellInfoG
import android.telephony.CellInfoL
import android.telephony.CellInfoW
import android.telephony.CellL
import android.telephony.gsm.GsmCellL
import java.lang.reflect.M
import java.lang.reflect.M
import java.util.ArrayL
import java.util.L
import de.robv.android.xposed.XC_MethodH
import de.robv.android.xposed.XposedB
import de.robv.android.xposed.XposedH
* Created by CaptainXero on
public class HookUtils {
public static void HookAndChange(ClassLoader classLoader, final double latitude, final double longtitude, final int lac, final int cid) {
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
"getCellLocation", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
GsmCellLocation gsmCellLocation = new GsmCellLocation();
gsmCellLocation.setLacAndCid(lac, cid);
param.setResult(gsmCellLocation);
XposedHelpers.findAndHookMethod("android.telephony.PhoneStateListener", classLoader,
"onCellLocationChanged", CellLocation.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
GsmCellLocation gsmCellLocation = new GsmCellLocation();
gsmCellLocation.setLacAndCid(lac, cid);
param.setResult(gsmCellLocation);
if (Build.VERSION.SDK_INT & Build.VERSION_CODES.LOLLIPOP_MR1) {
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
"getPhoneCount", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(1);
if (Build.VERSION.SDK_INT & Build.VERSION_CODES.M) {
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
"getNeighboringCellInfo", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(new ArrayList&&());
if (Build.VERSION.SDK_INT & Build.VERSION_CODES.JELLY_BEAN) {
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
"getAllCellInfo", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(getCell(460, 0, lac, cid, 0, 0));
XposedHelpers.findAndHookMethod("android.telephony.PhoneStateListener", classLoader,
"onCellInfoChanged", List.class, new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(getCell(460, 0, lac, cid, 0,0));
XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "getScanResults", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(new ArrayList&&());
XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "getWifiState", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(1);
XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "isWifiEnabled", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(true);
XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getMacAddress", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("00-00-00-00-00-00-00-00");
XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getSSID", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("null");
XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getBSSID", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("00-00-00-00-00-00-00-00");
XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
"getTypeName", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("WIFI");
XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
"isConnectedOrConnecting", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(true);
XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
"isConnected", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(true);
XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
"isAvailable", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(true);
XposedHelpers.findAndHookMethod("android.telephony.CellInfo", classLoader,
"isRegistered", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(true);
XposedHelpers.findAndHookMethod(LocationManager.class, "getLastLocation", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Location l = new Location(LocationManager.GPS_PROVIDER);
l.setLatitude(latitude);
l.setLongitude(longtitude);
l.setAccuracy(100f);
l.setTime(System.currentTimeMillis());
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.JELLY_BEAN_MR1) {
l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
param.setResult(l);
XposedHelpers.findAndHookMethod(LocationManager.class, "getLastKnownLocation", String.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Location l = new Location(LocationManager.GPS_PROVIDER);
l.setLatitude(latitude);
l.setLongitude(longtitude);
l.setAccuracy(100f);
l.setTime(System.currentTimeMillis());
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.JELLY_BEAN_MR1) {
l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
param.setResult(l);
XposedBridge.hookAllMethods(LocationManager.class, "getProviders", new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ArrayList&String& arrayList = new ArrayList&&();
arrayList.add("gps");
param.setResult(arrayList);
XposedHelpers.findAndHookMethod(LocationManager.class, "getBestProvider", Criteria.class, Boolean.TYPE, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("gps");
XposedHelpers.findAndHookMethod(LocationManager.class, "addGpsStatusListener", GpsStatus.Listener.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (param.args[0] != null) {
XposedHelpers.callMethod(param.args[0], "onGpsStatusChanged", 1);
XposedHelpers.callMethod(param.args[0], "onGpsStatusChanged", 3);
XposedHelpers.findAndHookMethod(LocationManager.class, "addNmeaListener", GpsStatus.NmeaListener.class, new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(false);
XposedHelpers.findAndHookMethod("android.location.LocationManager", classLoader,
"getGpsStatus", GpsStatus.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
GpsStatus gss = (GpsStatus) param.getResult();
if (gss == null)
Class&?& clazz = GpsStatus.
Method m =
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals("setStatus")) {
if (method.getParameterTypes().length & 1) {
if (m == null)
//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] =
param.setResult(gss);
m.invoke(gss, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);
param.setResult(gss);
} catch (Exception e) {
XposedBridge.log(e);
for (Method method : LocationManager.class.getDeclaredMethods()) {
if (method.getName().equals("requestLocationUpdates")
&& !Modifier.isAbstract(method.getModifiers())
&& Modifier.isPublic(method.getModifiers())) {
XposedBridge.hookMethod(method, new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (param.args.length &= 4 && (param.args[3] instanceof LocationListener)) {
LocationListener ll = (LocationListener) param.args[3];
Class&?& clazz = LocationListener.
Method m =
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals("onLocationChanged") && !Modifier.isAbstract(method.getModifiers())) {
Location l = new Location(LocationManager.GPS_PROVIDER);
l.setLatitude(latitude);
l.setLongitude(longtitude);
l.setAccuracy(10.00f);
l.setTime(System.currentTimeMillis());
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.JELLY_BEAN_MR1) {
l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
XposedHelpers.callMethod(ll, "onLocationChanged", l);
if (m != null) {
m.invoke(ll, l);
} catch (Exception e) {
XposedBridge.log(e);
if (method.getName().equals("requestSingleUpdate ")
&& !Modifier.isAbstract(method.getModifiers())
&& Modifier.isPublic(method.getModifiers())) {
XposedBridge.hookMethod(method, new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (param.args.length &= 3 && (param.args[1] instanceof LocationListener)) {
LocationListener ll = (LocationListener) param.args[3];
Class&?& clazz = LocationListener.
Method m =
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals("onLocationChanged") && !Modifier.isAbstract(method.getModifiers())) {
if (m != null) {
Location l = new Location(LocationManager.GPS_PROVIDER);
l.setLatitude(latitude);
l.setLongitude(longtitude);
l.setAccuracy(100f);
l.setTime(System.currentTimeMillis());
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.JELLY_BEAN_MR1) {
l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
m.invoke(ll, l);
} catch (Exception e) {
XposedBridge.log(e);
private static ArrayList getCell(int mcc, int mnc, int lac, int cid, int sid, int networkType) {
ArrayList arrayList = new ArrayList();
CellInfoGsm cellInfoGsm = (CellInfoGsm) XposedHelpers.newInstance(CellInfoGsm.class);
XposedHelpers.callMethod(cellInfoGsm, "setCellIdentity", XposedHelpers.newInstance(CellIdentityGsm.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(
lac), Integer.valueOf(cid)}));
CellInfoCdma cellInfoCdma = (CellInfoCdma) XposedHelpers.newInstance(CellInfoCdma.class);
XposedHelpers.callMethod(cellInfoCdma, "setCellIdentity", XposedHelpers.newInstance(CellIdentityCdma.class, new Object[]{Integer.valueOf(lac), Integer.valueOf(sid), Integer.valueOf(cid), Integer.valueOf(0), Integer.valueOf(0)}));
CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) XposedHelpers.newInstance(CellInfoWcdma.class);
XposedHelpers.callMethod(cellInfoWcdma, "setCellIdentity", XposedHelpers.newInstance(CellIdentityWcdma.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(lac), Integer.valueOf(cid), Integer.valueOf(300)}));
CellInfoLte cellInfoLte = (CellInfoLte) XposedHelpers.newInstance(CellInfoLte.class);
XposedHelpers.callMethod(cellInfoLte, "setCellIdentity", XposedHelpers.newInstance(CellIdentityLte.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(cid), Integer.valueOf(300), Integer.valueOf(lac)}));
if (networkType == 1 || networkType == 2) {
arrayList.add(cellInfoGsm);
} else if (networkType == 13) {
arrayList.add(cellInfoLte);
} else if (networkType == 4 || networkType == 5 || networkType == 6 || networkType == 7 || networkType == 12 || networkType == 14) {
arrayList.add(cellInfoCdma);
} else if (networkType == 3 || networkType == 8 || networkType == 9 || networkType == 10 || networkType == 15) {
arrayList.add(cellInfoWcdma);
return arrayL
我们的孤独就像天空中漂浮的城市,仿佛是一个秘密,却无从述说。你正在使用的浏览器版本过低,将不能正常浏览和使用知乎。小议安卓定位伪造-实战足不出户畅玩pokemon go
&本文旨在技术探讨故本文不提供工具,正常玩家请勿模仿,游戏中虚拟位置有封号风险
0x00 安卓定位方式归类
要伪造定位首先要摸清定位到底是如何实现的,首先从广义上来区分安卓的定位方式实际上就gps和network两种。但是network网络定位过于抽象,到底是移动网络基站定位,还是宽带ip定位还是wifi定位了,于是我又做了如下细分。
细分定位方式如下:
GPS定位:通过卫星定位,精度高耗电也高定位速度慢。但是需要搜索到三颗星以上才可以定位,室内的大多无法使用。
网络定位:多指wifi/宽带ip定位,其实也包括移动网络也就是第三点。
基站定位:通过运营商的基站三角定位,定位精度低功耗低。
混合定位:结合上面多种方式,AGPS定位。
第三方SDK: 百度地图/高德地图/谷歌地图,本质上还是使用上面4种方式。
通常位置信息权重排序 :gps & wifi & 基站 ,实际上还和信号强度,以及软件算法等多种因素有关。
功耗排序 : gps & 基站 & wifi
0x01位置欺骗可行方案
针对上述定位方式可以假想如下方案进行欺骗。
1.硬件放射gps信号欺骗。 成本较高,需要诸如hackrf这样的硬件设备。我工位在窗户边真实gps信号十分强,所以我伪造的信号就像对弱了导致整个方案成功率变低。具体操作可以参考下文。
2.android位置模拟。这种方式需要打开gps定位并且进入开发者模式开启位置模拟,这个方案较易操作。但是很多app对这种行为作了检测,例如pokemon go在检测到位置模拟后便会提示Failed to detect location
3.hook系统调用,篡改location返回值,需要root权限。这个是我最终采用到方案。这个方案的优点是比较稳定,被检测到异常的概率比较小。既可以正常人肉跑动玩游戏,也可以偷懒利用pc上的插件点击鼠标满地图抓小精灵。
07-14 12:30:40.573
/? D/pokemongoH﹕ location = -35..0560237
07-14 12:30:40.573
/? D/pokemongoH﹕ getLatitude Result : -35.
07-14 12:30:40.583
/? D/pokemongoH﹕ getLongitude Result : 149.0560237
4.模拟器提供位置模拟功能,ARM模拟器运行缓慢,x86模拟机虽然快但是兼容性差。命令行指定坐标 :
telnet localhost 5554
geo fix &longitude value& &latitude value&```
这类操作因为需要在模拟器中进行,所以体验和兼容性要差很多。
5.篡改软件上传的ip/wifi信息,实际操作难度较大。
0x02分析pokemon go APP
在android平台要玩此游戏需要 google play 框架,如果你手机是国行的肯定不会带此框架,必须root后才能安装。我所使用的nexus 5是自带的。
既然要使用google play的服务那在gfw的保护就必须得自备梯子了,我选择的是showsocks,vps在香港。
任天堂是一直不太care国服的,这次迫于服务器宕机的压力Pokemon go更是对大陆地区进行锁区操作。当你千辛万苦完成上述两个步骤后进行进入游戏会发现地图上没有任何小精灵和补给站以及道馆。所以这个时候就需要使用到本文讲解的技术定位伪造了。
先观察下网上公开的Pokemon go锁区图,从下图可以看出东三省和新疆部分地区是不在锁区范围可以正常游戏的。为什么这样,我个人猜测有这样两个原因
这个长方形的锁区范围从开发角度易于实现
游戏运营初期策略较为宽松宁放过不误杀。
为了测试Pokemon Go的定位方式,我做了如下操作。
1.设置系统使用wlan和移动网络定位会提示&GPS signal not found,当设置仅gps定位和gps/wlan/移动网络确定位置的时候可以正常游戏
2.监控 location provider
07-14 12:30:22.573
/? D/pokemongoH﹕ HOOK IT
07-14 12:30:40.553
/? D/pokemongoH﹕ location provider is : gps
07-14 12:30:40.563
/? D/pokemongoH﹕ location provider is : network
3.逆向app,在逆向过程中未发现调用getCellLocation/getBSSID方法,但是发现其有调用getLastKnownLocation。下文会描述这些方法的用处。
结论:pokemon go采用混合定位其中gps定位为主,network定位为辅且gps定位可以独立工作network定位无法独立工作。
0x03伪造gps插件开发
上文已经简单分析了安卓定位的方式以及pokemon go采用的定位方案,在hook系统api前腰先对这些api简单了解下。
需要关注的api:类以及方法如下
android.location.Location
public double getLatitude ()
//获取纬度,北纬为正数,南纬为负数。
public double getLongitude ()
//获取经度
android.location.LocationManager
public Location getLastLocation ()
public Location getLastKnownLocation (String provider)
//通过provider获取location
android.telephony.TelephonyManager
public CellLocation getCellLocation ()
//通过GSM获取location
android.net.wifi.WifiInfo
public String getBSSID ()
//获取wifi的bssid
【声明】:黑吧安全网()登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱,我们会在最短的时间内进行处理。
上一篇:【】【】

我要回帖

更多关于 天下游模拟地位无效 的文章

 

随机推荐