iOS应用程序安全

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

2021-04-12  本文已影响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的方式我们又应该如何防御呢?

上一篇下一篇

猜你喜欢

热点阅读