Виртуальные Android-устройства для многих — «игрушки», чтобы поиграть в танки или накрутить лайки. Но для экспертов-форензиков это полноценные гостевые ОС, которые живут поверх гипервизора (QEMU/KVM, VirtualBox) или прячутся в контейнерах (LXC). И вместо того чтобы возиться с медиатором или паяльным феном, мы имеем дело с файлом-образом диска. Raw, qcow2, vmdk, vdi — тысячи их, суть одна: это не NAND-чип, а просто кусок данных на хост-машине.
И это, друзья, открывает перед нами новые горизонты... и новые головные (а иногда и не только) боли.
Сценарии использования виртуальных Android-устройств в преступных схемах
Помимо легальных задач (а технология была разработана для них), «негодяйские» сценарии использования эмуляторов становятся все изощреннее. Смотрите сами:
- Автоматизированный кликфрод. Скрипты на adb shell input tap или Appium гоняются параллельно на десятках эмуляторов. Такие штуки железобетонно выдают себя в логах (event.log, system.log): одинаковые временные паттерны между тапами с точностью до миллисекунды. Человек, в отличие от бота, так не кликает.
- Симуляция геолокации. Включаем adb shell settings put secure mock_location 1, подставляем координаты — и приложение, доверяющее системному провайдеру, пишет эти GPS-данные к себе в SQLite (например, в /data/data/com.google.android.gms/databases/). Все вроде бы чисто, но следы найдутся (если знать, где поискать).
- Массовая регистрация аккаунтов с подменой IMEI и Android ID. В эмуляторе эти идентификаторы лежат в settings.db (таблица secure). Их меняют через adb shell content update или прямо в образе до запуска. Но старые значения как назло (читай «к добру») часто остаются в logcat и в last_log — опять же, если знать, куда смотреть.
- Прокси-цепи. Эмуляторы часто прогоняют трафик через SOCKS5 или HTTP-прокси. Настройки сохраняются в global.properties внутри образа, а на хосте — в /var/log/syslog или в дампах iptables.
На практике это означает: мы должны проверять не только пользовательские приложения, но и системные логи, проперти и временные метки событий ввода. Рекомендую почаще повторять эту мантру.
Чем виртуальные устройства отличаются от реальных
Перейдем к самому вкусному — как отличить эмулятор от «живого» устройства без специальных детекторов.
Ядро и драйверы
В реальном телефоне драйверы общаются с железом через прерывания и DMA. В эмуляторе все идет через гипервизор. Отсюда следы:
- /proc/cpuinfo — увидите флаг hypervisor.
- dmesg — сообщения о виртуальных шинах virtio.
- /sys/class/dmi/id/ — записи типа Product Name: KVM или VirtualBox.
Файловая система
- В эмуляторе блоковое устройство часто называется /dev/block/vda, а не привычное mmcblk0. Проверьте mount и fstab.
- Размер системного раздела system.img может быть не кратным (!) физическим блокам eMMC — это тоже маркер.
- build.prop содержит ro.kernel.qemu=1, ro.product.device=generic. Но умные негодяи правят build.prop. Однако идеальных преступлений не бывает. Остаются вторичные признаки: например, наличие /dev/qemu_pipe или /dev/virtio-ports/.
Поведение приложений
Некоторые приложения сами проверяют окружение:
- Свойства ro.kernel.qemu, ro.product.model, ro.hardware.
- Наличие файлов вроде fstab.goldfish.
- Архитектура CPU: если приложение требует ARM, а тут x86, оно может отказаться работать.
- Отсутствие датчиков: вызов SensorManager возвращает null или фиктивные данные.
Совет: в логах logcat с уровнем DEBUG и WARN многие приложения пишут что-то вроде Emulator detected или Running on virtual device. Найдете — считайте, можно прикуривать сигару.
Чем разные образы отличаются между собой
Универсального рецепта нет, каждый эмулятор — это особый мир со своими путями и форматами. Давайте кратко пробежимся по основным.
AVD (Android Virtual Device)
- Образы: system.img, userdata.img, cache.img — сырые ext4. Можно смонтировать в Linux через mount -o loop.
- Где лежат: ~/.android/avd// — там же config.ini, hardware-qemu.ini и снапшоты RAM (.snap или .img).
- Фишка: снапшоты можно анализировать через Volatility с плагином для Android — получите доступ к процессам на момент снимка.
BlueStacks
- Формат: гибридный .vdi (VirtualBox) или .vhd. Путь: C:\ProgramData\BlueStacks\Engine\ или ~/.bluestacks/.
- Особенность: пользовательские данные — в Data.vdi, системные — в System.vdi. В некоторых версиях Data.vdi зашифрован XOR-ключом, захардкоженным в исполняемый файл эмулятора.
- Артефакты: логи установки приложений сохраняются в %TEMP%\BlueStacksLogs\ на хосте — бесценный источник инфы о времени и действиях.
NoxPlayer
- Формат: VMDK или VHD. Лежит в C:\Users\\AppData\Local\Nox\bin\BignoxVMS\.
- Фишка: встроенный root и менеджер множественных инстансов. У каждого свой settings.db и shared_prefs.
- Клад: в папке Nox_share/ хранятся файлы, которыми обменивались между хостом и эмулятором — часто там находят документы, фото, улики.
LDPlayer
- Использует vmdk, Android 9. Отличается агрессивной оптимизацией ввода-вывода, из-за чего временные метки файлов (mtime, atime) не всегда корректно обновляются. Эту аномалию можно использовать как признак работы в виртуальной среде.
Waydroid (контейнерный подход)
- Нет отдельного образа диска — корневая ФС смонтирована через OverlayFS. Данные приложений в /var/lib/waydroid/data/ — часть хостовой ФС. Артефакты тонким слоем размазаны между хостом и контейнером. Анализировать нужно обе стороны.
Технический вывод: перед началом работы всегда идентифицируйте эмулятор и его версию. От этого зависят пути, форматы и методы монтирования. Универсального скрипта нет, но file и binwalk вам в помощь.
Особенности работы с виртуальными образами
Монтирование
- raw/ext4: sudo mount -o loop,ro userdata.img /mnt/android_data
- qcow2: используем qemu-nbd:
sudo modprobe nbd
sudo qemu-nbd --connect=/dev/nbd0 userdata.qcow2
- sudo mount /dev/nbd0p1 /mnt/
- vmdk: vmware-mount или тот же qemu-nbd.
- vdi (VirtualBox): VBoxManage clonehd или qemu-nbd.
- Проприетарные (BlueStacks): сначала конвертируем или пробуем qemu-nbd — если не зашифрован.
Важно! Никогда не монтируйте с записью — только в режиме чтения. Иначе вы меняете временные метки и рушите все доказательства. Это как трогать улики голыми руками — недопустимо.
Зашифрованные BLOB-объекты
Многие приложения с E2EE (мессенджеры) хранят ключи в KeyStore или в /data/misc/keystore/. На реальном устройстве они защищены TEE, а в эмуляторе — программным KeyStore. Часто мастер-ключ лежит прямо в keystore.db (SQLite) или в файле .key. Зная его, можно расшифровать базы приложений. Для WhatsApp, например, ключ можно извлечь, если есть root (а в эмуляторе он есть всегда). Как и многое в форензике, это не взлом, это — работа с плохо закрытой дверью =).
Восстановление удаленных данных
В виртуальном образе TRIM-команды могут не выполняться, потому что образ — просто файл на хосте. Поэтому удаленные файлы часто остаются в неразмеченных областях. Запускайте foremost, scalpel, photorec на сыром образе — вытащите JPEG, PDF, фрагменты SQLite. И не забывайте про debugfs -R "ls -d" /dev/loop0 — она покажет удаленные inode.
Снапшоты и дампы памяти
Снапшот RAM (.snap или .mem) — это золотая жила. Прогоните его через плагин linux_android в Volatility 3. Получите запущенные процессы, сетевые соединения, открытые файлы. Это критично, если преступник использовал самоуничтожающиеся сообщения — они могли сохраниться только в оперативке.
Корреляция сущностей
Когда на хосте десятки эмуляторов, не замыкайтесь на каждом образе по отдельности. Анализируйте хостовые логи (/var/log/auth.log, ~/.bash_history), сетевые соединения. Все эмуляторы могут использовать один выходной IP (NAT), но внутренние MAC и Android ID будут разные. А в logcat -b events можно найти время загрузки каждого инстанса — это поможет синхронизировать временные линии. Для упрощения процесса корреляции можно использовать «МК Эксперт Плюс» (да-да, я работаю в компании, которая его разрабатывает, можно засчитать за интеграцию) или что-то похожее: что-то, что позволяет создать один проект, куда вы добавляете образы всех эмуляторов и хостовые логи, и он сам выстраивает кросс-корреляцию, показывая, какие события на каких устройствах происходили одновременно.
Сравнительная таблица: реальное vs виртуальное

Кейс: когда эмулятор говорит громче слов
Теория теорией, но давайте на придуманном (как всегда) примере. Не мануал же читаете =)
Вводная: служба безопасности небольшого банка. У них «поплыла» реферальная программа — кто-то накручивал бонусы за приведенных клиентов. С виду все чисто: проходят идентификацию, загружают фото паспорта... Но новые аккаунты регистрируются с разных IP слишком уж быстро — по 10-15 регистраций в час, без выходных. Человек так не может, даже если очень старается. Подозреваем автоматизацию.
Первая зацепка: IP-адреса были разные, но все они принадлежали одной облачной платформе. Не скажу, какой магией (потому как не знаю, да и кейс-то выдуманный =)) получили доступ к виртуальным машинам — и нашли одну, которая в нужные часы активно качала трафик. На ней стоял BlueStacks. Начинаем тянуться к упомянутой выше сигаре.
Что мы сделали:
1. Скопировали образ Data.vdi (пользовательские данные) и System.vdi (системные) прямо с хоста, предварительно остановив эмулятор. Сняли хеши, задокументировали время.
2. Загрузили оба образа в «Мобильный Криминалист» — инструмент автоматически распознал структуру, распарсил системные логи и пользовательские приложения. Вместо того чтобы вручную монтировать и искать базы, мы получили готовую временную шкалу. В /data/data/com.bank.app/databases/ нашли SQLite-базу приложения. Внутри — таблица registrations, где для каждой сессии были прописаны координаты GPS. Координаты били в одну и ту же точку — сквер в центре Москвы, хотя «клиенты» якобы жили в разных регионах. Это был mock location чистой воды.
3. Подняли логи ADB (тоже в «МК») — в logcat нашли тысячи записей вида
I/InputDispatcher: Delivering touch event to: com.bank.appD/Appium: tap at (350, 720) at 2025-02-10 03:14:23.456
Интервалы между тапами — ровно 500 мс, без джиттера (видимо, пилоты «Формулы-1» в тапку соревновались).
4. Но самое вкусное — мы решили глянуть снапшот RAM, который эмулятор автоматически сохранил при остановке. Прогнали через Volatility с плагином для Android и нашли в памяти активный токен сессии одного из «новых клиентов». Токен еще не протух. Мы быстро проверили — этот аккаунт уже успел вывести бонусы на сторонний кошелек. Связали транзакции, и цепочка замкнулась.
5. Финальный аккорд: в хостовой папке %TEMP%\BlueStacksLogs\ нашли логи установки приложения и скриптов автоматизации, которые датировались месяцем до инцидента. А в Nox_share/ (да, там был еще и Nox, для подстраховки) валялся файл passwords.txt с паролями от десятков аккаунтов — их явно готовили заранее.
Результат: не только подтвердили факт накрутки, но и восстановили всю хронологию, от момента установки эмулятора до вывода средств. Предоставили банку хронологическую ленту с временными метками, хешами образов и выдержками из логов.
История выдумана, все совпадения, как всегда, случайны =)
Мораль: виртуальные образы — это не безликие файлы. Они хранят все: и координаты, и тайминги нажатий, и даже пароли, если преступник поленился их удалить. Главное — не бояться копать глубже, чем «просто посмотреть папки». Анализируйте память, сопоставляйте с хостовыми логами, ищите аномалии. Иногда эмулятор выдает злоумышленника с головой, даже когда тот считает себя невидимкой.
Вместо заключения
Форензика виртуальных Android-устройств — это гибрид мобильной форензики, систем виртуализации, файловых систем и криптографии. Она пока в стадии становления, но методики для AVD и основных эмуляторов уже отработаны.
Главное правило: не применяйте шаблон «реального телефона» к образу. Подходите индивидуально, вооружившись qemu-nbd, debugfs, logcat и терпением.
И помните: в реальной жизни преступник не может нажать Reset и за секунду вернуть телефон к заводским настройкам. А в виртуальной — может. Но мы-то умеем читать логи и восстанавливать удаленные inode. Пусть эта гонка вооружений продолжается — нам она только добавляет работы и интересных кейсов. А значит, скучно не будет.