
Легковесная библиотека динамической инструментации
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
## Что такое TinyInst?
TinyInst — это легковесная библиотека динамической инструментации, которая может использоваться для инструментации только выбранных модулей в процессе, оставляя остальную часть процесса выполняться нативно. Она предназначена для того, чтобы её было легко понять, легко модифицировать и легко использовать для хака. Она не предназначена для совместимости со всеми целями (об этом позже).
### Чем она отличается от [DynamoRIO](https://dynamorio.org/) и [PIN](https://software.intel.com/en-us/articles/pintool)?
TinyInst не предназначена для замены сложных фреймворков инструментации, таких как DynamoRIO и PIN, а скорее является альтернативой для сценариев, где достаточно более лёгкого решения. TinyInst предполагает, что цель ведёт себя хорошо (в смысле, объяснённом ниже), что не является обязательным для более сложных фреймворков. Таким образом, вам, вероятно, не удастся успешно запустить TinyInst против вредоносного ПО, как [ранее делалось с DynamoRIO](https://www.slideshare.net/MaximShudrak/fuzzing-malware-for-fun-profit-applying-coverageguided-fuzzing-to-find-bugs-in-modern-malware). С другой стороны, если цель не работает с другими фреймворками из-за модуля, который не требует инструментации, а инструментируемый модуль ведёт себя хорошо, она может работать с TinyInst. Поскольку в TinyInst большая часть процесса выполняется нативно, время запуска процесса будет короче, и он может превзойти другие решения в случаях, когда целевой процесс проводит много времени в модулях, где инструментация не требуется.
### Чем она отличается от [Mesos](https://github.com/gamozolabs/mesos) и [TrapFuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz)?
TinyInst — это полноценное решение для бинарной перезаписи, поэтому в целевом модуле можно изменять произвольное поведение. Это позволяет, например, извлекать покрытие по рёбрам, а не только по базовым блокам. Кроме того, TinyInst не зависит от другого программного обеспечения, такого как IDA Pro, для идентификации базовых блоков.
### Какие операционные системы поддерживает TinyInst?
TinyInst работает на Windows (x86 и x64), macOS (x64 и ARM64), Linux (x64 и ARM64) и Android (ARM64). Пожалуйста, см. README в соответствующем каталоге для каждой операционной системы для дополнительных примечаний и ограничений.
### Какие цели совместимы с TinyInst?
TinyInst предполагает, что все инструментируемые модули ведут себя хорошо в том смысле, что
- Нет самомодифицирующегося кода
- Адрес возврата в стеке никогда не читается программой напрямую
И/ИЛИ (в зависимости от настроек)
- Никакие данные никогда не сохраняются перед вершиной стека (по адресам ниже, чем ESP/RSP). Это условие можно смягчить до «нет данных перед (ESP/RSP — произвольное_смещение)» с помощью флага `-stack_offset`.
TinyInst также требует, чтобы для целевого процесса был включён DEP/NX. Если это не так, можно использовать флаг `-force_dep`, чтобы принудительно включить его. Однако в маловероятном случае, когда цели действительно требуется отключение DEP для корректной работы, принудительное включение может привести к неправильному поведению.
### Какое влияние на производительность?
Согласно ранним измерениям при декодировании изображений на хорошо ведущей себя 64-битной цели с настройками TinyInst по умолчанию, накладные расходы на производительность составляли около 15% без клиента и около 20% с примером клиента, собирающего покрытие. Обратите внимание, что это не включает задержку, вызванную первоначальной инструментацией модулей. См. советы по производительности ниже для более подробной информации.
## Сборка TinyInst
1. Откройте терминал и настройте среду сборки (например, в Windows запустите vcvars64.bat / vcvars32.bat)
2. Перейдите в каталог, содержащий исходный код
3. Выполните следующие команды (измените генератор в соответствии с версией IDE и платформой, для которой вы собираетесь собирать):
#### Windows```
mkdir build
cd build
cmake -G "Visual Studio 16 2019" -A x64 ..
cmake --build . --config Release
mkdir build cd build cmake -G Xcode .. cmake --build . --config Release
#### Linux```
mkdir build
cd build
cmake ..
cmake --build . --config Release
mkdir build cd build cmake -DCMAKE_TOOLCHAIN_FILE=</path/to/android/ndk>build/cmake/android.toolchain.cmake -DANDROID_NDK=</path/to/android/ndk> -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM= .. cmake --build . --config Release
Примечание №1: 64-битная сборка также будет работать с 32-битными целями в операционных системах Windows и Linux.
Примечание №2: Возникают проблемы при создании 32-битной сборки на 64-битной Windows из-за неправильной настройки среды и отсутствия библиотек? Откройте сгенерированный файл .sln в Visual Studio и собирайте оттуда, вместо запуска cmake --build. Также учтите, что 64-битная сборка будет работать на 32-битных целях, поэтому создание 32-битной сборки может быть необязательным.
## Использование TinyInst
TinyInst в первую очередь предназначен для использования в качестве библиотеки внутри других программ.
Клиент TinyInst пишется как подкласс класса TinyInst. Затем клиент может переопределять необходимые ему методы API. Методы API описаны ниже.
После создания клиента его необходимо инициализировать параметрами командной строки, вызвав
`void init(int argc, char **argv);`
Параметры командной строки описаны ниже, и клиент также может определять свои собственные. После этого для запуска и управления инструментируемой программой могут использоваться следующие функции.
`DebuggerStatus Run(int argc, char **argv, uint32_t timeout);`
`DebuggerStatus Attach(unsigned int pid, uint32_t timeout);`
Эти функции либо запускают программу (используя указанную командную строку), либо подключаются к уже запущенной программе. Если целевой метод не указан, цель будет продолжать работу до тех пор, пока программа не завершится, не произойдет сбой или не истечет таймаут (заданный в миллисекундах). Если целевой метод определен, TinyInst будет возвращаться при каждом входе в целевой метод и при каждом возврате из него, позволяя вызывающему коду выполнять дополнительные задачи.
Когда `Run` и `Attach` возвращают управление, а целевой процесс все еще жив, можно использовать следующие функции для завершения процесса или продолжения выполнения.
`DebuggerStatus Kill();`
`DebuggerStatus Continue(uint32_t timeout);`
TinyInst поставляется с примером бинарного файла покрытия, который можно вызвать с помощью
`<options> -- <target command line>`
Пример на Windows:
`litecov.exe -instrument_module notepad.exe -coverage_file coverage.txt -- notepad.exe`
## API инструментирования
### Обратные вызовы событий отладчика
Эти обратные вызовы предназначены только для информации, и клиент не должен генерировать инструментированный код во время их выполнения. Клиенты должны вызвать тот же обработчик, определенный в суперклассе, перед обработкой этих событий самостоятельно.
`OnProcessCreated`
Вызывается при создании или присоединении целевого процесса.
`OnProcessExit`
Вызывается при завершении целевого процесса.
`OnProcessEntrypoint`
Вызывается при достижении точки входа процесса (главного бинарного файла).
`OnTargetMethodReached`
Если целевой метод определен, вызывается при первом достижении целевого метода.