iOS 模拟定位钉钉打卡

对象:钉钉等LBS应用

公司设定打卡范围,100米,500米,1公里都可以,但是基于有模拟定位这个技术,钉钉在打卡选项里加了一项WiFi打卡,定位打卡和WiFi打开可以叠加存在以保证有人打卡作弊(后面讲解破解WiFi)。

一台Mac (安装了Xcode)
一台iPhone(越狱不越狱无所谓)
一根数据线。
坐标系统

这里普及一下坐标系统:
目前我们经常接触的无非就是原始坐标,火星坐标,二次加密坐标。
原始坐标:手机上获取到的是原始的GPS坐标 —— WGS-84。
火星坐标:我大天朝自己加了飘逸搞的一套加密坐标,中国国测局(和GFW一样的傻屌组织)—— GCJ-02:谷歌、高德。
百度加密坐标:在火星坐标的基础上再次飘逸后的加密坐标 —— BD-09:百度。
在遥远的东方,有一个天朝。
天朝有一个测绘局,发明了一种把美国卫星的GPS的地球坐标,进行偏移的算法,计算后,得出了一个火星坐标。
为了让火星坐标能正确的显示,又给每部导航软件加入了这个算法,可以在大家的地图上还原位置。并且给每部导航收费。美其名国家安全。而且这个算法看上去很牛B的样子,还不可逆。
所以,只有这个国家的人都在用错误的坐标。正宗的掩耳盗铃。
民用卫星精度都已经让你出身冷汗了,何况军用卫星。打仗估值也不会用中国的电子地图吧。
只可惜各种LBS应用,都是个麻烦事哦。
还好黄天不负有心人,终于经过大家的模拟,计算,基本还原了飘逸算法
选技师
坐标获取入口:
高德
百度
首先,根据各自的喜好,选好你想要模拟的位置,这里以高德地图为例:

可以看到右边有显示坐标(信息港坐标) :

113.373059,23.125725

过程开始

  • iOS原生坐标为: 世界标准地理坐标(WGS-84)
  • 百度地图的坐标为:BD-09
  • 高德以及国内坐标为:中国国测局地理坐标(GCJ-02)

iPhone所需要的坐标是WGS-84,我们获取的是GCJ-02,这里我们利用最新飘逸还原算法来转换出你所需要的真实坐标。转变的代码如下:

要导入 CoreLocation/CoreLocation.h

这个是.h

/**
     *  @brief  世界标准地理坐标(WGS-84) 转换成 中国国测局地理坐标(GCJ-02)<火星坐标>
     *
     *  ####只在中国大陆的范围的坐标有效,以外直接返回世界标准坐标
     *
     *  @param  location    世界标准地理坐标(WGS-84)
     *
     *  @return 中国国测局地理坐标(GCJ-02)<火星坐标>
     */
+ (CLLocationCoordinate2D)wgs84ToGcj02:(CLLocationCoordinate2D)location;
    
    
    /**
     *  @brief  中国国测局地理坐标(GCJ-02) 转换成 世界标准地理坐标(WGS-84)
     *
     *  ####此接口有1-2米左右的误差,需要精确定位情景慎用
     *
     *  @param  location    中国国测局地理坐标(GCJ-02)
     *
     *  @return 世界标准地理坐标(WGS-84)
     */
+ (CLLocationCoordinate2D)gcj02ToWgs84:(CLLocationCoordinate2D)location;
    
    
    /**
     *  @brief  世界标准地理坐标(WGS-84) 转换成 百度地理坐标(BD-09)
     *
     *  @param  location    世界标准地理坐标(WGS-84)
     *
     *  @return 百度地理坐标(BD-09)
     */
+ (CLLocationCoordinate2D)wgs84ToBd09:(CLLocationCoordinate2D)location;
    
    
    /**
     *  @brief  中国国测局地理坐标(GCJ-02)<火星坐标> 转换成 百度地理坐标(BD-09)
     *
     *  @param  location    中国国测局地理坐标(GCJ-02)<火星坐标>
     *
     *  @return 百度地理坐标(BD-09)
     */
+ (CLLocationCoordinate2D)gcj02ToBd09:(CLLocationCoordinate2D)location;
    
    
    /**
     *  @brief  百度地理坐标(BD-09) 转换成 中国国测局地理坐标(GCJ-02)<火星坐标>
     *
     *  @param  location    百度地理坐标(BD-09)
     *
     *  @return 中国国测局地理坐标(GCJ-02)<火星坐标>
     */
+ (CLLocationCoordinate2D)bd09ToGcj02:(CLLocationCoordinate2D)location;
    
    
    /**
     *  @brief  百度地理坐标(BD-09) 转换成 世界标准地理坐标(WGS-84)
     *
     *  ####此接口有1-2米左右的误差,需要精确定位情景慎用
     *
     *  @param  location    百度地理坐标(BD-09)
     *
     *  @return 世界标准地理坐标(WGS-84)
     */
+ (CLLocationCoordinate2D)bd09ToWgs84:(CLLocationCoordinate2D)location;

.m 为:

#define LAT_OFFSET_0(x,y) -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x))
#define LAT_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0
#define LAT_OFFSET_2 (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0
#define LAT_OFFSET_3 (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0
    
#define LON_OFFSET_0(x,y) 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x))
#define LON_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0
#define LON_OFFSET_2 (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0
#define LON_OFFSET_3 (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0
    
#define RANGE_LON_MAX 137.8347
#define RANGE_LON_MIN 72.004
#define RANGE_LAT_MAX 55.8271
#define RANGE_LAT_MIN 0.8293
    // jzA = 6378245.0, 1/f = 298.3
    // b = a * (1 - f)
    // ee = (a^2 - b^2) / a^2;
#define jzA 6378245.0
#define jzEE 0.00669342162296594323
    
        
    
+ (double)transformLat:(double)x bdLon:(double)y
{
    double ret = LAT_OFFSET_0(x, y);
    ret += LAT_OFFSET_1;
    ret += LAT_OFFSET_2;
    ret += LAT_OFFSET_3;
    return ret;
}

+ (double)transformLon:(double)x bdLon:(double)y
{
    double ret = LON_OFFSET_0(x, y);
    ret += LON_OFFSET_1;
    ret += LON_OFFSET_2;
    ret += LON_OFFSET_3;
    return ret;
}

+ (BOOL)outOfChina:(double)lat bdLon:(double)lon
{
    if (lon < RANGE_LON_MIN || lon > RANGE_LON_MAX)
    return true;
    if (lat < RANGE_LAT_MIN || lat > RANGE_LAT_MAX)
    return true;
    return false;
}

+ (CLLocationCoordinate2D)gcj02Encrypt:(double)ggLat bdLon:(double)ggLon
{
    CLLocationCoordinate2D resPoint;
    double mgLat;
    double mgLon;
    if ([self outOfChina:ggLat bdLon:ggLon]) {
        resPoint.latitude = ggLat;
        resPoint.longitude = ggLon;
        return resPoint;
    }
    double dLat = [self transformLat:(ggLon - 105.0)bdLon:(ggLat - 35.0)];
    double dLon = [self transformLon:(ggLon - 105.0) bdLon:(ggLat - 35.0)];
    double radLat = ggLat / 180.0 * M_PI;
    double magic = sin(radLat);
    magic = 1 - jzEE * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((jzA * (1 - jzEE)) / (magic * sqrtMagic) * M_PI);
    dLon = (dLon * 180.0) / (jzA / sqrtMagic * cos(radLat) * M_PI);
    mgLat = ggLat + dLat;
    mgLon = ggLon + dLon;
    
    resPoint.latitude = mgLat;
    resPoint.longitude = mgLon;
    return resPoint;
}

+ (CLLocationCoordinate2D)gcj02Decrypt:(double)gjLat gjLon:(double)gjLon {
CLLocationCoordinate2D  gPt = [self gcj02Encrypt:gjLat bdLon:gjLon];
double dLon = gPt.longitude - gjLon;
double dLat = gPt.latitude - gjLat;
CLLocationCoordinate2D pt;
pt.latitude = gjLat - dLat;
pt.longitude = gjLon - dLon;
return pt;
}

+ (CLLocationCoordinate2D)bd09Decrypt:(double)bdLat bdLon:(double)bdLon
{
    CLLocationCoordinate2D gcjPt;
    double x = bdLon - 0.0065, y = bdLat - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * M_PI);
    double theta = atan2(y, x) - 0.000003 * cos(x * M_PI);
    gcjPt.longitude = z * cos(theta);
    gcjPt.latitude = z * sin(theta);
    return gcjPt;
}

+(CLLocationCoordinate2D)bd09Encrypt:(double)ggLat bdLon:(double)ggLon
{
    CLLocationCoordinate2D bdPt;
    double x = ggLon, y = ggLat;
    double z = sqrt(x * x + y * y) + 0.00002 * sin(y * M_PI);
    double theta = atan2(y, x) + 0.000003 * cos(x * M_PI);
    bdPt.longitude = z * cos(theta) + 0.0065;
    bdPt.latitude = z * sin(theta) + 0.006;
    return bdPt;
}


+ (CLLocationCoordinate2D)wgs84ToGcj02:(CLLocationCoordinate2D)location
{
    return [self gcj02Encrypt:location.latitude bdLon:location.longitude];
}

+ (CLLocationCoordinate2D)gcj02ToWgs84:(CLLocationCoordinate2D)location
{
    return [self gcj02Decrypt:location.latitude gjLon:location.longitude];
}


+ (CLLocationCoordinate2D)wgs84ToBd09:(CLLocationCoordinate2D)location
{
CLLocationCoordinate2D gcj02Pt = [self gcj02Encrypt:location.latitude
                                              bdLon:location.longitude];
return [self bd09Encrypt:gcj02Pt.latitude bdLon:gcj02Pt.longitude] ;
}

+ (CLLocationCoordinate2D)gcj02ToBd09:(CLLocationCoordinate2D)location
{
return  [self bd09Encrypt:location.latitude bdLon:location.longitude];
}

+ (CLLocationCoordinate2D)bd09ToGcj02:(CLLocationCoordinate2D)location
{
return [self bd09Decrypt:location.latitude bdLon:location.longitude];
}

+ (CLLocationCoordinate2D)bd09ToWgs84:(CLLocationCoordinate2D)location
{
 CLLocationCoordinate2D gcj02 = [self bd09ToGcj02:location];
 return [self gcj02Decrypt:gcj02.latitude gjLon:gcj02.longitude];
}

 

 

这里我们需要新建一个xml文件(内容如下),包含坐标用于模拟定位。导入新建的项目中。

<?xml version="1.0" encoding="UTF-8" ?>
<gpx version="1.1"
    creator="GMapToGPX 6.4j - http://www.elsewhere.org/GMapToGPX/"
    xmlns="http://www.topografix.com/GPX/1/1"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
    <wpt lat="30.593234492328744" lon="104.06263069384391">
    </wpt>
</gpx>

根据不同位置不同把转换得到的原始坐标对应到latlon里面即可。(记得开定位)

4、真机运行新建的项目, 上面导入的 XML 文件 名字随便叫我的 “start” ,真机运行了之后,需要做下面这步

这个时候千万别点Stop,直接Home键后台,再打开带定位的应用看看你当前的位置。
还原定位的方法,直接Stop即可。

辣么,用WI-FI的我也说说:

  • 破解钉钉WiFi打卡:把家里的WiFi名称改得和公司打卡的WiFi即可。据我测试,我们公司只配置校验了SSID,没有校验DHCP地址。
  • 随时随地打卡:按照上面的步骤模拟定位完成之后,不要Stop,直接拔掉数据线(可能是Xcode开发者模式开了个进程来模拟定位,如果Xcode上没有Stop,那这个进程就不会Kill掉)。
  • WiFi破解弊端:公司如果启动了DHCP校验,那就只能搞到地址在家里打卡,不然没用。
  • 随地打卡弊端:恢复方法只能重启手机才能还原定位,经测试,微信里地图无法使用,一片空白,所以这里阔以用不用的旧的测试机来专注打卡,我就只能帮你到这里了。
    还没弄明白的找我拿压缩包我打包好了。

     

 

 

 

文 / Aex
LEAVE A REPLY
loading