自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

檢測Android虛擬機的方法和代碼實現(xiàn)

云計算 虛擬化 Android
剛剛看了一些關于Detect Android Emulator的開源項目/文章/論文,我看的這些其實都是13年14年提出的方法,方法里大多是檢測一些環(huán)境屬性,檢查一些文件這樣,但實際上檢測的思路并不局限于此。

剛剛看了一些關于Detect Android Emulator的開源項目/文章/論文,我看的這些其實都是13年14年提出的方法,方法里大多是檢測一些環(huán)境屬性,檢查一些文件這樣,但實際上檢測的思路并不局限于此。有的是很直接了當去檢測qemu,而其它的方法則是旁敲側擊比如檢測adb,檢測ptrace之類的。思路也很靈活。

***看到有提出通過利用QEMU這樣的模擬CPU與物理CPU之間的實際差異(任務調(diào)度差異), 模擬傳感器和物理傳感器的差異,緩存的差異等方法來檢測。相比檢測環(huán)境屬性,檢測效果會提升很多。

[[228598]]

下面我就列出各個資料中所提出的一些方法/思路/代碼供大家交流學習。

QEMU Properties

  1. public class Property { 
  2.    public String name
  3.    public String seek_value; 
  4.  
  5.    public Property(String name, String seek_value) { 
  6.        this.name = name
  7.        this.seek_value = seek_value; 
  8.    } 
  9. /** 
  10. * 已知屬性, 格式為 [屬性名, 屬性值], 用于判定當前是否為QEMU環(huán)境 
  11. */ 
  12. private static Property[] known_props = {new Property("init.svc.qemud"null), 
  13.        new Property("init.svc.qemu-props"null), new Property("qemu.hw.mainkeys"null), 
  14.        new Property("qemu.sf.fake_camera"null), new Property("qemu.sf.lcd_density"null), 
  15.        new Property("ro.bootloader""unknown"), new Property("ro.bootmode""unknown"), 
  16.        new Property("ro.hardware""goldfish"), new Property("ro.kernel.android.qemud"null), 
  17.        new Property("ro.kernel.qemu.gles"null), new Property("ro.kernel.qemu""1"), 
  18.        new Property("ro.product.device""generic"), new Property("ro.product.model""sdk"), 
  19.        new Property("ro.product.name""sdk"), 
  20.        new Property("ro.serialno"null)}; 
  21. /** 
  22. * 一個閾值, 因為所謂"已知"的模擬器屬性并不完全準確, 有可能出現(xiàn)假陽性結果, 因此保持一定的閾值能讓檢測效果更好 
  23. */ 
  24. private static int MIN_PROPERTIES_THRESHOLD = 0x5; 
  25. /** 
  26. * 嘗試通過查詢指定的系統(tǒng)屬性來檢測QEMU環(huán)境, ***跟閾值比較得出檢測結果. 
  27. * @param context A {link Context} object for the Android application. 
  28. * @return {@code true} if enough properties where found to exist or {@code false} if not
  29. */ 
  30. public boolean hasQEmuProps(Context context) { 
  31.    int found_props = 0; 
  32.  
  33.    for (Property property : known_props) { 
  34.        String property_value = Utilities.getProp(context, property.name); 
  35.        // See if we expected just a non-null 
  36.        if ((property.seek_value == null) && (property_value != null)) { 
  37.            found_props++; 
  38.        } 
  39.        // See if we expected a value to seek 
  40.        if ((property.seek_value != null) && (property_value.indexOf(property.seek_value) != -1)) { 
  41.            found_props++; 
  42.        } 
  43.  
  44.    } 
  45.  
  46.    if (found_props >= MIN_PROPERTIES_THRESHOLD) { 
  47.        return true
  48.    } 
  49.  
  50.    return false

這些都是基于一些經(jīng)驗和特征來比對的屬性, 這里的屬性以及之后的一些文件呀屬性啊之類的我就不再多作解釋。

Device ID

  1. private static String[] known_device_ids = {"000000000000000", // Default emulator id 
  2.        "e21833235b6eef10", // VirusTotal id 
  3.        "012345678912345"}; 
  4. public static boolean hasKnownDeviceId(Context context) { 
  5.    TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 
  6.  
  7.    String deviceId = telephonyManager.getDeviceId(); 
  8.  
  9.    for (String known_deviceId : known_device_ids) { 
  10.        if (known_deviceId.equalsIgnoreCase(deviceId)) { 
  11.            return true
  12.        } 
  13.  
  14.    } 
  15.    return false

Default Number

  1. private static String[] known_numbers = { 
  2.        "15555215554", // 模擬器默認電話號碼 + VirusTotal 
  3.        "15555215556""15555215558""15555215560""15555215562""15555215564""15555215566"
  4.        "15555215568""15555215570""15555215572""15555215574""15555215576""15555215578"
  5.        "15555215580""15555215582""15555215584",}; 
  6. public static boolean hasKnownPhoneNumber(Context context) { 
  7.    TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 
  8.  
  9.    String phoneNumber = telephonyManager.getLine1Number(); 
  10.  
  11.    for (String number : known_numbers) { 
  12.        if (number.equalsIgnoreCase(phoneNumber)) { 
  13.            return true
  14.        } 
  15.  
  16.    } 
  17.    return false

IMSI

  1. private static String[] known_imsi_ids = {"310260000000000" // 默認IMSI編號 
  2. }; 
  3. public static boolean hasKnownImsi(Context context) { 
  4.    TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 
  5.    String imsi = telephonyManager.getSubscriberId(); 
  6.  
  7.    for (String known_imsi : known_imsi_ids) { 
  8.        if (known_imsi.equalsIgnoreCase(imsi)) { 
  9.            return true
  10.        } 
  11.    } 
  12.    return false

Build類

  1. public static boolean hasEmulatorBuild(Context context) { 
  2.    String BOARD = android.os.Build.BOARD; // The name of the underlying board, like "unknown"
  3.    // This appears to occur often on real hardware... that's sad 
  4.    // String BOOTLOADER = android.os.Build.BOOTLOADER; // The system bootloader version number. 
  5.    String BRAND = android.os.Build.BRAND; // The brand (e.g., carrier) the software is customized for, if any
  6.    // "generic" 
  7.    String DEVICE = android.os.Build.DEVICE; // The name of the industrial design. "generic" 
  8.    String HARDWARE = android.os.Build.HARDWARE; // The name of the hardware (from the kernel command line or 
  9.    // /proc). "goldfish" 
  10.    String MODEL = android.os.Build.MODEL; // The end-user-visible name for the end product. "sdk" 
  11.    String PRODUCT = android.os.Build.PRODUCT; // The name of the overall product. 
  12.    if ((BOARD.compareTo("unknown") == 0) /* || (BOOTLOADER.compareTo("unknown") == 0) */ 
  13.            || (BRAND.compareTo("generic") == 0) || (DEVICE.compareTo("generic") == 0) 
  14.            || (MODEL.compareTo("sdk") == 0) || (PRODUCT.compareTo("sdk") == 0) 
  15.            || (HARDWARE.compareTo("goldfish") == 0)) { 
  16.        return true
  17.    } 
  18.    return false

運營商名

  1. public static boolean isOperatorNameAndroid(Context paramContext) { 
  2.    String szOperatorName = ((TelephonyManager) paramContext.getSystemService(Context.TELEPHONY_SERVICE)).getNetworkOperatorName(); 
  3.    boolean isAndroid = szOperatorName.equalsIgnoreCase("android"); 
  4.    return isAndroid; 

QEMU驅(qū)動

  1. private static String[] known_qemu_drivers = {"goldfish"}; 
  2. /** 
  3. * 讀取驅(qū)動文件, 檢查是否包含已知的qemu驅(qū)動 
  4. * @return {@code true} if any known drivers where found to exist or {@code false} if not
  5. */ 
  6. public static boolean hasQEmuDrivers() { 
  7.    for (File drivers_file : new File[]{new File("/proc/tty/drivers"), new File("/proc/cpuinfo")}) { 
  8.        if (drivers_file.exists() && drivers_file.canRead()) { 
  9.            // We don't care to read much past things since info we care about should be inside here 
  10.            byte[] data = new byte[1024]; 
  11.            try { 
  12.                InputStream is = new FileInputStream(drivers_file); 
  13.                is.read(data); 
  14.                is.close(); 
  15.            } catch (Exception exception) { 
  16.                exception.printStackTrace(); 
  17.            } 
  18.  
  19.            String driver_data = new String(data); 
  20.            for (String known_qemu_driver : FindEmulator.known_qemu_drivers) { 
  21.                if (driver_data.indexOf(known_qemu_driver) != -1) { 
  22.                    return true
  23.                } 
  24.            } 
  25.        } 
  26.    } 
  27.  
  28.    return false

QEMU文件

  1. private static String[] known_files = {"/system/lib/libc_malloc_debug_qemu.so""/sys/qemu_trace"
  2.        "/system/bin/qemu-props"}; 
  3. /** 
  4. * 檢查是否存在已知的QEMU環(huán)境文件 
  5. * @return {@code true} if any files where found to exist or {@code false} if not
  6. */ 
  7. public static boolean hasQEmuFiles() { 
  8.    for (String pipe : known_files) { 
  9.        File qemu_file = new File(pipe); 
  10.        if (qemu_file.exists()) { 
  11.            return true
  12.        } 
  13.    } 
  14.  
  15.    return false

Genymotion文件

  1. private static String[] known_geny_files = {"/dev/socket/genyd""/dev/socket/baseband_genyd"}; 
  2. /** 
  3. * 檢查是否存在已知的Genemytion環(huán)境文件 
  4. * @return {@code true} if any files where found to exist or {@code false} if not
  5. */ 
  6. public static boolean hasGenyFiles() { 
  7.    for (String file : known_geny_files) { 
  8.        File geny_file = new File(file); 
  9.        if (geny_file.exists()) { 
  10.            return true
  11.        } 
  12.    } 
  13.  
  14.    return false

QEMU管道

  1. private static String[] known_pipes = {"/dev/socket/qemud""/dev/qemu_pipe"}; 
  2. /** 
  3. * 檢查是否存在已知的QEMU使用的管道 
  4. * @return {@code true} if any pipes where found to exist or {@code false} if not
  5. */ 
  6. public static boolean hasPipes() { 
  7.    for (String pipe : known_pipes) { 
  8.        File qemu_socket = new File(pipe); 
  9.        if (qemu_socket.exists()) { 
  10.            return true
  11.        } 
  12.    } 
  13.  
  14.    return false

設置斷點

  1. static { 
  2.    // This is only valid for arm 
  3.    System.loadLibrary("anti"); 
  4. public native static int qemuBkpt(); 
  5.  
  6. public static boolean checkQemuBreakpoint() { 
  7.    boolean hit_breakpoint = false
  8.  
  9.    // Potentially you may want to see if this is a specific value 
  10.    int result = qemuBkpt(); 
  11.  
  12.    if (result > 0) { 
  13.        hit_breakpoint = true
  14.    } 
  15.  
  16.    return hit_breakpoint; 

以下是對應的c++代碼

  1. void handler_sigtrap(int signo) { 
  2.  exit(-1); 
  3.  
  4. void handler_sigbus(int signo) { 
  5.  exit(-1); 
  6.  
  7. int setupSigTrap() { 
  8.  // BKPT throws SIGTRAP on nexus 5 / oneplus one (and most devices) 
  9.  signal(SIGTRAP, handler_sigtrap); 
  10.  // BKPT throws SIGBUS on nexus 4 
  11.  signal(SIGBUS, handler_sigbus); 
  12.  
  13. // This will cause a SIGSEGV on some QEMU or be properly respected 
  14. int tryBKPT() { 
  15.  __asm__ __volatile__ ("bkpt 255"); 
  16.  
  17. jint Java_diff_strazzere_anti_emulator_FindEmulator_qemuBkpt(JNIEnv* env, jobject jObject) { 
  18.  
  19.  pid_t child = fork(); 
  20.  int child_status, status = 0; 
  21.  
  22.  if(child == 0) { 
  23.    setupSigTrap(); 
  24.    tryBKPT(); 
  25.  } else if(child == -1) { 
  26.    status = -1; 
  27.  } else { 
  28.  
  29.    int timeout = 0; 
  30.    int i = 0; 
  31.    while ( waitpid(child, &child_status, WNOHANG) == 0 ) { 
  32.      sleep(1); 
  33.      // Time could be adjusted here, though in my experience if the child has not returned instantly 
  34.      // then something has gone wrong and it is an emulated device 
  35.      if(i++ == 1) { 
  36.        timeout = 1; 
  37.        break; 
  38.      } 
  39.    } 
  40.  
  41.    if(timeout == 1) { 
  42.      // Process timed out - likely an emulated device and child is frozen 
  43.      status = 1; 
  44.    } 
  45.  
  46.    if ( WIFEXITED(child_status) ) { 
  47.      // 子進程正常退出 
  48.      status = 0; 
  49.    } else { 
  50.      // Didn't exit properly - very likely an emulator 
  51.      status = 2; 
  52.    } 
  53.  
  54.    // Ensure child is dead 
  55.    kill(child, SIGKILL); 
  56.  } 
  57.  
  58.  return status; 

這里我的描述可能并不準確, 因為并沒有找到相關的資料. 我只能以自己的理解來解釋一下:

SIGTRAP是調(diào)試器設置斷點時發(fā)生的信號, 在nexus5或一加手機等大多數(shù)手機都可以觸發(fā). SIGBUS則是在一個總線錯誤, 指針也許訪問了一個有效地址, 但總線會因為數(shù)據(jù)未對齊等原因無法使用, 在nexus4手機上可以觸發(fā). 而bkpt則是arm的斷點指令, 這是曾經(jīng)qemu被提出來的一個issue, qemu會因為SIGSEGV信號而崩潰, 作者想利用這個崩潰來檢測qemu. 如果程序沒有正常退出或被凍結, 那么就可以認定很可能是在模擬器里.

ADB

  1. public static boolean hasEmulatorAdb() { 
  2.    try { 
  3.        return FindDebugger.hasAdbInEmulator(); 
  4.    } catch (Exception exception) { 
  5.        exception.printStackTrace(); 
  6.        return false
  7.    } 

isUserAMonkey()

  1. public static boolean hasEmulatorAdb() { 
  2.    try { 
  3.        return FindDebugger.hasAdbInEmulator(); 
  4.    } catch (Exception exception) { 
  5.        exception.printStackTrace(); 
  6.        return false
  7.    } 

這個其實是用于檢測當前操作到底是用戶還是腳本在要求應用執(zhí)行。

isDebuggerConnected()

  1. /** 
  2. * 你信或不信, 還真有許多加固程序使用這個方法... 
  3. */ 
  4. public static boolean isBeingDebugged() { 
  5.    return Debug.isDebuggerConnected(); 

這個方法是用來檢測調(diào)試,判斷是否有調(diào)試器連接。

ptrace

  1. private static String tracerpid = "TracerPid"
  2. /** 
  3. * 阿里巴巴用于檢測是否在跟蹤應用進程 
  4. * 容易規(guī)避, 用法是創(chuàng)建一個線程每3秒檢測一次, 如果檢測到則程序崩潰 
  5. * @return 
  6. * @throws IOException 
  7. */ 
  8. public static boolean hasTracerPid() throws IOException { 
  9.    BufferedReader reader = null
  10.    try { 
  11.        reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/status")), 1000); 
  12.        String line; 
  13.  
  14.        while ((line = reader.readLine()) != null) { 
  15.            if (line.length() > tracerpid.length()) { 
  16.                if (line.substring(0, tracerpid.length()).equalsIgnoreCase(tracerpid)) { 
  17.                    if (Integer.decode(line.substring(tracerpid.length() + 1).trim()) > 0) { 
  18.                        return true
  19.                    } 
  20.                    break; 
  21.                } 
  22.            } 
  23.        } 
  24.  
  25.    } catch (Exception exception) { 
  26.        exception.printStackTrace(); 
  27.    } finally { 
  28.        reader.close(); 
  29.    } 
  30.    return false

這個方法是通過檢查 /proc/self/status 的TracerPid項,這個項在沒有跟蹤的時候默認為0,當有程序在跟蹤時會修改為對應的pid。因此如果TracerPid不等于0,那么就可以認為是在模擬器環(huán)境。

TCP連接

  1. public static boolean hasAdbInEmulator() throws IOException { 
  2.    boolean adbInEmulator = false
  3.    BufferedReader reader = null
  4.    try { 
  5.        reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/net/tcp")), 1000); 
  6.        String line; 
  7.        // Skip column names 
  8.        reader.readLine(); 
  9.  
  10.        ArrayList<tcp> tcpList = new ArrayList<tcp>(); 
  11.  
  12.        while ((line = reader.readLine()) != null) { 
  13.            tcpList.add(tcp.create(line.split("\\W+"))); 
  14.        } 
  15.  
  16.        reader.close(); 
  17.  
  18.        // Adb is always bounce to 0.0.0.0 - though the port can change 
  19.        // real devices should be != 127.0.0.1 
  20.        int adbPort = -1; 
  21.        for (tcp tcpItem : tcpList) { 
  22.            if (tcpItem.localIp == 0) { 
  23.                adbPort = tcpItem.localPort; 
  24.                break; 
  25.            } 
  26.        } 
  27.  
  28.        if (adbPort != -1) { 
  29.            for (tcp tcpItem : tcpList) { 
  30.                if ((tcpItem.localIp != 0) && (tcpItem.localPort == adbPort)) { 
  31.                    adbInEmulator = true
  32.                } 
  33.            } 
  34.        } 
  35.    } catch (Exception exception) { 
  36.        exception.printStackTrace(); 
  37.    } finally { 
  38.        reader.close(); 
  39.    } 
  40.  
  41.    return adbInEmulator; 
  42.  
  43. public static class tcp { 
  44.  
  45.    public int id; 
  46.    public long localIp; 
  47.    public int localPort; 
  48.    public int remoteIp; 
  49.    public int remotePort; 
  50.  
  51.    static tcp create(String[] params) { 
  52.        return new tcp(params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8], 
  53.                        params[9], params[10], params[11], params[12], params[13], params[14]); 
  54.    } 
  55.  
  56.    public tcp(String id, String localIp, String localPort, String remoteIp, String remotePort, String state, 
  57.                    String tx_queue, String rx_queue, String tr, String tm_when, String retrnsmt, String uid, 
  58.                    String timeout, String inode) { 
  59.        this.id = Integer.parseInt(id, 16); 
  60.        this.localIp = Long.parseLong(localIp, 16); 
  61.        this.localPort = Integer.parseInt(localPort, 16); 
  62.    } 

這個方法是通過讀取/proc/net/tcp的信息來判斷是否存在adb,比如真機的的信息為0: 4604D20A:B512 A3D13AD8...,而模擬器上的對應信息就是 0: 00000000:0016 00000000:0000,因為adb通常是反射到0.0.0.0這個ip上,雖然端口有可能改變,但確實是可行的。

TaintDroid

  1. public static boolean hasPackageNameInstalled(Context context, String packageName) { 
  2.    PackageManager packageManager = context.getPackageManager(); 
  3.  
  4.    // In theory, if the package installer does not throw an exception, package exists 
  5.    try { 
  6.        packageManager.getInstallerPackageName(packageName); 
  7.        return true
  8.    } catch (IllegalArgumentException exception) { 
  9.        return false
  10.    } 
  11. public static boolean hasAppAnalysisPackage(Context context) { 
  12.    return Utilities.hasPackageNameInstalled(context, "org.appanalysis"); 
  13. public static boolean hasTaintClass() { 
  14.    try { 
  15.        Class.forName("dalvik.system.Taint"); 
  16.        return true
  17.    } 
  18.    catch (ClassNotFoundException exception) { 
  19.        return false
  20.    } 

這個比較單純了。就是通過檢測包名,檢測Taint類來判斷是否安裝有TaintDroid這個污點分析工具。另外也還可以檢測TaintDroid的一些成員變量。

eth0

  1. private static boolean hasEth0Interface() { 
  2.    try { 
  3.        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { 
  4.            NetworkInterface intf = en.nextElement(); 
  5.            if (intf.getName().equals("eth0")) 
  6.                return true
  7.        } 
  8.    } catch (SocketException ex) { 
  9.    } 
  10.    return false

檢測是否存在eth0網(wǎng)卡。

傳感器

手機上配備了各式各樣的傳感器, 但它們實質(zhì)上都是基于從環(huán)境收集的信息輸出值, 因此想要模擬傳感器是非常具有挑戰(zhàn)性的. 這些傳感器為識別手機和模擬器提供了新的機會。

比如在論文 Rage Against the Virtual Machine: Hindering Dynamic Analysis of Android Malware 中,作者對Android模擬器的加速器進行測試,作者發(fā)現(xiàn)Android模擬器上的傳感器會在相同的時間間隔內(nèi)(觀測結果是0.8s, 標準偏差為0.003043)產(chǎn)生相同的值。顯然對于現(xiàn)實世界的傳感器,這是不可能的。

于是我們可以先注冊一個傳感器監(jiān)聽器,如果注冊失敗,就可能是在模擬器中(排除實際設備不支持傳感器的可能性)。如果注冊成功,那么檢查onSensorChanged回調(diào)方法,如果在連續(xù)調(diào)用這個方法的過程所觀察到的傳感器值或時間間隔相同,那么就可以認定是在模擬器環(huán)境中。

QEMU任務調(diào)度

出于性能優(yōu)化的原因, QEMU在每次執(zhí)行指令時都不會主動更新程序計數(shù)器(PC), 由于翻譯指令在本地執(zhí)行, 而增加PC需要額外的指令帶來開銷. 所以QEMU只在執(zhí)行那些從線性執(zhí)行過程里中斷的指令(例如分支指令)時才會更新程序計數(shù)器。

這也就導致在執(zhí)行一些基本塊的期間如果發(fā)生了調(diào)度事件, 那么也沒有辦法恢復調(diào)度前的PC,也是出于這個原因,QEMU僅在執(zhí)行基本塊后才發(fā)生調(diào)度事件,絕不會執(zhí)行的過程中發(fā)生。

如上圖,因為調(diào)度可能在任意時間發(fā)生,所以在非模擬器環(huán)境下,會觀察到大量的調(diào)度點. 而在模擬器環(huán)境中,只能看到特定的調(diào)度點。

SMC識別

因為QEMU會跟蹤代碼頁的改動,于是存在一種新穎的方法來檢測QEMU--使用自修改代碼(Self-Modifying Code, SMC)引起模擬器和實際設備之間的執(zhí)行流變化。

ARM處理器包含有兩個不同的緩沖Cache, 一個用于指令訪問(I-Cache),而另一個用于數(shù)據(jù)訪問(D-Cache)。但如ARM這樣的哈佛架構并不能保證I-Cache和D-Cache之間的一致性。因此CPU有可能在新代碼片已經(jīng)寫入主存后執(zhí)行舊的代碼片(也許是無效的)。

這個問題可以通過強迫兩個緩存一致得到解決, 這有兩步:

  1. 清理主存, 以便將D-Cache中新寫入的代碼移入主存
  2. 使I-Cache無效, 以便它可以用主存的新內(nèi)容重新填充

在原生Android代碼中,可以使用cacheflush函數(shù),該函數(shù)通過系統(tǒng)調(diào)用完成上述操作。

識別代碼,使用一個具有讀寫權限的內(nèi)存, 其中包含兩個不同函數(shù)f1和f2的代碼,這兩個函數(shù)其實很簡單,只是單純在一個全局字符串變量的末尾附加各自的函數(shù)名稱, 這兩個函數(shù)會在循環(huán)里交錯執(zhí)行,這樣就可以通過結果的字符串推斷出函數(shù)調(diào)用序列。

如前所述,我們調(diào)用cacheflush來同步緩存. 在實際設備和模擬器上運行代碼得到的結果是相同的--每次執(zhí)行都會產(chǎn)生一致的函數(shù)調(diào)用序列。

接下來我們移除調(diào)用cacheflush,執(zhí)行相同的操作。那么在實際設備中, 我們每次運行都會觀察到一個隨機的函數(shù)調(diào)用序列,這也如前所述的那樣,因為I-Cache可能包含一些舊指令,每次調(diào)用的時候緩存都不同步所導致的。

而模擬器環(huán)境卻不會發(fā)生這樣的情況, 而且函數(shù)調(diào)用序列會跟之前沒有移除cacheflush時完全相同, 也就是每次函數(shù)調(diào)用前緩存都是一致的. 這是因為QEMU會跟蹤代碼頁上的修改,并確保生成的代碼始終與內(nèi)存中的目標指令匹配, 因此QEMU會放棄之前版本的代碼翻譯并重新生成新代碼。

結語

看到這里會不會已經(jīng)覺得檢測方法夠多了,可是我還只是看了13年14年的資料。有關近幾年的資料還未涉及。

***我就把這些檢測方法整合在一張思維導圖(見附件)里供大家一覽,歡迎大家和我交流帶帶我

參考鏈接

strazzere/anti-emulator:***發(fā)表于2013年HitCon, 提出了檢測虛擬機的一些方法和思路, 應該是Android模擬器檢測的開山之作了, 本文也主要基于該倉庫進行講解.

Rage Against the Virtual Machine: Hindering Dynamic Analysis of Android Malware:通過任務調(diào)度檢測和使用SMC識別都是參考于這篇論文. 這篇論文和下面這篇論文十分有參考價值, 值得一讀.

Evading Android Runtime Analysis via Sandbox Detection:論文中提出了大量的檢測Android運行環(huán)境的方法和思路, 內(nèi)容豐富且十分全面, 也值得一讀.

CalebFenton/AndroidEmulatorDetect:這個倉庫其實是整合了一些文章和倉庫中的檢測方法和代碼, 而且并不全面, 不過倒是給出了很多參考鏈接, 我順藤摸瓜.

How can I detect when an Android application is running in the emulator? 網(wǎng)友給出了很多解決方法. 但實際上并不全面, 也只是模擬器檢測中的冰山一角罷了. 畢竟可以檢測的地方多了去了。

利用任務調(diào)度特性檢測Android模擬器

 

責任編輯:武曉燕 來源: 看雪社區(qū)
相關推薦

2012-05-18 10:22:23

2010-07-26 09:02:38

2013-07-17 09:32:58

2018-10-11 11:07:28

Windows虛擬機方法

2023-02-20 14:24:56

AndroidDalvikART

2010-01-21 11:17:36

xen虛擬機

2023-04-26 07:51:36

虛擬機操作系統(tǒng)進程

2016-09-27 20:12:33

Android虛擬機Android動態(tài)調(diào)試

2011-04-08 09:25:50

虛擬機

2022-01-26 16:30:47

代碼虛擬機Linux

2009-10-13 15:00:36

物理機虛擬機網(wǎng)絡安全

2022-08-09 11:25:52

數(shù)據(jù)備份服務器虛擬化磁盤

2020-01-17 10:52:37

無服務器容器技術

2009-09-07 21:51:59

2021-03-16 10:36:38

網(wǎng)絡釣魚安全檢測網(wǎng)絡安全

2010-03-03 09:57:37

Linux虛擬機

2020-12-08 05:58:57

CPU虛擬化虛擬機

2009-06-29 19:36:07

虛擬機備份虛擬環(huán)境

2009-09-04 08:33:25

VirtualBox虛

2024-03-13 08:03:02

點贊
收藏

51CTO技術棧公眾號