- Русские Блоги
- Zygote для Android
- Что такое зигота
- Процесс запуска Zygote
- Запустите виртуальную машину
- Зарегистрировать метод JNI
- 1) метод registerZygoteSocket ()
- 2) предварительная загрузка системных ресурсов, метод preload ();
- 3 startSystemServer () запускает процесс SystemServer
- 4) метод runSelectLoop ()
- Новое семейство Android-троянов Triada модифицирует процесс Zygote
- Русские Блоги
- Исходный код Android 8.1_startup (два) — исследование zygote
- Исходный код Android 8.1_startup (two) — углубленное изучение зиготы
- Предисловие
- Открытие
- Основной исходный код
- Введение в зиготу
- Read The Fucking Code
- Триггер зиготы
- init.zygoteXX.rc
- start zygote
- app_process
- AndroidRuntime
- Отражение старт ZygoteInit
- ZygoteInit
- Создать серверный сокет
- Предварительная загрузка
- Запустите процесс SystemServer
- Обработка информации запроса
Русские Блоги
Zygote для Android
Что такое зигота
Zygote — это сервис-демон. SystemServer и все другие процессы виртуальной машины Dalvik разрабатываются Zygote.
Zygote — это самый важный процесс в Android и процесс Init. Процесс SystemServer — это три полюса, которые поддерживают мир Android. Процесс Zygote запускается как служба в процессе Init.
Zygote — это модель C / S. Процесс Zygote выступает в качестве сервера, а другие процессы выступают в качестве клиентов для отправки ему «инкубационных» запросов. Zygote «инкубирует» новый процесс после получения этого запроса. Как показано на рисунке, при щелчке по значку приложения в Launcher для запуска нового процесса приложения запрос достигает основной службы ActivityManagerService уровня платформы. Когда AMS получает этот запрос, он выполняет вызов, вызывая класс Process. «Зафиксируйте» запрос сокета дочернего процесса, и Zygote разветвляет новый процесс сразу после прослушивания этого запроса.
Процесс запуска Zygote
Основной файл, соответствующий процессу Zygote, это app_main.cpp. Когда он запускается процессом Init, он входит в функцию main () основного файла app_main.cpp. Затем его основная функция начинает анализ запуска процесса Zygote:
Наконец, функция main () вызывает функцию start () среды выполнения. Runtime — это объект AppRuntime. Взгляните на класс AppRuntime:
Класс AppRuntime наследует класс AndroidRuntime, поэтому функция start () среды выполнения, вызванная ранее, войдет в функцию start () AndroidRuntime. Взгляните на функцию ниже:
Функция start () AndroidRuntime в основном выполняет следующие три функции:
1. Вызовите функцию startVM (), чтобы запустить виртуальную машину.
2. Вызовите функцию startReg (), чтобы зарегистрировать метод JNI.
3. Вызовите функцию main () класса com.android.internal.os.ZygoteInit (если это дочерний процесс, вызовите функцию main () com.android.internal.os.RuntimeInit Это в основном завершает инициализацию. Основная функция процесса Zygote имеет следующие 5 задач)
Далее описывается конкретная работа трех функций одна за другой:
Запустите виртуальную машину
Запустите виртуальную машину, вызвав функцию startVM ():
Зарегистрировать метод JNI
В Android мир Java использует механизм JNI для вызова функций в собственном мире, а механизм JNI также широко используется в системе Android.В системе Android для регистрации используется следующая функция startReg ():
Функция startReg () дополнительно регистрируется путем вызова функции register_jni_procs (). Переданное значение — массив gRegJNI. Версия Android 6.0 имеет более 130 массивов, как показано ниже:
JNI, перечисленные выше, регистрируются с помощью функции register_jni_procs ():
Зарегистрируйте все функции JNI через цикл. , ,
ZygoteInit отвечает за инициализацию Zygote. Вот основной метод класса ZygoteInit
1) Зарегистрируйте порт сокета в zygote для прослушивания
2) предварительная загрузка системных ресурсов;
3) Запустите процесс SystemServer;
4) войти в цикл прослушивания и получения сообщений;
Взгляните на эти четыре метода по очереди:
1) метод registerZygoteSocket ()
Создайте локальный сокет, а затем дождитесь вызова runSelectLoop (), чтобы войти в цикл, ожидающий сокет для ожидания соединения;
2) предварительная загрузка системных ресурсов, метод preload ();
Сначала посмотрите на карту общей памяти процесса приложения Android
Из приведенного выше рисунка легко понять, что после того, как процесс Zygote предварительно загружает системные ресурсы, он затем штрихует другие процессы виртуальной машины, а затем разделяет память виртуальной машины и ресурсы уровня структуры, что значительно повышает скорость запуска и запуска приложений. Теперь посмотрим на метод preload ();
В основном предварительная загрузка различных системных ресурсов, в основном см. 2.1) предварительная загрузка системных классов; 2.2) предварительная загрузка системных ресурсов; 2.3) предварительная загрузка, так что библиотека
Прочитайте файлы в файле PRELOADED_CLASSES, получите объект InputStream, преобразуйте его в BufferedReader, построчно прочитайте содержимое файла, передайте trim (), отфильтруйте пустые строки, а затем вызовите метод Class.forName () для загрузки информации о классе Java Вместо создания объекта;
2.2 preloadResources (); предварительная загрузка системных ресурсов
2.3 preloadSharedLibraries (); загрузка системных общих библиотек
3 startSystemServer () запускает процесс SystemServer
Было выполнено три основных действия: 3.1) Подготовить параметры для запуска процесса SystemServer. Вы можете видеть, что ProcessId и Group Id SystemServer оба равны 1000. Класс выполнения SystemServer — com.android.server.SystemServer; 3.2) Форкировать процесс SystemServer; 3.3) После того, как процесс SystemServer разветвлен, инициализируйте процесс SystemServer;
3.1 метод handleSystemServerProcess ()
4) метод runSelectLoop ()
Это делает две основные вещи:
4.1) Принять запрос на соединение, i = 0, это означает, что событие запроса на соединение наступило, вызвать acceptCommandPeer (), чтобы установить соединение с клиентом через сокет, а затем присоединиться к массиву прослушивания, ожидая прибытия команды на этом сокете;
4.2) Принять сообщение; i> 0 означает, что у уже подключенного сокета есть данные. После вызова метода runOnce () класса ZygoteConnection соединение с клиентом будет отключено и удалено из прослушивающего массива;
Источник
Новое семейство Android-троянов Triada модифицирует процесс Zygote
Ранее трояны, использующие процесс Zygote, были представлены только в виде PoC-кода.
Исследователи безопасности «Лаборатории Касперского» обнаружили новое семейство уникальных в своем роде троянов для Android под общим названием Triada, столь же опасных, как и вредоносные программы для Windows. Triada является незаметным, модульным и стойким вредоносным ПО. По словам исследователей, трояны созданы высококвалифицированными киберпреступниками.
Вредоносы могут модифицировать SMS-сообщения, отправленные другими приложениями. Когда пользователь делает внутриигровые покупки с помощью SMS, мошенники изменяют исходящие сообщения и получают деньги вместо разработчиков.
Triada работает незаметно для пользователей. После попадания на устройство вредонос находится в оперативной памяти и внедряется почти в каждый рабочий процесс. Для получения персистентности троян модифицирует Zygote — родительский процесс для всех Android-приложений, содержащий используемые ими системные библиотеки и фреймворки. Подобное вредоносное ПО, активно используемое злоумышленниками, было зафиксировано впервые. Ранее трояны, эксплуатирующие процесс Zygote, были представлены только в виде PoC-кода.
Triada распространяется через приложения, устанавливаемые пользователями из ненадежных источников. Загрузчики программ и установочные модули связаны с различными троянами, но они были добавлены в антивирусную базу «Лаборатории Касперского» под общим названием Triada.
Наиболее уязвимы смартфоны и планшетные ПК под управлением Android 4.4.4. и более ранних версий мобильной ОС. Android-устройства на базе версий выше 4.4.4 имеют меньше эксплуатируемых Triada уязвимостей.
Источник
Русские Блоги
Исходный код Android 8.1_startup (два) — исследование zygote
Исходный код Android 8.1_startup (two) — углубленное изучение зиготы
Предисловие
В Android зигота — это основной процесс создания новых процессов во всей системе. Процесс зиготы сначала запустит виртуальную машину Dalvik изнутри, затем загрузит некоторые необходимые системные ресурсы и системные классы и, наконец, войдет в состояние мониторинга. В последующих операциях, когда другие системные модули (например, AMS) хотят создать новый процесс, им нужно только отправить запрос процессу зиготы. После того, как процесс зиготы прослушает запрос, он соответственно создаст новый процесс, поэтому этот новый процесс. Когда он родился, у него была собственная виртуальная машина Dalvik и системные ресурсы.
Открытие
Основной исходный код
Ключевая категория | дорожка |
---|---|
init.rc | system/core/rootdir/init.rc |
init.cpp | system/core/init/init.cpp |
init.zygote64.rc | system/core/rootdir/init.zygote64.rc |
builtins.cpp | system/core/init/builtins.cpp |
service.cpp | system/core/init/service.cpp |
app_main.cpp | frameworks/base/cmds/app_process/app_main.cpp |
AndroidRuntime.cpp | frameworks/base/core/jni/AndroidRuntime.cpp |
JniInvocation.cpp | libnativehelper/JniInvocation.cpp |
ZygoteInit.java | frameworks/base/core/java/com/android/internal/os/ZygoteInit.java |
ZygoteServer.java | frameworks/base/core/java/com/android/internal/os/ZygoteServer.java |
Введение в зиготу
В системе Android JavaVM (виртуальная машина Java), процесс приложения и процесс SystemServer, который запускает ключевые службы системы, создаются процессом Zygote, и мы также называем его инкубатором. Он создает процессы приложений и процессы SystemServer в форме fock (процесс копирования). Поскольку процесс Zygote создает JavaVM при запуске, процесс приложения и процесс SystemServer, созданные fock, могут внутренне получать копию экземпляра JavaVM.
Read The Fucking Code
Триггер зиготы
Анализируя процесс init, мы знаем, что после запуска процесса init он проанализирует файл init.rc, а затем создаст и загрузит процесс, указанный в поле service. Таким образом, процесс zygote загружается процессом init.
В начале system / core / rootdir / init.rc вы можете увидеть:
init.zygoteXX.rc
Из предыдущего анализа статьи об инициализации мы знаем, что на разных платформах (32, 64 и 64_32) init.rc будет содержать разные файлы zygote.rc. В каталоге system / core / rootdir находятся init.zygote32_64.rc, init.zyote64.rc, init.zyote32.rc и init.zygote64_32.rc.
✨init.zygote32.rc: Программа выполнения, соответствующая процессу зиготы, — это app_process (чистый 32-битный режим)
init.zygote64.rc: программа выполнения, соответствующая процессу zygote, — app_process64 (чистый 64-разрядный режим).
init.zygote32_64.rc: запустить два процесса zygote (с именами zygote и zygote_secondary), соответствующие программы выполнения — app_process32 (основной режим), app_process64
init.zygote64_32.rc: запустить два процесса zygote (с именами zygote и zygote_secondary), соответствующие программы выполнения — app_process64 (основной режим), app_process32
Зачем определять столько ситуаций? Недостаточно определить его напрямую, это в основном потому, что Android 5.0 начинает поддерживать 64-разрядные программы и определяется таким образом только для совместимости с 32-разрядными и 64-разрядными версиями. Содержимое разных zygote.rc примерно одинаково, основная разница заключается в том, следует ли запускать 32-битный или 64-битный процесс. init.zygote32_64.rc и init.zygote64_32.rc запускают два процесса с первичной и вторичной точками.
Взять здесь64-битный процессорНапример, код init.zygote64_32.rc выглядит следующим образом:
start zygote
После того, как служба определена, должно быть место для вызова стартовой зиготы. В предыдущем блоге, посвященном анализу инициализации, мы проанализировали запуск процесса инициализации. В конце запуска процесса инициализации будет сгенерировано событие «late-init».
Соответствуя конфигурационному файлу system / core / rootdir / init.rc, находим следующий код:
Соответствуя конфигурационному файлу init.rc, мы находим следующий код
У команды start есть соответствующая функция выполнения do_start, которая определена в platform / system / core / init / builtins.cpp.
Взглянем на do_start ():
Do_start сначала проходит массив службы через FindServiceByName, сопоставляет соответствующую службу по имени, а затем вызывает функцию Start службы.
Наконец, давайте взглянем на функцию Start, определенную в service.cpp:
Функция Start в основном предназначена для разветвления нового процесса, затем выполнения двоичного файла, соответствующего службе, и передачи параметров. Итак, возьмем init.zygote64.rc в качестве примера для анализа.
app_process
Из файла init.zygote64.rc, который мы проанализировали выше, видно, что адрес файла запуска zygote64 — app_process64. Код, соответствующий app_process64, определен в frameworks / base / cmds / app_process,
Взглянем на соответствующий Android.mk: frameworks / base / cmds / app_process
Фактически, будь то app_process, app_process32 или app_process64, соответствующий исходный файл — app_main.cpp.
Далее мы рассмотрим основную функцию, соответствующую app_process, которая определена в app_main.cpp.
В основной функции app_main.cpp главное, что нужно сделать — это проанализировать параметры.Эта функция имеет два режима запуска:
✨ Один из них — это режим зиготы, который предназначен для инициализации процесса зиготы. Передаваемые параметры: —start-system-server —socket-name = zygote. Первый означает запуск SystemServer, а второй указывает имя сокета. (Zygote64_32).
✨ Один из них — это режим приложения, который запускает обычное приложение. Передаваемые параметры включают имя класса и параметры класса.
Оба в конечном итоге вызывают функцию запуска объекта AppRuntime, загружают два Java-класса ZygoteInit или RuntimeInit и передают ранее отсортированные параметры.
Мы пока будем объяснять только процесс загрузки ZygoteInit.
AndroidRuntime
Поскольку AppRuntime наследуется от AndroidRuntime и не переопределяет метод запуска, процесс zygote входит в frameworks / base / core / jni / AndroidRuntime.cpp.
Затем давайте посмотрим на последовательность запуска функции AndroidRuntime.
Здесь мы следуем jni_invocation.Init (): libnativehelper / JniInvocation.cpp
Основная функция функции Init — инициализировать JNI. Конкретная работа заключается в том, чтобы сначала загрузить libart.so через dlopen, чтобы получить его дескриптор, а затем вызвать dlsym, чтобы найти три адреса функций: JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM и JNI_GetCreatedJavaVMs из libartJavaVMs. , и назначьте их соответствующим свойствам элемента.Функция будет вызываться при последующем создании виртуальной машины.
Во-вторых, проследим startVm ():
Эта функция очень длинная, но то, что она делает, очень проста. Фактически, она считывает некоторые параметры из различных системных свойств, а затем сохраняет их в массиве mOptions AndroidRuntime через addOption. Другой способ — найти JNI_CreateJavaVM из libart.so перед вызывая функцию и передайте эти параметры.
startReg сначала настраивает функцию обработки потока создания Android, затем создает локальную ссылочную область размером 200, чтобы гарантировать, что OutOfMemoryException не возникает, и, наконец, вызывает register_jni_procs для регистрации JNI.
Следуем с помощью startReg ():
Как видно из приведенного выше кода, функция startReg в основном регистрирует функцию JNI через register_jni_procs. Среди них gRegJNI — это глобальный массив, который определяется следующим образом:
Мы выбираем register_com_android_internal_os_ZygoteInit_nativeZygoteInit, который на самом деле является стандартным способом настройки функций JNI и их динамической регистрации.
внутренне вызывает RegisterNatives JNI, поэтому после регистрации собственный метод nativeZygoteInit класса Java ZygoteInit вызовет функцию com_android_internal_os_ZygoteInit_nativeZygoteInit.
Определение макроса, соответствующее REG_JNI, и определение структуры RegJNIRec:
Согласно определению макроса, макрос REG_JNI получит имя функции; при определении массива RegJNIRec имя функции присваивается структуре RegJNIRec, поэтому каждое имя функции принудительно преобразуется в указатель функции.
Следовательно, параметр register_jni_procs представляет собой массив указателей на функции, размер массива и JNIEnv.
Давайте продолжим с функцией register_jni_procs:
В сочетании с предыдущим анализом легко узнать, что функция register_jni_procs на самом деле вызывает функцию, соответствующую указателю функции (mProc), для выполнения фактической регистрации функции JNI.
Отражение старт ZygoteInit
Продолжаем анализировать функцию запуска AndroidRuntime.cpp:
Как видите, в конце AndroidRuntime основная функция ZygoteInit будет вызываться через отражение. Так далеко,Процесс зиготы вошел в мир Java。
Фактически, если мы подумаем об этом внимательно, мы почувствуем, что весь процесс зиготы на самом деле очень соответствует реальной ситуации.
✨✨ В Android каждый процесс выполняется на соответствующей виртуальной машине, поэтому за создание виртуальной машины в первую очередь отвечает зигота.
✨✨ Затем, чтобы рефлексивно вызывать java-код, должна быть соответствующая функция JNI, поэтому zygote зарегистрировала функцию JNI.
✨✨ Когда все будет готово, процесс зиготы перейдет в мир Java.
ZygoteInit
Теперь проследим за основной функцией ZygoteInit.java.
Вышеупомянутое является основной частью основной функции ZygoteInit. Помимо контента, связанного с безопасностью, основная работа заключается в регистрации сокета сервера, предварительной загрузке, запуске системного сервера и входе в бесконечный цикл для обработки сообщений запроса.
Далее мы обсудим это отдельно в четырех частях!
Создать серверный сокет
Android O переносит работу, связанную с серверным сокетом, в /frameworks/base/core/java/com/android/internal/os/ZygoteServer.java. Давайте посмотрим на функцию registerZygoteSocket:
Мы отслеживаем LocalServerSocket () в /framework//core/java/android/net/LocalServerSocket.java:
Предварительная загрузка
Посмотрим на содержимое предварительной загрузки (zygoteinit.java):
Чтобы сделать фактическую работу системы более плавной, при запуске зиготы вызывается функция предварительной загрузки для выполнения некоторых операций предварительной загрузки. Android создает дочерние процессы через вилку zygote. Процесс zygote предварительно загружает эти классы и ресурсы.Если дочерний процесс является fork, требуется только одна копия.
Это может сэкономить время запуска дочернего процесса. В то же время, согласно механизму копирования при записи fork, если некоторые классы не изменяются или даже не копируются, дочерний процесс может совместно использовать эту часть данных с родительским процессом, тем самым экономя много памяти.
Запустите процесс SystemServer
Давайте посмотрим на процесс запуска System Server (zygoteinit.java):
Обработка информации запроса
После создания процесса SystemServer процесс zygote вызывает функцию runSelectLoop в ZygoteServer для обработки команд, полученных серверным сокетом.
Из приведенного выше кода видно, что изначально в fds есть только серверный сокет, поэтому при поступлении данных будет выполнена ветвь с i, равным 0. На этом этапе ясно, что необходимо создать новое коммуникационное соединение, поэтому будет вызван acceptCommandPeer.
Смотрим на функцию acceptCommandPeer:
Из приведенного выше кода мы видим, что acceptCommandPeer вызывает функцию accpet серверного сокета. Поэтому, когда новое соединение установлено, zygote создаст новый сокет для связи с ним и добавит сокет в fds. Следовательно, как только коммуникационное соединение установлено, в fds будет несколько сокетов.
Когда опрос отслеживает поступление данных в этот набор сокетов, он восстанавливается после блокировки. Следовательно, нам нужно определить, какой сокет получил данные.
В runSelectLoop используется метод обратного опроса. Поскольку серверный сокет добавляется к fds первым, последний опрошенный сокет должен обрабатывать операцию создания нового соединения; когда другие сокеты получают данные, им нужно только вызвать функцию runonce zygoteConnection, чтобы выполнить операцию, соответствующую к данным. Если соединение обработало все соответствующие сообщения, сокет и соединение, соответствующие соединению, будут удалены.
Давайте посмотрим на дескриптор в функции forksystemserver в zygoteinit.java.
Мы видим, что программа передает версию sdk, параметры процесса разделения и т. Д., А затем вызывает функцию zygoteinit. Давайте проследим за функцией
Эта функция, наконец, вызывает функцию applicationinit в runtimeinit
Выше представлен весь процесс запуска, обратитесь к коду жертвы и соответствующим образом дополните часть контента. Для изучения и цитаты, пожалуйста, простите меня за любые нарушения.
Источник