安卓逆向环境检测--frida

一、遍历运行的进程,对比进程名是否为fridaserver(只需改server名即可绕过)

二、通过遍历端口来检查frida server 10000~65535


UNEXPORT void AntiFrida::check_Server() {
    Thread::create_thread_func(check_Server_Thread, nullptr);
}

/**
 * 当前函数执行较耗时,需要放入子线程进行
 * @return  检查到frida痕迹,返回true,否则返回false
 */
UNEXPORT bool AntiFrida::check_Server_func() {
    LOGI("in AntiFrida::check_Server_func");
    int sock;
    struct sockaddr_in sa;
    bzero(&sa,sizeof(sa));
    sa.sin_family = AF_INET;
    inet_aton("127.0.0.1", &(sa.sin_addr));
    if( inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr) < 0){    //set ip address
        LOGE(" %s - %d  error:%s", __FILE__, __LINE__, strerror(errno));
        return false;
    }

    char res[7];
    for (int i = 10000; i <= 65535; i++) {
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1){
            LOGI("test socket fail:%s", strerror(errno));
        }
        sa.sin_port = htons(i);
        LOGI("check_Server_func test connect port:%d", i);
        if ( connect(sock, (struct sockaddr *) &sa, sizeof(sa)) >= 0) {
            LOGI("check_Server_func connect 127.0.0.1:%d", i);
            memset(res, 0, 7);
            send(sock, "\x00", 1, 0);
            send(sock, "AUTH\r\n", 6, 0);
            usleep(10);    // Give it some time to answer
            if ((recv(sock, res, 6, MSG_DONTWAIT)) != -1) {
                if (strcmp(res, "REJECT") == 0) {
                    close(sock);
                    LOGI("check_Server find frida for port:%d", i);
                    return true;
                }
            }
        }
        close(sock);
    }
    return false;
}


/**
 * 此函数必须作为线程函数被调用
 * @param param
 * @return
 */
UNEXPORT void* AntiFrida::check_Server_Thread(void* param) {
    check_Server_func();
    return nullptr;
}

三、maps检测,注入frida后,在/proc/self/maps 中会出现libgadget.so ,或frida-agent-32.so,frida-agent.so等模块


UNEXPORT bool AntiFrida::find_mem_string(size_t start, size_t end, char *bytes, unsigned int len) {
    char *pmem = (char *) start;
    int matched = 0;
    while ((unsigned long) pmem < (end - len)) {
        if (*pmem == bytes[0]) {
            matched = 1;
            char *p = pmem + 1;
            while (*p == bytes[matched] && (unsigned long) p < end) {
                matched++;
                p++;
            }
            if (matched >= len) {
                LOGI("find keyword LIBFRIDA");
                return true;
            }
        }
        pmem++;
    }
    return false;
}

UNEXPORT bool AntiFrida::scan_executable_segments(char *map) {
    //LOGI("scan_executable_segments do:%s", map);
    char buf[512];
    size_t start, end;
    sscanf(map, "%lx-%lx %s", &start, &end, buf);
    if (Str::strstr(map, (char*)"libgadget") != NULL){
        LOGI("find libgadget");
        return true;
    }
    if (buf[2] == 'x' && buf[0] == 'r') { //可执行 还必须可读,不然会无法访问该地址
        if (strstr(map, ".so") != NULL || strstr(map, "frida") != NULL){
            return (find_mem_string(start, end, keyword, 8) == 1); // 查找LIBFRIDA子串
        }
        return false;
    } else {
        return false;
    }
}

UNEXPORT char* AntiFrida::keyword = (char*)"LIBFRIDA";

UNEXPORT bool AntiFrida::read_line_scan(string str){
    char* split = (char*)"\n";
    string strs = str + split; // 在字符串末尾也加入分隔符,方便截取最后一段
    size_t pos = strs.find(split);
    while (pos != strs.npos)
    {
        string temp = strs.substr(0, pos);
        //LOGI("read_line_scan maps -> %s", temp.c_str());
        if (scan_executable_segments(const_cast<char *>(temp.c_str()))){
            return true;
        }
        //去掉已分割的字符串,在剩下的字符串中进行分割
        strs = strs.substr(pos + 1, strs.size());
        pos = strs.find(split);
    }
    return false;
}


UNEXPORT bool AntiFrida::check_maps() {
    Thread::lock_mutex();
    Env::thread_share_switch_maps = true;
    Thread::unLock_mutex();
    string str = Syscall::readFile((char*)"/proc/self/maps"); // 读取maps查找子串LIBFRIDA
    Thread::lock_mutex();
    Env::thread_share_switch_maps = false;
    Thread::unLock_mutex();
    if (str != "null"){
        return read_line_scan(str);
    }
    return false;
}

四、fd检测


UNEXPORT bool AntiFrida::check_fd() {
    DIR *dir = NULL;
    struct dirent *entry;
    char link_name[100];
    char buf[100];
    bool ret = false;
    if ((dir = opendir("/proc/self/fd/")) == NULL) {
        LOGE(" %s - %d  error:%s", __FILE__, __LINE__, strerror(errno));
    } else {
        entry = readdir(dir);
        while (entry) {
            switch (entry->d_type) {
                case DT_LNK:
                    sprintf(link_name, "%s/%s", "/proc/self/fd/", entry->d_name);
                    readlink(link_name, buf, sizeof(buf));
                    if (strstr(buf, "frida") || strstr(buf, "gum-js-loop") || strstr(buf, "gmain") ||
                        strstr(buf, "-gadget") || strstr(buf, "linjector")) {
                        LOGI("check_fd -> find frida:%s", buf);
                        ret = true;
                    }
                    break;
                default:
                    break;
            }
            entry = readdir(dir);
        }
    }
    closedir(dir);
    return ret;
}

五、status(线程名)检测


UNEXPORT bool AntiFrida::check_status() {
    DIR *dir = NULL;
    struct dirent *entry;
    char status_path[128];
    if ((dir = opendir("/proc/self/task/")) == NULL) {
        LOGE(" %s - %d  error:%s", __FILE__, __LINE__, strerror(errno));
    } else {
        entry = readdir(dir);
        while (entry) {
            switch (entry->d_type) {
                case DT_DIR:
                    if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                        break;
                    }
                    sprintf(status_path, "%s/%s/status", "/proc/self/task", entry->d_name);
                    string status = Syscall::readFile(status_path); // 读取 /proc/self/task/tid/status 文件
                    if (status == "null"){
                        break;
                    }
                    size_t pos = status.find("\n");
                    while (pos != status.npos)
                    {
                        string temp = status.substr(0, pos);
                        if (Str::strstr(const_cast<char *>(temp.c_str()), (char*)"Name:") != nullptr){
                            if (Str::strstr(const_cast<char *>(temp.c_str()), (char*)"gmain") != nullptr ||
                                    Str::strstr(const_cast<char *>(temp.c_str()), (char*)"gum-js-loop") != nullptr ||
                                    Str::strstr(const_cast<char *>(temp.c_str()), (char*)"pool-frida") != nullptr ||
                                    Str::strstr(const_cast<char *>(temp.c_str()), (char*)"gdbus") != nullptr){
                                LOGI("check_status -> find frida thread:%s", temp.c_str());
                                // TODO 发现frida
                                //Crash::crash_no_return();
                                //Crash::crash_kill(getpid(), SIGKILL); //进程被杀后会重启,然后frida会断开
                                return true;
                            }
                            break;
                        }
                        //去掉已分割的字符串,在剩下的字符串中进行分割
                        status = status.substr(pos + 1, status.size());
                        pos = status.find("\n");
                    }
                    break;
            }
            entry = readdir(dir);
        }
    }
    closedir(dir);
    return false;
}

六、inlinehook检测

// frida注入过程中,会在对libart的PrettyMethod函数进行hook,该函数头的代码会发生改变
// 只提取了安卓10的code


UNEXPORT bool AntiFrida::check_inlinehook(){
    bool find = false;
#ifdef __arm__
    string st_PrettyMethod = get_method_code("/apex/com.android.runtime/lib/libart.so", "ArtMethod12PrettyMethod");
#elif defined(__aarch64__)
    string st_PrettyMethod = get_method_code("/apex/com.android.runtime/lib64/libart.so", "ArtMethod12PrettyMethod");
    if (strstr(st_PrettyMethod.c_str(), "50 00 00 58 00 02 1F D6 00 9E 23 ED 78 00 00 00") != NULL){
        LOGI("check inlinehook find frida patchcode PrettyMethod -> %s", st_PrettyMethod.c_str());
        find = true;
    }else{
        LOGI("check inlinehook cant find frida patchcode PrettyMethod -> %s", st_PrettyMethod.c_str());
    }
#else
#error "Arch unknown, please port me"
#endif

    return find;
}

UNEXPORT string AntiFrida::get_method_code(const char* lib, const char* method){
    string st;

    void* handle = LoadLibrary::fake_dlopen(lib, RTLD_NOW);
    if (handle == nullptr){
        LOGE("dlopen failed -> %s", strerror(errno));
        return st;
    }
    void* op = (void*)LoadLibrary::fake_dlsym(handle, method);
    if (op == nullptr){
        LOGE("dlsym failed -> %s", strerror(errno));
        LoadLibrary::fake_dlclose(handle);
        return st;
    }

    long pageSize = sysconf(_SC_PAGESIZE);
    void* start = (void*)((long)op & -pageSize);
    if (mprotect(start, pageSize * 2, PROT_READ | PROT_WRITE | PROT_EXEC) == 0){
        LOGI("mprotect success");
    }else{
        LOGE("mprotect failed -> %s", strerror(errno));
    }
    char tmp[128] = {0};
    sprintf(tmp, "%s %s -> %p\n", lib, method, op);
    LOGI("tmp = %s ", tmp);
    //st.append(tmp);
    unsigned char*code = (unsigned char*)op;
    for (int i = 0; i < 16; i++){
        if (code[i] < 0x10){
            sprintf(tmp, "0%X ",code[i]);
        }else{
            sprintf(tmp, "%X ",code[i]);
        }
        st.append(tmp);
    }
    LOGI("get_method_code -> %s", st.c_str());
    LoadLibrary::fake_dlclose(handle);
    return st;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值