美文网首页
Android逆向 检测对抗

Android逆向 检测对抗

作者: LiuJP | 来源:发表于2020-05-12 18:28 被阅读0次

    推荐文章:https://bbs.pediy.com/thread-255212.htm

    包名检测

    • 对策就是搜索包名

    检测/proc/mypid/maps

    char line[512];
    FILE* fp;
    fp = fopen("/proc/self/maps", "r");
    if (fp) {
        while (fgets(line, 512, fp)) {
            if (strstr(line, "frida")) {
                /* Evil library is loaded. Do something… */
            }
        }
        fclose(fp);
        } else {
           /* Error opening /proc/self/maps. If this happens, something is off. */
        }
    }
    

    每当一个进程创建的时候,/proc目录下就会有和该进程id对应的目录产生.
    目录名称就是进程id.里面记录该进程的各种信息.其中maps记录了进程的内存信息

    //检测xposed substrate
    public static int checkMap() throws Throwable {
            UnsupportedEncodingException unsupportedEncodingException;
            BufferedReader bufferedReader;
            Throwable th;
            int i = 0;
            BufferedReader bufferedReader2;
            int i2;
            int result = 0;
            try {
                HashSet hashSet = new HashSet();
                bufferedReader2 = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/" + android.os.Process.myPid() + "/maps"), "utf-8"));
                while (true) {
                    try {
                        String readLine = bufferedReader2.readLine();
                        if (readLine == null) {
                            break;
                        } else if (readLine.endsWith(".so") || readLine.endsWith(".jar")) {
                            hashSet.add(readLine.substring(readLine.lastIndexOf(" ") + 1));
                        }
                    } catch (UnsupportedEncodingException e) {
                        unsupportedEncodingException = e;
                        i2 = 0;
                        bufferedReader = bufferedReader2;
                        try {
                            unsupportedEncodingException.printStackTrace();
                            if (bufferedReader != null) {
                            }
                        } catch (Throwable th2) {
                            th = th2;
                            bufferedReader2 = bufferedReader;
                            if (bufferedReader2 != null) {
                            }
                            throw th;
                        }
                    }
                }
     
                Iterator it = hashSet.iterator();
                while (it.hasNext()) {
                    int i3;
                    Object next = it.next();
                    if (((String) next).toLowerCase().contains("xposed")) {
                        result = result | 64;
                    }
     
                    if (((String) next).toLowerCase().contains("com.saurik.substrate")) {
                        result = result | 128;
                    }
     
                }
     
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
    • 对策
    
    int copy_file(char *src_path, char *dst_path) {
        if (src_path && dst_path) {
            int in, out;
            ssize_t size; // TLS变量,减少堆栈占用
    //        static __thread char buffer[512]; // 内置函数(nested function),用于函数返回时关闭in,out文件句柄
            in = old_open(src_path, O_RDONLY, 0, 0, 0);
            if (-1 == in) {
                return do_return(-1, in, out);
            }
     //S_IRUSR(S_IREAD)  文件拥有者具备读权限 
    //S_IWUSR(S_IWRITE) 文件拥有者具备写权限 
    //S_IRGRP   用户组具备读权限 
    //S_IWGRP   用户组具备写权限 
    //S_IXGRP
            
    // 用户组具备可执行权限 
    //S_IROTH   其他用户具备读权限 
    // 创建目标文件,并指定合适的权限
            const __mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
    //        out = old_open(dst_path, mode,0,0,0);
            out = creat(dst_path, mode);
            if (-1 == out) {
                return do_return(-1, in, out);
            }
            while (1) {
                std::string line;
                char buf;
                while ((size = read(in, &buf, 1) > 0)) {
                    if (buf == '\n') {
                        line.push_back(buf);
                        LogD("%s line.length=%d line=%s",__FUNCTION__,line.length(),line.c_str());
                        break;
                    }
                    line.push_back(buf);
                }
                if (size <= 0) {
                    break;
                }
    
                line = replace_all(line,"com.iplay.assistant","");
                if (line.find("app_gameassist/builtin/") == -1) {
                    LogD("%s line.length=%d line=%s",__FUNCTION__,line.length(),line.c_str());
                    if (-1 == write(out, line.c_str(), line.length())) {
                        return do_return(-1, in, out);
                    }
                }
                line.clear();
            }
            { // 如果目标文件权限与所要求的权限不同则修改文件权限
                struct stat s_buf;
                stat(dst_path, &s_buf);
                if (mode != (s_buf.st_mode & mode)) {
                    if (-1 == chmod(dst_path, mode)) {
                        return do_return(-1, in, out);
                    }
                }
            }
            return do_return(0, in, out);
        }
        return -1;
    }
    
    int (*old_open)(char *path, int mode, char *a3, char *a4, char *a5)=NULL;
    
    int alt_open(char *path, int mode, char *a3, char *a4, char *a5) {
        LogD("%s path%s", __FUNCTION__, path);
        if(old_strstr(path,"com.iplay.assistant")){
            return NULL;
        }
        if (strstr(path, "/maps") && strstr(path, "/proc/")) {
            char myPath[512];
            sprintf(myPath, "/%s/%d/%s", "proc", getpid(), "maps");
            if (strstr(path, myPath) == NULL || strstr(path, "/proc/self/maps")) {
                char *relPath = "sdcard/DCIM/maps";
                copy_file(path, relPath);
                int ret = old_open(relPath, mode, a3, a4, a5);
                LogD("%s ret=%d %s -> %s", __FUNCTION__, ret, path, relPath);
                return ret;
            } else {
                return -1;
            }
        }
        return open(path, mode, a3, a4, a5);
    }
    
    char* (*old_strstr)(char* a1,char* a2) = NULL;
    
    char* my_strstr(char* a1,char* a2) {
        if(old_strstr(a2,"com.iplay.assistant")||old_strstr(a2,"center")){
            LogD("%s a1=%s a2=%s", __FUNCTION__, a1,a2);
            return NULL;
        }
        char* ret = old_strstr(a1,a2);
        return ret;
    }
    int (*old_strncmp)(char* a1,char* a2,int length,int a4,int a5,int a6) = NULL;
    
    int alt_strncmp(char* a1,char* a2,int length,int a4,int a5,int a6) {
        if(strstr(a2,"racerPid")){
            sleep(1000000);
        }
        if(strstr(a2,"iplay.assistant")||old_strstr(a2,"center")){
            LogD("%s a1=%s a2=%s", __FUNCTION__, a1,a2);
            char* dummy = "GameFuck: third party call";
            return old_strncmp(a1,dummy,length,a4,a5,a6);
        }
        int ret = old_strncmp(a1,a2,length,a4,a5,a6);
        return ret;
    }
    
    void setMemoryArt(int myfind){
        if(myfind) {
            size_t pagesize = sysconf(_SC_PAGESIZE);
            //  Calculate start and end addresses for the write.
            uintptr_t start = (uintptr_t) myfind ;
            uintptr_t end = start + 1024;
            //  Calculate start of page for mprotect.
            uintptr_t pagestart = start & -pagesize;
            int memorySize = end - pagestart;
            mprotect((void *) pagestart, end - pagestart,PROT_WRITE | PROT_READ  | PROT_EXEC);
    
        }
    
    }
    void gotTableHook(void *got_addr,void *replace, void **result){
        setMemoryArt((int)(got_addr));
        *result = *(void **)got_addr;
        *(void **)got_addr = replace;
    }
    
    
     inlineHookAddress((void *) open, (void *) alt_open, (void **) &old_open);
    || inlineHookAddress(dlsym(handle,"open"), (void *) alt_open, (void **) &old_open);
    || inlineHookAddress((void*)(info->base+0x1B0C + 1), (void *) alt_fopen, (void **) &old_fopen);
    
    || gotTableHook((void *)(info->base + 0x1F0CD4), (void*)alt_strncmp, (void**)&old_strncmp);
    || gotTableHook((void*)strstr,(void*)my_strstr,(void**)&old_strstr);
    || gotTableHook((void *)(info->base + 0x1F0D28), (void*)alt_open, (void**)&old_open);
    
    

    检测堆栈信息

    public static int checkStackTraceElement() {
        int i = 0;
        try {
            throw new Exception("detect hook");
        } catch (Exception e) {
            int i2 = 0;
            for (StackTraceElement stackTraceElement : e.getStackTrace()) {
                if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals("main")) {
                    i2 |= 4;
                }
                if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals("handleHookedMethod")) {
                    i2 |= 8;
                }
                if (stackTraceElement.getClassName().equals("com.saurik.substrate.MS$2") && stackTraceElement.getMethodName().equals("invoked")) {
                    i2 |= 16;
                }
                if (stackTraceElement.getClassName().equals("com.android.internal.os.ZygoteInit")) {
                    i++;
                    if (i == 2) {
                        i2 |= 32;
                    }
                }
            }
            return i2;
        }
    }
    

    模拟器检测

    public static String getVMDesc()
    {
        StringBuilder stringBuilder = new StringBuilder();
        String VM = AdbShell.getprop("ro.genymotion.version");//判断genymotion模拟器
        if (VM != null) {
            stringBuilder.append("ro.genymotion.version");
            stringBuilder.append("|");
            stringBuilder.append(VM);
            stringBuilder.append("\n");
        }
        VM = AdbShell.getprop("androVM.vbox_dpi");//判断使用了vbox的模拟器,目前很多市面上的安卓模拟器都是基于vbox的
        if (VM != null) {
            stringBuilder.append("androVM.vbox_dpi");
            stringBuilder.append("|");
            stringBuilder.append(VM);
            stringBuilder.append("\n");
        }
        VM = AdbShell.getprop("qemu.sf.fake_camera");//检测安卓自身的模拟器
        if (VM != null) {
            stringBuilder.append("qemu.sf.fake_camera");
            stringBuilder.append("|");
            stringBuilder.append(VM);
        }
        return stringBuilder.toString();
    }
    

    模拟器都具有一些特殊的属性.查找这个特殊的属性就可以判断是否是模拟器.
    其中AdbShell.getprop 等效于 Systemproperties.get(name).

    Debug检测

    //检测是否拥有调试属性
       public static String HaveDebugProp()
       {
           //ro.debuggable表示调试权限,默认为0,1表示可以调试
           StringBuilder builder = new StringBuilder();
           builder.append("ro.debuggable");
           builder.append(AdbShell.getprop("ro.debuggable"));
           return builder.toString();
     
       }
     
       //如果进程被调试TracerPid不为0
       public static String getTracerPid()
       {
           BufferedReader bufferedReader;
           String readLine = "";
           try {
               bufferedReader = new BufferedReader(new FileReader("/proc/self/status"));
               do{
                   readLine = bufferedReader.readLine();
                   if (readLine == null) {
                       break;
                   }
     
               }while (!readLine.startsWith("TracerPid:"));
               readLine = readLine.substring(10).trim();
     
           } catch (Exception e) {
               e.printStackTrace();
           }
           return readLine;
       }
    

    Root 检测

    private static final String[] suFiles = new String[]{"/su", "/su/bin/su", "/sbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/data/local/su", "/system/xbin/su", "/system/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/system/bin/cufsdosck", "/system/xbin/cufsdosck", "/system/bin/cufsmgr", "/system/xbin/cufsmgr", "/system/bin/cufaevdd", "/system/xbin/cufaevdd", "/system/bin/conbb", "/system/xbin/conbb"};
     
        public static boolean haveSu()
        {
            boolean z = false;
            boolean z2 = false;
            for (String file : suFiles) {
                if (new File(file).exists()) {
                    z = true;
                    break;
                }
            }
     
     
            if (Build.TAGS == null || !Build.TAGS.contains("test-keys")) {
                z2 = false;
            } else {
                z2 = true;
            }
            return z2 || z;
        }
     
        public static String RootCheckProp()
        {
            //ro.secure表示root权限,如果为0则表示启用root权限,1则相反
            //这个只能检测ROM被刷入时的默认属性.
            StringBuilder builder = new StringBuilder();
            builder.append("ro.secure:");
            builder.append(AdbShell.getprop("ro.secure"));
            builder.append("\n");
            builder.append("ro.adb.secure:");
            builder.append(AdbShell.getprop("ro.adb.secure"));
            builder.append("\n");
            return builder.toString();
        }
    

    DexFile文件检测

    根据ClassLoad检测加载了那些Dex文件

    //查询所有加载的dex,jar,apk文件,看一下是否有其他异己的模块加载
    public static void allDex()
    {
        Object pathList = getDeclaredFieldValue(DexFileCheck.class.getClassLoader(),"pathList");
        Object [] dexElements = (Object [])getDeclaredFieldValue(pathList,"dexElements");
        for(Object dex:dexElements)
        {
            DexFile dexFile = (DexFile)getDeclaredFieldValue(dex,"dexFile");
            if(dexFile == null)continue;
            Log.d(TAG, "allDex: found dexfile "+ dexFile.getName());
        }
    }
    

    转载自:https://bbs.pediy.com/thread-250871.htm

    相关文章

      网友评论

          本文标题:Android逆向 检测对抗

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