Android反模拟器的总结

0x00背景:

很多病毒都很先检测检测运行环境。如果不是沙箱环境就释放恶意代码。
我们来总结他检测了哪些模拟器的特性

0x01检测特定文件

检测一些系统特定属性,如检测当前设备手机号,设备DeviceId,dev下是否存在socket/qemud和qemu_pipe两个文件,以及build.prop下的一些属性

/**固件信息
/system/libc_malloc_debg_qem.so   //在cm,魔趣等基于aosp改版的系统上会存在libc_malloc_debug_qemu.so这个文件
/sys/qemu_trace                           
/system/bin/qemu-props                 
/dev/socket/genyd            
/dev/socket/baseband_genyd              
/dev/socket/qemud           
/dev/qemu_pipe                 
**/

我这里的代码列出来几个

    private static String[] known_pipes={
            "/dev/socket/qemud",
            "/dev/qemu_pipe"
    };
     /**
     *  检测“/dev/socket/qemud”,“/dev/qemu_pipe”这两个通道
     *读取文件内容,然后检查已知QEmu的驱动程序的列表
     * @param context The context of the application package.
     * @return launcher activity name of this application. From the
     * "android:name" attribute.
     */
    public static boolean checkPipes(){
        for(int i = 0; i < known_pipes.length; i++){
            String pipes = known_pipes[i];
            File qemu_socket = new File(pipes);
            if(qemu_socket.exists()){
                Log.v("Result:", "Find pipes!");
                return true;
            }
        }
        Log.i("Result:", "Not Find pipes!");
        return false;
    }

目前市面上流行的Android模拟器主要有
Genymotion,天天模拟器,夜神模拟器,海马玩模拟器,畅玩模拟器,itools模拟器,逍遥模拟器,文卓爷模拟器,原生Android模拟器,BlueStacks,我们都知道除了原生模拟器之外,大部分Android模拟器都是基于VirtualBox的,这是重要的检测点之一,其次相比于手机,模拟器上少了一些重要特征,如蓝牙功能,温度传感器等等,这些都是可以用来检测模拟器的依据,同时,每种定制版本的模拟器上,都会有一些它特有的可执行文件,如下是我在测试多种模拟器时收集的特征文件:


/**其他模拟器特性
/system/usr/idc/androVM_Virtual_Input.idc   
/system/usr/keylayout/androVM_Virtual_Input.kl  
/system/xbin/mount.vboxsf   
/ueventd.android_x86.rc //基于VirtualBox的模拟器都会存在该属性
/ueventd.vbox86.rc  //基于VirtualBox的模拟器都会存在该属性
**/

0x02检测真机才有的一些特殊信息

检测一些特殊信息,如当前设备cpu温度时,搜集了一些资料,提供了一个adb方式去获取,/sys/class/thermal/thermal_zoneX/temp(其中X是核心数量),但发现模拟器上没有thermal_zoneX目录,只有两个cooling_deviceX目录,因而有了一个新的判断依据,如下:

int checkTemp() {
    DIR *dirptr = NULL; //当前手机的温度检测,手机下均有thermal_zone文件
    int i = 0;
    struct dirent *entry;
    if ((dirptr = opendir("/sys/class/thermal/")) != NULL) {
        while (entry = readdir(dirptr)) {
            // LOGE("%s  \n", entry->d_name);
            if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
                continue;
            }
            char *tmp = entry->d_name;
            if (strstr(tmp, "thermal_zone") != NULL) {
                i++;
            }
        }
        closedir(dirptr);
    } else {
        LOGE("open thermal fail");
    }
    return i;
}

使用opendir函数去访问thermal目录,遍历该目录下所有目录,当不存在thermal_zone目录时,则判断当前设备为模拟器

0x03检测设备信息

1,IMEI和IMSI

IMEI 移动设备国际身份码。

IMSI IMSI国际移动用户识别码,储存在SIfinal TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

String imei = tm.getDeviceId();

String imsi = tm.getSubscriberId();:354273055927169 / null(无卡)

设备2:862966024243759 / 460011040618938

模拟器:000000000000000 / 310260000000000

2,SerialString serial = android.os.Build.SERIAL;:4df78680771b117b

设备2:OBAI5HDQZPDIRCQG

模拟器:unknown

3,androidString android_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);和模拟器都有,16位。

4,Mac地址

WifiManager wifimanage=(WifiManager)getSystemService(Context.WIFI_SERVICE); WifiInfo wifiinfo= wifimanage.getConnectionInfo();

设备1:88:32:9b:1e:49:20

设备2:f8:a4:5f:fd:56:17

/**
     * 检测手机上的一些硬件信息
     *
     * @param context The context of the application package.
     * @return launcher activity name of this application. From the
     * "android:name" attribute.
     */
    public static Boolean CheckEmulatorBuild(Context context){
        String BOARD = android.os.Build.BOARD;
        String BOOTLOADER = android.os.Build.BOOTLOADER;
        String BRAND = android.os.Build.BRAND;
        String DEVICE = android.os.Build.DEVICE;
        String HARDWARE = android.os.Build.HARDWARE;
        String MODEL = android.os.Build.MODEL;
        String PRODUCT = android.os.Build.PRODUCT;
        if (BOARD == "unknown" || BOOTLOADER == "unknown"
                || BRAND == "generic" || DEVICE == "generic"
                || MODEL == "sdk" || PRODUCT == "sdk"
                || HARDWARE == "goldfish")
        {
            Log.v("Result:", "Find Emulator by EmulatorBuild!");
            return true;
        }
        Log.v("Result:", "Not Find Emulator by EmulatorBuild!");
        return false;
    }

这种方式可以通过root后hook来绕过

0x04检测内核信息

一,native方式。

通过c代码读取设备中的配置和硬件相关信息。

1,diskstats

获取闪存的分区状态信息。

int fd = open(“/proc/diskstats”, O_RDONLY);

bytes = read(fd, buf, bytes);
区别:真机下都有mmcblk0分区,但是模拟器没有分区信息。

2,mac地址。

通过socket和ioctl读取mac地址。

sockfd = socket(AF_INET, SOCK_DGRAM, 0);

ioctl(sockfd, SIOCGIFCONF, (char*)&ifc);

ioctl(sockfd, SIOCGIFADDR, &ifr[i])

ioctl(sockfd, SIOCGIFHWADDR, (char*)&ifr[i])
区别:真机可以获取wlan0的ip和mac地址,模拟器只能获取eth0的ip和mac地址;

3,有用的prop信息。

__system_property_get(key, buf);
区别: 模拟器没有ro.boot.serialno和ro.serialno属性,真机中为机器序列号。

模拟器 ro.hardware属性为goldfish,真机为各自的型号。

4,cpu信息。

int fd = open(“/proc/cpuinfo”, O_RDONLY);

bytes = read(fd, buf, bytes);
区别:模拟器中cpuinfo的硬件为Goldfish。

5,drivers

int fd = open(“/proc/tty/drivers”, O_RDONLY);
区别:模拟器中包含goldfish的驱动

反模拟器代码:https://github.com/ThomasKing2014/anti-emulator/blob/master/AntiEmulator/src/diff/strazzere/anti/MainActivity.java

改机伪装代码:https://github.com/bingghost/HideAndroidEmulator

参考:

https://yq.aliyun.com/ziliao/152739
https://github.com/l123456789jy/Lazy/blob/master/lazylibrary/src/main/java/com/github/lazylibrary/util/AntiEmulatorUtiles.java
https://github.com/ysrc/Anti-Emulator/blob/master/app/src/main/AndroidManifest.xml

posted @ 2017-03-22 14:50  Tesi1a  阅读(862)  评论(0编辑  收藏  举报