美文网首页
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