что такое smali код
Шпаргалка по Smali на русском
Приветствую, любители реверс-инжинирить Android. Перед вами шпаргалка по Smali — аналогу ассемблера для Android-приложений.
Изначальный текст на русском взят отсюда. Там текст появился из машинного перевода официальной документации.
В итоге, оформил сухой текст + поправил небольшие опечатки и корявости перевода. По поводу замечаний и предложений можете писать либо мне в ЛС, либо оформлять PR на Gist.
Общая информация
Виды(Types)
Байт-код Dalvik имеет два основных класса типов: примитивные типы и ссылочные типы. Типы ссылок — это объекты и массивы, все остальное является примитивным.
Примитивы представлены одной буквой:
Объекты принимают форму Lpackage/name/ObjectName; — где ведущий L указывает, что это тип объекта, package/name/ — это пакет, в котором находится объект, ObjectName — это имя объекта и ; обозначает конец имени объекта.
Это эквивалентно имени package.name.ObjectName в java. Или, для более конкретного примера, Ljava/lang/String; эквивалентно java.lang.String
Вы также можете иметь массивы объектов, [Ljava/lang/String; будет массив строк.
Методы(Methods)
Методы всегда указываются в очень подробной форме, которая включает тип, содержащий метод, имя метода, типы параметров и тип возвращаемого значения. Вся эта информация необходима, чтобы виртуальная машина могла находить правильный метод и иметь возможность выполнять статический анализ на байт-коде
Они принимают форму Lpackage/name/ObjectName;->MethodName(III)Z
В этом примере вы должны распознать Lpackage/name/ObjectName; как тип. MethodName — это имя метода. (III)Z является сигнатурой метода. III — параметры (в данном случае 3 целых числа), а Z — тип возврата (bool).
Параметры метода перечислены один за другим, без разделителей между ними.
Вот более сложный пример:
В Java, это было бы
Поля(Fields)
Поля также всегда указывается в многословной форме, которая включает тип, содержащее поле, имя поля и тип поля. Опять же, это позволяет виртуальной машине находить правильное поле, а также выполнять статический анализ на байт-коде.
Они принимают форму Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
Это должно быть довольно очевидно — это пакет и имя объекта, имя поля и тип поля соответственно
Регистры (Register)
Вступление
В байт-коделе dalvik регистры всегда 32 битные и могут содержать любой тип значения. 2 регистра используются для хранения 64-битных типов (длинного — Long и числа с плавающей точкой — Double).
Указание количества регистров в методе
Как параметры метода передаются в метод:
Первым параметром для нестатических методов ( non-static methods ) всегда является объект, на который вызывается метод ( this объект)
Для статических методов ( static methods ) это одно и то же, за исключением того, что неявный этот аргумент.
Регистрация имен (Register names)
Существует две схемы именования для регистров — обычная схема именования v# и схема именования p# для регистров параметров. Первый регистр в схеме именования p# является первым регистром параметров в методе.
Итак, вернемся к предыдущему примеру метода с 3-мя аргументами и 5-ю полными регистрами. В следующей таблице показано обычное имя v# для каждого регистра, за которым следует имя p# для регистров параметров ( parameter registers )
v# | p# | |
---|---|---|
v0 | Первый локальный регистр | |
v1 | Второй локальный регистр | |
v2 | p0 | Первый регистр параметров |
v3 | p1 | Второй регистр параметров |
v4 | p2 | Третий регистр параметров |
Вы можете ссылаться на регистры параметров по имени — это не имеет никакого значения.
Введения регистров параметров ( parameter registers )
Но если схема именования p# использовалась для ссылки на регистры параметров во всем методе, вы можете легко изменить количество регистров в методе, не беспокоясь о перонумеровании любых существующих регистров.
Long/Double значения
Кроме того, когда вы вызываете метод позже, вам нужно указать оба регистра для любых аргументов с двойным расширением в списке регистров для инструкции типа invoke.
Array (массивы)
array-length vA, vB
Сохраняет длину (количество записей) указанного массива vB в vA
fill-array-data vA+, :target
Пример таблицы данных:
new-array vA+, vB, Lclass;->type
Создает новый массив указанного типа и размера. Тип должен быть типом массива.
filled-new-array < vA [ vB, v. vX ]>, Lclass;->type
Array Accessors (приемники массивов)
Сохраняет целое ( integer ) значение от vA в массиве, на который ссылается vB на индекс vC
Например: aget-objec (Получает объект( object ))
Сравнения
cmp-long vA, vB+, vC+
Сравнивает длинные (long) значения в исходных регистрах, сохраняя 0
cmpg-double vA, vB+, vC+
Сравнивает числа с плавающей точкой (double) значения в исходных регистрах, сохраняя 0
cmpg-float vA, vB, vC
Сравнивает значения с плавающей(float) запятой в исходных регистрах, сохраняя 0;
cmpl-double vA, vB+, vC+
Сравнивает double значения в исходных регистрах, сохраняя 0;
cmpl-float vA, vB, vC — выполняет указанное сравнение с плавающей(float) запятой, сохраняя 0;
Константы
const vAA, #+BBBBBBBB
const/16 vAA, #+BBBB
Заносит #+BBBB в регистр vAA
const/4 vA, #+B
const/high16 vAA, #+BBBB
const-class vAA, Lclass
const-string vAA, «BBBB»
Переместит ссылку на строку, указанную в регистре назначения vAA
const-string/jumbo vAA, «BBBBBBBB»
Переместит ссылку на строку, указанную в регистре назначения vAA
jumbo — обозначает, что значение будет «большим»
Еще примеры:
const-wide/16 vA+, #+BBBB
const-wide/high16 vA+, #+BBBB
const-wide vA+, #+BBBBBBBBBBBBBBBB
Go To
goto — Безусловный переход к :target.
Только замена не может производиться на оборот: goto не может заменить goto/16, а он в свою очередь не может заменить goto/32.
Условия
if — Если выполняется условие, происходит переход по метке
Примеры:
Invoke
Вызывает метод интерфейса ( interface method ) (то есть объект, чей конкретный класс неизвестен, используя метод, который ссылается на интерфейс):
Вызывает статический метод ( static method ) (который всегда считается прямым методом):
Вызывает виртуальный метод ( virtual method ) непосредственного родительского класса:
Вызывает виртуальный метод ( virtual method ) (метод, который не является статическим или окончательным, и не является конструктором):
Примечание:
Если метод возвращает значение ( R не является « V » для Void), он должен быть зафиксирован в следующей строке одним из операторов move-result или он будет потерян.
И так можно делать с любым выше перечисленным invoke:
Прочее
check-cast vAA, Lclass
instance-of vA, vB, Lclass
new-instance vAA, Lclass
Пустая команда/Нет операции
throw vAA
Прим: A: x bits. B: x bits не является частью кода. Добавил только для обозначения бит в регистрах
move vA, vB
Перемещает содержимого одного регистра не-объекта (non-object) к другому.
move/16 vAAAA, vBBBB
A: 16 bits. B: 16 bits
move/from16 vAA, vBBBB
A: 8 bits. B: 16 bits
move-exception vAA
move-object vA, vB
Перемещает содержимое одного объекта, несущего регистра в другой.
move-object/16 vAAAA, vBBBB
A: 16 bits. B: 16 bits
move-object/from16 vAA, vBBBB
A: 8 bits. B: 16 bits
move-result vAA
move-result-object vAA
Остальное кратко:
Операции
Оператор ADD
Cкладывает значения по обе стороны от оператора
add-double vA+, vB+, vC+
Вычисляет vB+ + vC+ и сохраняет результат в vA+
add-double/2addr vA+, vB+
Вычисляет vA + vB и сохраните результат в vA+
add-float vA, vB, vC
Вычисляет vB + vC и сохраняет результат в vA
add-float/2addr vA, vB
Вычисляет vA + vB и сохраняет результат в vA
add-int vA, vB, vC
Вычисляет vB + vC и сохраняет результат в vA
add-int/lit8 vA, vB, 0xC
Вычисляет vB + 0xC и сохраняет результат в vA
add-int/lit16 vA, vB, 0xC
Вычисляет vB + 0xC и сохраняет результат в vA
add-int/2addr vA, vB
Вычисляет vA + vB и сохраняет результат в vA
Оператор AND
Бинарный оператор копирует бит в результат, если он существует в обоих операндах.
Оператор DIV
Делит левый операнд на правый операнд
Оператор MUL
Умножает значения по обе стороны от оператора
Оператор OR
Копирует бит, если он существует в любом из операндов.
Оператор REM
Делит левый операнд на правый операнд и возвращает остаток
Оператор SHL
Значение левых операндов перемещается влево на количество бит, заданных правым операндом.
Оператор SHR
Значение правых операндов перемещается вправо на количество бит, заданных левых операндом.
Оператор SUB
Вычитает из правого операнда левый операнд
Оператор USHR
Оператор XOR
копирует бит, если он установлен в одном операнде, но не в обоих.
Return
Оператор return используется для выполнения явного возврата из метода. То есть он снова передает управление объекту, который вызвал данный метод. Оператор return предписывает интерпретатору остановить выполнение текущего метода. Если метод возвращает значение, оператор return сопровождается некоторым выражением. Значение этого выражения становится возвращаемым значением метода.
return vAA
Возврат из метода возвращаемого значения non-object со значением vAA.
return-object vAA
Возврат из метода object-returning с помощью object-reference в vAA.
return-void
Возврат из метода void без значения.
return-wide vA+
Switch-и
packed-switch vAA, :target
Легенда:
sparse-switch vAA, :target
Реализует оператор switch, где константы case не являются последовательными. В инструкции используется таблица поиска с константами case и смещениями для каждой константы случая. Если в таблице нет соответствия, выполнение продолжается в следующей команде (случай по умолчанию).
Русские Блоги
Глава 5 Статический анализ программ Android (1) (читать код smali)
Каталог статей
Статический анализ программ Android
Введение в статический анализ
Методы статического анализа программ Android
Читать код smali
файловая структура smali
Объявление класса
Комментарий
аннотация
метод
оператор цикла
Вторая форма состоит в том, чтобы вручную получить итератор, а затем вызвать hasNext () в итераторе в цикле, чтобы проверить, пуст ли он, и, наконец, вызвать его next () в теле цикла для обхода итератора.
Теперь декомпилируйте пример программы Circulate (пример кода:GitHub). Откройте файл MainActivity.smali в каталоге smali / com / droider / circate проекта декомпиляции и найдите метод iterator (). Код выглядит следующим образом:
В приведенном выше коде итератор () List вызывается для получения итератора списка процессов, а затем он входит в цикл итерации из goto_0. В цикле сначала вызывается hasNext () итератора, чтобы проверить, пуст ли итератор. Если итератор пуст, перейдите к cond_0 и вызовите Toas, чтобы вывести всю информацию о процессе; если итератор не пуст, это означает, что содержимое итератора еще не было выполнено, и для получения одного итератора необходимо вызвать next () RunningAppProcessInfo, а затем создайте новый временный StringBuilder, объедините имя процесса и символ новой строки и добавьте его в StringBuilder, созданный перед началом цикла, и, наконец, используйте оператор goto для перехода к началу цикла.
Можно видеть, что этот код очень похож на оператор цикла while, перечисленный ранее. Фактически, первый тип цикла итератора является реализацией цикла второго типа. Хотя их код Java отличается, сгенерированный код дизассемблирования очень похож. аналогичный
Особенности циклов итератора:
Цикл итератора вызывает hasNext () итератора, чтобы проверить, выполняются ли условия цикла.
Цикл итератора вызывает next () итератора для получения единственного объекта.
Цикл итератора использует инструкцию goto для управления потоком кода.
После того, как цикл итератора for-form развернут, это цикл итератора while-form
Далее идет традиционный цикл for. Посмотрите на forCirculate () в файле MainActivity.smali, код:
Особенности кода цикла:
Перед входом в цикл инициализируйте переменную счетчика цикла и измените ее значение в теле цикла.
Оценка условия цикла может быть законным утверждением, состоящим из инструкций условного перехода.
Используйте инструкцию goto для управления потоком кода в цикле
Структура циклов while и do while не сильно отличается. Код этих двух очень похож на код предыдущего цикла итератора, но расположение оценки условия цикла отличается.
оператор переключения ветви
инструкция try / catch
(0x503ac + 5 * 2) = 0x503ae
Русские Блоги
Обратный путь Android: глубокое понимание инструкций байт-кода Davilk и файлов Smali
Сегодня я представлю знания, связанные с виртуальной машиной Davilk. Во-первых, я познакомлю вас с байт-кодом Davilk, который нас больше всего беспокоит, а затем углублюсь в область обратного проектирования Android. Причина написания этой статьи Потому что есть девушки, которые хотят этому научиться, плюс в Интернете много информации слишком разрозненно и однобоко. Конечно, важнее резюмировать прошлое.
Вы можете следить за моим блогом, чтобы узнавать о моем настроенииРеки и озера называют маленьким белым братом
Дескриптор Davilk
Подобно JVM, байт-код Davilk также имеет набор методов для описания типов, методов и полей. Эти методы в сочетании с инструкциями Davilk образуют полный ассемблерный код.
Байт-код и тип данных
Байт-код Davilk имеет только два типа: базовые типы и ссылочные типы. Объекты и массивы являются ссылочными типами. Описание типов байт-кода в Davilk согласуется с правилами дескриптора в JVM: для базовых типов и void без возвращаемого значения Тип представлен заглавная буква, а тип объекта представлен буквой L плюс полное имя объекта. Массив представлен символом [, и конкретные правила таковы:
тип java | Дескриптор типа |
---|---|
boolean | Z |
byte | B |
short | S |
char | C |
int | I |
long | J |
float | F |
double | D |
void | V |
Тип объекта | L |
Тип массива | [ |
Здесь мы сосредоточимся на объяснении типов объектов и типов массивов:
Тип объекта
Тип массива
Описание поля
Описание метода
Для иллюстрации воспользуемся несколькими примерами, например java.lang.String:
Набор инструкций Davilk
Освоив описание вышеуказанных полей и методов, мы можем только сказать, что мы понимаем, как описывать поле и метод, а для конкретной логики в методе нам необходимо понимать набор инструкций в Dalvik. Поскольку Dalvik основан на Архитектура на основе регистров, набор инструкций Он сильно отличается от набора инструкций в JVM, но больше похож на инструкции сборки в x86.
Инструкции по определению данных
Инструкции по работе с данными
Команда перемещения используется для операций с данными, что означает перемещение пункта назначения, источника, то есть данные данных перемещаются из регистра источника (регистр источника) в регистр назначения (регистр источника), который может понимать операцию присваивания между переменными в java. • В зависимости от байт-кода и типа «Другой» за командой перемещения будет следовать другой суффикс.
инструкция | описание |
---|---|
move vA,vB | Назначьте значение регистра vB регистру vA, регистры vA и vB имеют 4 бита |
move/from16 vAA,VBBBB | Присвойте значение регистра vBBBB (16 бит) регистру vAA (7 бит), from16 указывает, что исходный регистр vBBBB составляет 16 бит |
move/16 vAAAA,vBBBB | Назначьте значение регистра vBBBB регистру vAAAA, 16 означает, что регистр источника vBBBB и регистр назначения vAAAA являются 16-битными. |
move-object vA,vB | Назначьте ссылку на объект в регистре vB регистру vA, регистр vA и регистр vB имеют 4 бита. |
move-result vAA | Назначьте одиночный (32-битный) не объектный результат предыдущей операции вызова инструкции (вызова метода) регистру vAA. |
move-result-wide vAA | Назначьте двойное слово (64-битный) не объектный результат предыдущей операции вызова инструкции регистру vAA |
mvoe-result-object vAA | Назначьте объектный результат предыдущей операции вызова инструкции регистру vAA |
move-exception vAA | Сохраните исключение, возникшее во время последнего запуска, в регистр vAA. |
Инструкции по эксплуатации объекта
Операции, связанные с экземплярами объекта, такие как создание объекта, проверка объекта и т. Д.
инструкция | описание |
---|---|
new-instance vAA,[email protected] | Создайте объект указанного типа и назначьте ссылку на устройство регистру vAA. Объекты массивов сюда не включаются. |
instance-of vA,vB,[email protected] | Определите, имеет ли ссылка на объект в регистре vB указанный тип, если это так, присвойте v1 значение 1, в противном случае присвойте ему значение 0 |
check-cast vAA,[email protected] | Преобразуйте ссылку на объект в регистре vAA в указанный тип и присвойте результат vAA в случае успеха, в противном случае будет выброшено исключение ClassCastException. |
Инструкции по работе с массивом
В примере инструкций по работе мы не нашли инструкции по созданию объекта, Davilk устанавливает специальную инструкцию для операций с массивами.
инструкция | Описание |
---|---|
new-array vA,vB,[email protected] | Создайте массив указанного типа и размера (заданного регистром vB) и назначьте его регистру vA. |
fill-array-data vAA,+BBBBBBBB | Заполните массив указанными данными, vAA представляет собой ссылку на массив (адрес первого элемента массива) |
Инструкции по работе с данными
Операции с данными в основном бывают двух типов: арифметические операции и логические операции.
1. Инструкции по арифметическим операциям
инструкция | Описание |
---|---|
add-type | Инструкция по добавлению |
sub-type | Инструкция по вычитанию |
mul-type | Инструкция умножения |
div-type | Инструкция по разделу |
rem-type | попрошайничество |
2. Инструкции по расчету логического элемента.
инструкция | Описание |
---|---|
and-type | И инструкция |
or-type | ИЛИ инструкция |
xor-type | Инструкция по вычислению элемента XOR |
3. Инструкции по перемещению
инструкция | Описание |
---|---|
shl-type | Подписанная инструкция сдвига влево |
shr-type | Подписанная инструкция сдвига вправо |
ushr-type | Беззнаковая инструкция сдвига вправо |
Сравните инструкции
Инструкции по эксплуатации в полевых условиях
Инструкции по работе с полями представляют собой установку и выборку полей объекта, как и ваши более длинные методы set и get в коде. Основные инструкции: iput-type, iget-type, sput-type, sget-type.type Представляет тип данных.
Операции чтения и записи обычных полей
Инструкции iput-type и iget-type с префиксом i используются для операций чтения и записи полей.
инструкция | Описание |
---|---|
iget-byte vX,vY,filed_id | Считайте значение поля filed_id в объекте в регистре vY и назначьте его регистру vX |
iput-byte vX,vY,filed_id | Установите значение поля filed_id в объекте в регистре vY равным значению регистра vX |
iget-boolean vX,vY,filed_id | |
iput-boolean vX,vY,filed_id | |
iget-long vX,vY,filed_id | |
iput-long vX,vY,filed_id |
Операции чтения и записи статического поля
Инструкции типа sput и sget с префиксом s используются для операций чтения и записи статических полей.
инструкция | Описание |
---|---|
sget-byte vX,vY,filed_id | |
sput-byte vX,vY,filed_id | |
sget-boolean vX,vY,filed_id | |
sput-boolean vX,vY,filed_id | |
sget-long vX,vY,filed_id | |
sput-long vX,vY,filed_id |
Инструкция по вызову метода
Большинство инструкций методов в Davilk очень похожи на инструкции в JVM. В настоящее время существует пять наборов инструкций:
Эти пять инструкций являются базовыми. Кроме того, вы также встретите инструкции invoke-direct / range, invoke-static / range, invoke-super / range, invoke-virtual / range, invoke-interface / range. Единственная разница между Тип и приведенные выше инструкции заключаются в том, что последние могут устанавливать диапазон регистров, который могут использовать параметры метода, который используется, когда имеется более четырех параметров.
Следует отметить, что если вы хотите получить возвращаемое значение выполнения метода, вам необходимо получить результат выполнения через указанную выше инструкцию move-result.
Инструкция возврата метода
В Java во многих случаях нам нужно вернуть результат выполнения метода через Return, а также инструкция возврата, предоставленная в Davilk, чтобы вернуть результат выполнения:
инструкция | Описание |
---|---|
return-void | Ничего не вернуть |
return vAA | Возвращает 32-битное значение не объектного типа. |
return-wide vAA | Возвращает 64-битное значение не объектного типа. |
return-object vAA | Ссылка на тип объекта |
Инструкция по синхронизации
инструкция | Описание |
---|---|
monitor-enter vAA | Получить операцию блокировки для указанного объекта |
monitor-exit vAA | Отменить операцию блокировки для указанного объекта |
Инструкция по исключению
Давным-давно виртуальная машина также использовала инструкции jsr и ret для реализации исключений, но теперь JVM выбросила исходный метод и вместо этого использует таблицы исключений для реализации исключений. Davilk по-прежнему использует инструкции для реализации:
инструкция | Описание |
---|---|
throw vAA | Бросить исключение указанного типа в регистр vAA |
Инструкция по прыжкам
Инструкции перехода используются для перехода от текущей адресной строки к указанному смещению и в основном используются в ветвях if и switch. Davilk предоставляет инструкции goto, Packaging-Switch и if-test для реализации операций перехода.
В условном сравнении тест в if-test представляет собой правило сравнения. Эта инструкция используется часто, поэтому мы просто садимся и объясняем:
инструкция | Описание |
---|---|
if-eq vA,vB,target | Регистры vA и vB равны, что эквивалентно if (a == b) в java. Например, if-eq v3, v10, 002c означает, что если условие истинно, переход к текущей позиции + 002c. Остальное похож |
if-ne vA,vB,target | Эквивалентно if (a! = B) в java |
if-lt vA,vB,target | Значение в регистре vA меньше vB, что эквивалентно if (a b) |
if-gt vA,vB,target | Эквивалентно if (a > b) |
if-ge vA,vB,target | Эквивалентно if (a >= b) |
if-le vA,vB,target | Эквивалентно if (a b) |
В дополнение к приведенным выше инструкциям Davilk также предоставляет условную инструкцию с нулевым значением, которая используется для сравнения с 0, что можно понимать как установку значения регистра vB в приведенной выше инструкции на 0.
инструкция | Описание |
---|---|
if-eqz vAA,target | Эквивалентно if (a == 0) или if (! A) в java |
if-nez vAA,target | Эквивалентно if (a! = 0) или if (a) в java |
if-ltz vAA,target | Эквивалентно if (a 0) |
if-gtz vAA,target | Эквивалентно if (a > 0) |
if-lez vAA,target | Эквивалентно if (a 0) |
if-gtz vAA,target | Эквивалентно if (a >= 0) |
Прикрепил:
Выше мы сказали, что есть две таблицы смещения, упакованные-переключатели-полезные данные и запасные-переключатели-полезные данные. Единственная разница между ними заключается в том, в порядке ли значения в таблице. Мы сделаем это позже Подробное объяснение.
Инструкции по преобразованию данных
Преобразование типов данных хорошо знакомо любому разработчику Java и используется для реализации взаимного преобразования двух разных типов данных. Базовый формат инструкции: unop vA, vB, что означает работу с медианным значением регистра vB и результатом. Хранится в реестре vA.
инструкция | Описание |
---|---|
int-to-long | Преобразование в длинное целое число |
float-to-int | Преобразование типа с плавающей запятой одинарной точности в целое число |
int-to-byte | Преобразование в байтовый тип |
neg-int | Инструкция дополнения, дополнить целое число |
not-int | Инструкция отрицания, отрицать целое число |
До сих пор мы сделали краткое описание инструкций в Davilk. Инструкции Davilk в значительной степени объединены с инструкциями x86, а также структурой и семантикой инструкций JVM, поэтому в целом инструкции в Davilk по-прежнему очень легко изучить. Подробнее Подробнее подробные инструкции, пожалуйста, обратитесь к:Полный комплект инструкций Davilk
Подробный файл smali
Ключевые слова | Описание |
---|---|
.filed | Определить поля |
.method. end method | Метод определения |
.annotation | Аннотация к определению |
.implements | Определите инструкции интерфейса |
.local | Задает количество используемых локальных переменных |
.registers | Укажите количество используемых локальных регистров |
.prologue | Указывает начало кода в методе |
.line | Представляет указанную строку в исходном файле Java |
.paramter | Параметры метода указаны. |
Ниже мы кратко объясним структуру файла smali:
Первые три строки файла smali описывают текущую информацию о классе:
После заголовка файла идет тело файла, то есть основная часть класса, включая четыре части описания интерфейса, описания аннотации, описания поля и описания метода, реализованного классом. Давайте посмотрим на структуру полей и методов соответственно. (Не забывайте. (Представление методов и полей мы сказали в Davilk)
Описание интерфейса
smali добавил к нему аннотацию #Interface
Описание аннотации
Описание поля
Поля описаны в smali. Мы знаем, что Java делится на статические поля (атрибуты класса) и обычные поля (атрибуты экземпляра). Их представление в smali выглядит следующим образом:
1. Общие поля:
2. Статические поля
Знание статических полей добавляет статику к определению общих полей и имеет следующий формат:
Примечание: файлы smali также являются статическими полями, а обычные поля добавляются с комментариями #static field и #instan filed соответственно.
Описание метода
.Method используется в smali для описания метода. Конкретный формат определения выглядит следующим образом:
Следует отметить, что smali добавил к нему аннотацию метода #direct
Структура файла smali также очень ясна и понятна. Его также очень удобно читать после знакомства. Давайте взглянем на простой файл smali. Чтобы облегчить понимание, мы сначала вставляем фрагмент java-кода:
Давайте проанализируем smali, который декомпилирован из этого фрагмента кода. В коде
Заключительные замечания
Я все еще чувствую, что есть много моментов, которые я не ясно изложил, поэтому я добавлю их позже.