美文网首页iOS应用程序安全
iOS防护----越狱检测2021年版

iOS防护----越狱检测2021年版

作者: 捡书 | 来源:发表于2021-04-12 09:59 被阅读0次

    如何检测越狱手机一直是iOS应用安全防护的第一道门槛。
    早在2018年的时候就写过一篇文章来介绍越狱检测,但是由于时间久远,技术在不断地推陈出新,因此当初的代码大多已经被各种反越狱插件研究透彻,因此才有了这篇新的文章。

    首先最好使的依然是检测各个越狱常用的软件是否存在:

    static char *paths[] = {
        "/Applications/ALS.app"
        "/Applications/Cydia.app",
        "/Applications/FakeCarrier.app",
        "/Applications/Filza.app",
        "/Applications/FlyJB.app",
        "/Applications/IntelliScreen.app",
        "/Applications/MTerminal.app",
        "/Applications/SBSetttings.app",
        "/Applications/Snoop-itConfig.app"
        "/Applications/WinterBoard.app",
        "/Applications/blackra1n.app",
        "/Library/LaunchDaemons/com.openssh.sshd.plist"
        "/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
        "/Library/LaunchDaemons/com.tigisoftware.filza.helper.plist",
        "/Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist",
        "/Library/LaunchDaemons/dhpdaemon.plist",
        "/Library/LaunchDaemons/re.frida.server.plist",
        "/Library/MobileSubstrate",
        "/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",
        "/Library/MobileSubstrate/DynamicLibraries/Veency.plist",
        "/Library/MobileSubstrate/MobileSubstrate.dylib",
        "/System/Library/LaunchDaemons/com.ikey.bbot.plist",
        "/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
        "/User/Applications/",
        "/bin.sh",
        "/bin/bash",
        "/etc/apt",
        "/etc/ssh/sshd_config",
        "/private/etc/apt",
        "/private/etc/apt/preferences.d/checkra1n",
        "/private/etc/apt/preferences.d/cydia",
        "/private/etc/dpkg/origins/debian",
        "/private/etc/ssh/sshd_config",
        "/private/var/lib/apt",
        "/private/var/lib/cydia",
        "/private/var/mobileLibrary/SBSettingsThemes/",
        "/private/var/stash",
        "/private/var/tmp/cydia.log",
        "/usr/bin/cycript",
        "/usr/bin/ssh",
        "/usr/lib/libcycript.dylib",
        "/usr/libexec/cydia/",
        "/usr/libexec/sftp-server",
        "/usr/libexec/ssh-keysign",
        "/usr/local/bin/cycript",
        "/usr/sbin/frida-server",
        "/usr/sbin/sshd",
        "/var/lib/cydia",
        "/var/lib/dpkg/info"
    };
    
    BOOL checkPath() {
       
        for (int i = 0;i < sizeof(paths) / sizeof(char *);i++) {
            struct stat stat_info;
            if (0 == stat(paths[i], &stat_info)) {
                return YES;
            }
        }
        
        return NO;
    }
    

    这么做其实有问题,如果大家知道有个叫fishhook的东西,其实很容易就能hook stat函数,那么应该怎么办呢?
    我们可以用函数指针调用的方式隐藏一下:

    BOOL checkPath() {
        void * handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
        stat_ptr_t stat_ptr = dlsym(handle, "stat");
        for (int i = 0;i < sizeof(paths) / sizeof(char *);i++) {
            struct stat stat_info;
            if (0 == stat_ptr(paths[i], &stat_info)) {
                return YES;
            }
        }
        return NO;
    }
    

    但是dlopen调用的方式,想必大家也能看出如何破解,fishhook既然能hook你的stat,难道就不能hook你的dlopen和dlsym吗?
    所以我们再加大些力度,直接用汇编搞一个stat的调用:

    __attribute__((always_inline)) long f_stat(const char * s, struct stat * stat_info) {
        long ret = 0;
        __asm__ volatile(
                         "mov x0, %[s_p]\n"
                         "mov x1, %[stat_info_p]\n"
                         "mov x16, #338\n"
                         "svc #0x80\n"
                         "mov %[ret_p], x0\n"
            : [ret_p]"=r"(ret)
            : [s_p]"r"(s), [stat_info_p]"r"(stat_info)
        );
        return ret == 0 ? ret : -1;
    }
    
    BOOL checkPath() {
        for (int i = 0;i < sizeof(paths) / sizeof(char *);i++) {
            struct stat stat_info;
            if (0 == f_stat(paths[i], &stat_info)) {
                return YES;
            }
        }
        return NO;
    }
    

    其中mov x16, #338代表的是stat函数的系统调用号,完整的系统调用号可以从这里查看

    当然,我们除了stat函数,还可以使用open函数来判断:

    __attribute__((always_inline)) long f_open(const char *path) {
        long rs = 0;
        __asm__ volatile(
                         "mov x0, %[path]\n"
                         "movz x1, #0\n"
                         "movz x16, #5\n"
                         "svc #0x80\n"
                         "mov %[result], x0\n"
                         : [result]"=r"(rs)
                         : [path]"r"(path)
                         );
        
        return rs > 2 ? rs : -1;
    }
    
    BOOL checkPath() {
        for (int i = 0;i < sizeof(paths) / sizeof(char *);i++) {
            if (-1 != f_open(paths[i])) {
                return YES;
            }
        }
        return NO;
    }
    

    至于汇编代码为什么要这么写,可以看一下这篇文章,自己领悟一下。

    防护做到这里,我们其实可以成功的防御fishhook的攻击,但是目前国内的大神做了一个叫Dobby的inlinehook框架,专治各种防御,那么针对Dobby这种inlinehook的方式我们又应该如何防御呢?

    相关文章

      网友评论

        本文标题:iOS防护----越狱检测2021年版

        本文链接:https://www.haomeiwen.com/subject/wqitlltx.html