Pull to refresh

Comments 18

Итого: гонять надо на реальном железе, подключенном по JTAG?
как один из вариантов. Но JTAG есть далеко не во всех мобильниках(производители его отключают насколько мне известно), а вирусописатели могут затачиваться под конкретные уязвимости в прошивках определённых устройств.
А подход, аналогичный BOCHS — т.е. точная эмуляция аппаратуры, пусть медленнее, чем в реальном мире, но зато для виртуальной машины это выглядит как работа с нормальной скоростью, а значения датчиков туда вообще отправлять записанные с реального устройства? Вроде все эти эвристики должны сливать — как это можно обнаружить, если эмулятор «не палится» (не использует хорошо известных фиксированных значений, подставляет реальные или реалистичные идентификаторы на место IMEI и т. д.)?
в разделе 2.3. написано как определяют QEMU с помощью самомодифицирующегося кода и по работе механизма переключения конктекста.
Подход QEMU отличается от подхода BOCHS. Я про второй — там идея в том, чтобы точно сэмулировать поведение аппаратуры, как бы это неэффективно в смысле производительности ни оказалось.
Википедия говорит, что на эмуляцию 1 такта виртуального процессора уходит 260 тактов физического процессора. Если я правильно понимаю, это замедление в 260 раз, я думаю это будет оооочень медленно. Но да, с таким подходом, мы палиться не будем палиться, если только приложение не завязано на каком-нибудь взаимодействии со внешним миром(по сети например). Именно поэтому сейчас смотрят в сторону применения гипервизоров, а не виртуальных машин в этой области, потому что они дают маленький оверхед и могут быть запущены на реальном устройстве, чтобы не эмулировать всю эту аппаратуру, потому что спецификаций нету и на эмуляцию могут уйти годы. А устройства клепаются сейчас достаточно быстро. systems.cs.columbia.edu/projects/kvm-arm — вот эти ребята из Columbia University пилят. Мне почему-то кажется, что за этим подходом будущее, хотя полная и точная эмуляция аппаратуру это тоже круто конечно!
А зачем поддерживать эмуляцию всех фич всех новых устройств, если мы таким способом собираемся тестировать прикладное ПО? Достаточно, чтобы оно запускалось и работало на эмулируемой платформе.
Всё зависит от задачи которая перед нами стоит. Если мы хотим запустить конкретный эксплоит, то он может быть завязан на уязвимостях конкретной прошивки устройства, а это значит нам нужно запускать на нём. Ведь как показывает практика 70% уязвимостей Android — это уязвимости в прошивках устройств от вендоров. Официальный Android не такой дырявый и достаточно постоянно обновляется.
С другой стороны, такой подход будет производить более высокую нагрузку на исполнение, что сделает QEMU, а следовательно и эмулятор Android, легко обнаружимым (например, путем сравнения различных времён исполнения для конкретных операций, наблюдаемых в эмуляторе и реальном устройстве).
Так можно и время тикать подопытному медленнее. Ну и другие операции типа i/o тоже замедлить. В итоге если хорошо подобрать все коэффициенты замедления, то отличить будет очень сложно.
Согласен, но представь если у нас замедленее в 10 раз и в приложение соединяется по сети и на сокетах установлен тайм-аут и если у нас очень медленно работает приложение сокеты вылетают по тайм-ауту. Или же значения времени берётся по зашифрованному каналлу по сети. Так что и да, и нет одновременно.
Так ведь и сеть может быть ненастоящая, с задержками специально подобранными!
Ну или вместо гигабитного 4G будет канал через VPN по Bluethooth с сервером на другом полушарии.

Вообще, проверки типа «внутри кастрюли я или нет», основанные на измерении времени, крайне чувствительны ко всему подряд и ведут ложноположительным срабатываниям, и при этом принципиально ничем не лучше чисто функциональных тестов. То железо изменится, то планировщик ОС что-то по-другому сделает, и все задержки сдвинутся в ту или другую сторону.

Существует печальный пример защиты от копирования Starforce, в том числе использовавшей измерения времён доступов к приводу для различения виртуальных и реальных.

А вот тест на распределение времён обработки прерываний (привязанных в случае ДТ к границам базового блока) выглядит прикольным, потому что использует не само время как таковое, а относительный порядок событий, и фактически требует проверки статистической гипотезы.
Хотя, опять же, ничто не мешает написать такой ДТ, который обрабатывает доставку прерываний более равномерно и при этом работает лишь чуть медленнее.

Согласен, многие недостатки указанные в статье можно исправить. Правда второй тест с самомодифицирующимся кодом исправить намного сложнее чем тест с прерываниями, и поскольку я не специалист в бинарной трансляции я не скажу как, хотя возможно уже есть решения. Данная же статья лишь отражает текущее положение дел и показывает векторы развития. На текущий момент мы имеем что все песочницы «палятся». Особенно печальным мне кажется что палится Google Bouncer, которым проверяют приложения в маркете. А это значит залить вредоносное приложение в маркет не составляет труда. Обфусцировать его, чтобы никто не догодался что на самом деле делает приложение и ву-а-ля, отличный вектор атаки.
> Правда второй тест с самомодифицирующимся кодом
А вот это вообще уже не тест, а криминал — софт использует неопределённое поведение железа. При отсутствии вызовов cacheflush в исполняться будет не f1 или f2, а чаще всего смесь этих функций — часть байт из одной, часть — из другой, т.е. мусор. Опять же содержимое страницы будет зависеть от размера кэш-линии, политик вытеснения и замещения, иерархии кэшей, т.е. от марки ЦПУ, вендора, варианта микроархитектуры и прочих факторов. Да и вообще кэш может быть вырублен.
Т.е. на одной железке это будет работать, а на другой — нет. Ложноположительные срабатывания на аппаратуре, отличной от использованной при разработке, обеспечены.

мне кажется функция достаточно маленькая и умешается в одну страницу кэша, хотя я могу ошибаться. Так что варианта, что будет испольняться часть кода одной функции и часть другой мне кажется не будет. Самомодифицирующийся код никакой не криминал, а нормальная ситуация для малвари. Если этот код будет работать на более чем 50% устройств, я думаю авторов малвари это устроит) Но мне всё же кажется, что поведение на реальном оборудовании всегда будет отличаться от поведения в эмуляторе, потому что кэш на реальном устройстве не обновляется сразу и я не верю в то, что он может быть выключен, потому что иначе всё будет работать дико медленно и такие телефоны и устройства вряд ли кому нужны.
>мне кажется функция достаточно маленькая и умешается в одну страницу кэша
Если размер линии определён архитектурно, то да. В таком случае Qemu может повторять логику железа и просто моделировать кэш-линии. Это будет несколько накладно, однако вполне реализуемо. Симулятор уже следит за страницами, может следить и за более мелкими единицами, особенно если они связаны с кодом, а не с данными.
Если размер кэш-линии не задан архитектурно, то он может быть и 2 байта, и 16, и 1024, и 8192. Нельзя думать, что если сейчас все кэш-линии размером в 16 байт, то завтра (буквально завтра, как часто и бывает!) не будет выпущена серия процов с размеров кэш-линии в 8 байт или в 64 байта.

> Самомодифицирующийся код никакой не криминал
Дело не в SMC, а в отсутствии гарантий на когерентность содержимое кэша и памяти. SMC не только для малвари нужен. Опять же, где гарантии, что на аппаратуре «на мобильном устройстве наблюдалась случайная последовательность вызовов» — ведь последовательность f1 f1 f1 f1 f1 f1 f1 тоже вполне валидная выборка для случайной последовательности. Т.е. опять же требуется проверка статистической гипотезы. Но нужно отметить, что этот противоотладочный метод известен довольно давно, значит, он на практике эффективен.

>поведение на реальном оборудовании всегда будет отличаться от поведения в эмуляторе
never say «never». Дело в том, что чёткой границы «симулятор-реальность» не существует.

> я не верю в то, что он может быть выключен
Это да, кэш никто в здравом уме на телефонах отключать не будет. Но вот от девайса к девайсу его характеристики и алгоритмы могут отличаться в разы.
Механизм работы бинарной трансляции устроен таким образом, что он отслеживает изменения оперативной памяти и оттранслированный блок сразу аннулируется и вытесняется из кэша, как только произошло изменение памяти на которую он ссылался. Именно поэтому в эмуляторе всегда будет f1 f2 f1 f2 f1 f2. Да, я согласен что это поведение также можно изменить, просто это сложнее и тут нужно хорошее понимание алгоритма бинарной трансляции. Но ничего невозможно нет, тут ты прав) И никогда не говори никогда, тоже соглашусь с тобой. Про «случайную последовательность» я думаю они имели ввиду, что на их устройствах так. Но даже если будет f1 f1 f1 f1 f1, мы сможем отличить её от последовательности эмулятора f1 f2 f1 f2 f1 f2. Гарантий что это будет работать устройствах я дать не могу, как и авторы статьи вроде бы тоже их не дают. Они дают всего лишь набор эвристик, которые работают у них.
>что он отслеживает изменения оперативной памяти и оттранслированный блок сразу аннулируется и вытесняется из кэша
Можно привязать инвалидацию блоков трансляции к выполнению той самой инструкции cacheflush, а до того момента задерживать перетрансляцию кода в модифицированных секциях. Такое поведение, как и оригинальное с энергичной инвалидацией, будет удовлетворять спецификациям аппаратуры, которая не гарантирует консистентности кода до выполнения cacheflush, но и не запрещает её. Даже может быть в производительности чуть-чуть выиграем. Но соглашусь, такой путь усложняет модель.
Не рекламы ради. Моя подруга из университета Люксембурга ищет как-раз PhD студента (аспиранта по-нашему) и Post-Doc'а на проект, основная цель которого как-раз определять вирусы, в которых содержится подобная функциональность (context-sensitive mobile malware detection). Знаю, что здесь очень много толковых ребят, так что если есть интерес, то пишите мне в личку — дам подробные объяснения и контакты.
Sign up to leave a comment.

Articles