飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 94373|回复: 198

[iOS] 【非越狱环境】钉钉躺床上打卡之WIFI篇

  [复制链接]
  • TA的每日心情
    开心
    2023-1-18 15:50
  • 签到天数: 227 天

    [LV.7]常住居民III

    发表于 2017-2-7 16:02:32 | 显示全部楼层 |阅读模式
    本帖最后由 gengjf025 于 2017-2-8 10:01 编辑

    钉钉iOS客户端WIFI修改(非越狱环境)

    本文续自上一篇:【非越狱环境】钉钉躺床上打卡之GPS篇https://www.chinapyg.com/thread-88593-1-1.html

    一、背景
    最近有朋友公司移动考勤用的是wifi考勤,即公司设置签到的wifi热点之后,员工只有在连接上该热点后才能打考勤成功,就顺手做了点小事情。


    二、工具准备
    见上一篇。

    三、分析
    1、iOS的wifi获取用到的CNCopySupportedInterfaces()和CNCopyCurrentNetworkInfo()两个函数,组合使用获取到一个CFDictionaryRef,能够读取SSID(wifi热点名)、BSSID(路由器的Mac地址)、SSIDDATA(SSID的十六进制);
    2、很多app会获取当前网络状态,常用的是函数SCNetworkReachabilityGetFlags(),Reachability中会通过该函数判断当前网络是wifi还是其他状态;

    知道这些东西之后就可以直接对这几个系统函数动手了,一劳永逸。

    四、编码
        我们在上一篇的代码基础上增加wifi信息修改的相关代码,这里使用的是fishhook这个库,为了避免命名冲突,所有函数都加了前缀;
    1、创建一个wifi信息类DTWifiModel,头文件如下:
    [Objective-C] 纯文本查看 复制代码
    //
    //  DTWifiModel.h
    //  DingTalkDylib
    //
    //
    //
    
    #import <Foundation/Foundation.h>
    #import <SystemConfiguration/SCNetworkReachability.h>
    
    @interface DTWifiModel : NSObject
    
    // en0
    @property (nonatomic, copy) NSString *ifnam;
    
    @property (nonatomic, assign) SCNetworkReachabilityFlags flags;
    
    // WIFI昵称,例如:公司办公wifi、公司客户wifi
    @property (nonatomic, copy) NSString *nickName;
    
    // BSSID:路由器的Mac地址
    @property (nonatomic, copy) NSString *BSSID;
    
    // SSID:路由器的广播名称
    @property (nonatomic, copy) NSString *SSID;
    
    // SSIDDATA:SSID的十六进制
    @property (nonatomic, strong) NSData *SSIDDATA;
    
    @property (nonatomic, assign) BOOL isSelected;
    
    - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
    
    - (instancetype)initWith:(NSString *)ifnam dictionary:(NSDictionary *)dictionary;
    
    @end

    2、创建wifi信息展示类DTWifiSettingViewController,该类主要用于展示当前连接的wifi、已经设置过的wifi历史,便于切换:
    核心函数如下:
    (1)、获取当前wifi信息,获取到之后会额外记录当前网络状态的flags,存出以备后用:
    [Objective-C] 纯文本查看 复制代码
    - (void)fetchCurrentWifi {
        
        [_currentWifi.array removeAllObjects];
        
        CFArrayRef arrayRef = CNCopySupportedInterfaces();
        NSArray *ifs = (__bridge_transfer NSArray *)arrayRef;
        
        if(ifs && [ifs count] > 0) {
            
            NSString *ifnam = [ifs objectAtIndex:0];
            
            CFDictionaryRef info = CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
            
            NSDictionary *dictionary = (__bridge_transfer NSDictionary *)info;
            
            if (dictionary && [dictionary count]) {
                
                DTWifiModel *wifi = [[DTWifiModel alloc] initWith:ifnam dictionary:dictionary];
                
                wifi.flags = [self fetchCurrentNetworkStatus];
                
                [_currentWifi addObject:wifi];
            }
        }
    }
    
    (2)、获取当前网络状态,很多app都会先获取网络状态判断是否为wifi连接,一次获取到wifi热点信息之后再记录一次当前网络状态,用于篡改系统函数返回的flags,代码如下:
    [Objective-C] 纯文本查看 复制代码
    - (SCNetworkReachabilityFlags)fetchCurrentNetworkStatus {
        
        // 创建零地址,0.0.0.0的地址表示查询本机的网络连接状态
        struct sockaddr_in zeroAddress;//sockaddr_in是与sockaddr等价的数据结构
        bzero(&zeroAddress, sizeof(zeroAddress));
        zeroAddress.sin_len = sizeof(zeroAddress);
        zeroAddress.sin_family = AF_INET;//sin_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET,代表TCP/IP协议族
        
        SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); //创建测试连接的引用:
        SCNetworkReachabilityFlags flags;
        
        BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
        CFRelease(defaultRouteReachability);
        
        if (!didRetrieveFlags) {
            NSLog(@"Error. Could not recover network reachability flagsn");
            return 0;
        }
        
        return flags;
    }

    3、创建类DTWIFIHook,用于hook系统函数:CNCopySupportedInterfaces()、CNCopyCurrentNetworkInfo()和SCNetworkReachabilityGetFlags(),代码如下:
    [Objective-C] 纯文本查看 复制代码
    // CFArrayRef CNCopySupportedInterfaces        (void)
    static CFArrayRef (*orig_CNCopySupportedInterfaces)();
    
    static CFArrayRef jf_CNCopySupportedInterfaces() {
        
        CFArrayRef re = NULL;
        
        DTWifiModel *wifi = [DTWIFIHook wifiHooked];
        
        if(wifi && wifi.ifnam) {
            
            NSArray *array = [NSArray arrayWithObject:wifi.ifnam];
            
            re = CFRetain((__bridge CFArrayRef)(array));
        }
        
        if(!re) {
            
            re = orig_CNCopySupportedInterfaces();
        }
        
        return re;
    }

    [Objective-C] 纯文本查看 复制代码
    // CFDictionaryRef CNCopyCurrentNetworkInfo        (CFStringRef interfaceName)
    static CFDictionaryRef (*orig_CNCopyCurrentNetworkInfo)(CFStringRef interfaceName);
    
    static CFDictionaryRef jf_CNCopyCurrentNetworkInfo(CFStringRef interfaceName) {
        
        CFDictionaryRef re = NULL;
        
        DTWifiModel *wifi = [DTWIFIHook wifiHooked];
        
        if(wifi) {
            
            NSDictionary *dictionary = @{
                                         @"BSSID" : (wifi.BSSID ? wifi.BSSID : @""),
                                         @"SSID" : (wifi.SSID ? wifi.SSID : @""),
                                         @"SSIDDATA" : (wifi.SSIDDATA ? wifi.SSIDDATA : @""),
                                         };
            re = CFRetain((__bridge CFDictionaryRef)(dictionary));
        }
        
        if(!re) {
            
            re = orig_CNCopyCurrentNetworkInfo(interfaceName);
        }
        
        return re;
    }

    [Objective-C] 纯文本查看 复制代码
    // Boolean SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags)
    static Boolean (*orig_SCNetworkReachabilityGetFlags)(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags);
    
    static Boolean jf_SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags) {
        
        Boolean re = false;
        
        DTWifiModel *wifi = [DTWIFIHook wifiHooked];
        
        if(wifi && wifi.flags > 0) {
            
            re = true;
            
            *flags = wifi.flags;
        }
        
        if(!re) {
            
            re = orig_SCNetworkReachabilityGetFlags(target, flags);
        }
        
        return re;
    }

    [Objective-C] 纯文本查看 复制代码
    + (void)load {
        
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            
            _jf_rebind_symbols((struct _jf_rebinding[3]){
                {"CNCopySupportedInterfaces", jf_CNCopySupportedInterfaces, (void *)&orig_CNCopySupportedInterfaces},
                {"CNCopyCurrentNetworkInfo", jf_CNCopyCurrentNetworkInfo, (void *)&orig_CNCopyCurrentNetworkInfo},
                {"SCNetworkReachabilityGetFlags", jf_SCNetworkReachabilityGetFlags, (void *)&orig_SCNetworkReachabilityGetFlags},
            }, 3);
        });
    }

    五、注入、打包、签名
    操作步骤同上一篇,安装测试:
    11111.png
    IMG_3589.PNG
    可以看到即使使用3G网络也可以实现wifi考勤,大功告成;

    六、代码地址

    七、结束语
    谨慎使用!







    评分

    参与人数 13威望 +46 飘云币 +48 收起 理由
    qukeke112 + 2 PYG有你更精彩!
    hyh0101 + 4 老哥 有没有安卓的?
    77356614 + 4 老哥牛比了.
    rNKsT61v + 4 + 4 很给力!
    Alonc + 4 赞一个!
    zhiaizhuzhu + 4 PYG有你更精彩!
    woshizs + 4 有签名工具和证书呢,楼主给个成品!!!呜.
    论坛管理员 + 4 PYG有你更精彩!
    世态炎凉 + 4 楼主出个安卓的哇
    kuniao + 1 很给力!

    查看全部评分

    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2023-1-18 15:50
  • 签到天数: 227 天

    [LV.7]常住居民III

     楼主| 发表于 2017-2-7 16:54:00 | 显示全部楼层
    hzq999 发表于 2017-2-7 16:48
    我们单位居然用分享逍客

    不管什么app,应该都是通用的,提供的代码是hook的系统函数,与app本身无关
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2023-1-18 15:50
  • 签到天数: 227 天

    [LV.7]常住居民III

     楼主| 发表于 2017-2-18 22:05:08 | 显示全部楼层
    本帖最后由 gengjf025 于 2017-2-18 22:06 编辑
    mancong122 发表于 2017-2-18 12:33
    楼主是不是,对软件进行欺骗的方式来模拟已在制定WiFi环境下,然而软件的签到网络通讯可以是用wifi或流量都 ...

    请看代码,或者看文章中的分析,主要做了有两个工作,一个是劫持并修改获取当前网络状态的系统函数,永远返回当前网络是wifi连接状态,另一个是劫持并修改获取当前wifi信息的两个系统函数,返回指定的wifi信息(热点名、mac地址及其16进制的数据)。所以并不是hook钉钉的类或方法,直接hook的系统函数。从目前一段时间的使用情况看,钉钉应该没有其他特殊的防作弊方式。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2023-1-18 15:50
  • 签到天数: 227 天

    [LV.7]常住居民III

     楼主| 发表于 2017-2-19 17:07:15 | 显示全部楼层
    mancong122 发表于 2017-2-19 12:45
    你的文章我看到了,我的意思是:如果说签到的wifi网络属于局域网范畴,只能是在该网络下才能访问到指定的 ...

    你说的这种情况,还要移动考勤干啥?直接打指纹或者刷卡算了。
    PYG19周年生日快乐!
    回复 支持 1 反对 0

    使用道具 举报

  • TA的每日心情
    开心
    2023-1-18 15:50
  • 签到天数: 227 天

    [LV.7]常住居民III

     楼主| 发表于 2017-2-21 10:20:25 | 显示全部楼层
    不要说以后 发表于 2017-2-21 09:58
    要是有成品就更好了

    企业证书哪能随便乱用,现在Apple查的很严的,一不小心就会被封的
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2023-1-18 15:50
  • 签到天数: 227 天

    [LV.7]常住居民III

     楼主| 发表于 2017-3-28 14:37:24 | 显示全部楼层
    qientin085 发表于 2017-3-28 13:38
    我就不清楚你那个选择Wi-Fi和定位的界面在哪里打开的?

    屏幕右下角有个绿色设置按钮,如果第一次登陆之后没显示,双击home键并杀掉app,重新打开程序之应该就能看见了,再找不到请看代码,一共也没多少代码量
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表