
Una biblioteca ligera de instrumentación dinámica
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.
## ¿Qué es TinyInst?
TinyInst es una biblioteca ligera de instrumentación dinámica que se puede utilizar para instrumentar únicamente el/los módulo(s) seleccionado(s) del proceso, dejando que el resto del proceso se ejecute de forma nativa. Está pensado para ser fácil de entender, fácil de modificar y fácil de usar con fines de hacking. No está diseñado para ser compatible con todos los objetivos (más sobre esto más adelante).
### ¿Cómo se compara con [DynamoRIO](https://dynamorio.org/) y [PIN](https://software.intel.com/en-us/articles/pintool)?
TinyInst no está pensado como un reemplazo de frameworks de instrumentación complejos como DynamoRIO y PIN, sino más bien como una alternativa para escenarios donde una solución más ligera sea suficiente. TinyInst asume que el objetivo está bien comportado (en el sentido que se explica a continuación), algo que no ocurre con frameworks más complejos. Por lo tanto, probablemente no podrás ejecutar TinyInst con éxito contra malware como [se hizo anteriormente con DynamoRIO](https://www.slideshare.net/MaximShudrak/fuzzing-malware-for-fun-profit-applying-coverageguided-fuzzing-to-find-bugs-in-modern-malware). Por otro lado, si un objetivo no funciona con otros frameworks debido al módulo que no necesita ser instrumentado, y el módulo instrumentado está bien comportado, podría funcionar con TinyInst. Debido a que con TinyInst la mayor parte del proceso se ejecuta de forma nativa, tendrá un tiempo de arranque del proceso más corto y podría superar a otras soluciones en los casos en que el proceso objetivo dedica mucho tiempo a los módulos donde no se necesita instrumentación.
### ¿Cómo se compara con [Mesos](https://github.com/gamozolabs/mesos) y [TrapFuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz)?
TinyInst es una solución completa de reescritura de binarios, por lo que se puede cambiar el comportamiento arbitrario en el módulo objetivo. Esto le permite, por ejemplo, extraer cobertura de aristas en lugar de solo bloques básicos. Además, TinyInst no depende de otro software, como IDA Pro, para identificar bloques básicos.
### ¿Qué sistema operativo es compatible con TinyInst?
TinyInst funciona en Windows (x86 y x64), macOS (x64 y ARM64), Linux (x64 y ARM64) y Android (ARM64). Consulta el archivo README en el directorio correspondiente de cada sistema operativo para obtener notas y limitaciones adicionales.
### ¿Qué objetivos son compatibles con TinyInst?
TinyInst asume que todos los módulos instrumentados están bien comportados en el sentido de que
- No hay código automodificable
- La dirección de retorno en la pila nunca es accedida directamente por el programa
O/Y (dependiendo de la configuración)
- Nunca se almacenan datos antes de la parte superior de la pila (en direcciones más bajas que las apuntadas por ESP/RSP). Esta condición se puede relajar a "ningún dato antes de (ESP/RSP - arbitrary_offset)" utilizando la opción `-stack_offset`.
TinyInst también requiere que DEP/NX esté habilitado para el proceso objetivo. Si ese no es el caso, puedes utilizar la opción `-force_dep` para forzarlo. Sin embargo, en el improbable caso de que el objetivo realmente necesite DEP desactivado para funcionar correctamente, forzarlo podría hacer que se comporte de manera incorrecta.
### ¿Cuál es la sobrecarga de rendimiento?
Según mediciones tempranas en decodificación de imágenes, en un objetivo de 64 bits bien comportado con la configuración predeterminada de TinyInst, la sobrecarga de rendimiento fue de alrededor del 15 % sin un cliente y de aproximadamente el 20 % con el cliente de ejemplo que recopila cobertura. Ten en cuenta que esto no incluye el tiempo de espera (timeout) introducido por la instrumentación inicial de los módulos. Consulta los consejos de rendimiento a continuación para obtener más detalles.
## Compilación de TinyInst
1. Abre una terminal y configura tu entorno de compilación (p. ej., en Windows, ejecuta vcvars64.bat / vcvars32.bat)
2. Navega hasta el directorio que contiene el código fuente
3. Ejecuta los siguientes comandos (cambia el generador según la versión del IDE y la plataforma para la que quieras compilar):
#### 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
Nota #1: la compilación de 64 bits también funcionará con objetivos de 32 bits en sistemas operativos Windows y Linux
Nota #2: ¿Tienes problemas para crear una compilación de 32 bits en Windows de 64 bits porque el entorno no está configurado correctamente y faltan bibliotecas? Abre el archivo .sln generado en Visual Studio y compílalo desde allí en lugar de ejecutar cmake --build. Ten en cuenta también que la compilación de 64 bits funcionará con objetivos de 32 bits, por lo que puede que no sea necesario crear una compilación de 32 bits.
## Uso de TinyInst
TinyInst está pensado principalmente para usarse como una biblioteca dentro de otros programas.
Un cliente de TinyInst se implementa como una subclase de la clase TinyInst. El cliente puede sobrescribir los métodos de la API que necesite. Los métodos de la API se definen a continuación.
Después de crear el cliente, debe inicializarse con las opciones de línea de comandos llamando a
`void init(int argc, char **argv);`
Las opciones de línea de comandos se definen a continuación y un cliente también puede definir las suyas propias. Después de eso, para ejecutar y controlar un programa instrumentado, se pueden usar las siguientes funciones.
`DebuggerStatus Run(int argc, char **argv, uint32_t timeout);`
`DebuggerStatus Attach(unsigned int pid, uint32_t timeout);`
Estas funciones ejecutan un programa (usando la línea de comandos especificada) o se adjuntan a un programa ya en ejecución. Si no se especifica un método objetivo, el objetivo continuará ejecutándose hasta que el programa salga, el programa falle o expire el tiempo de espera (expresado en milisegundos). Si se define un método objetivo, TinyInst retornará cada vez que se entre al método objetivo y cada vez que el método objetivo retorne, lo que permite a quien lo invoca realizar tareas adicionales.
Cuando `Run` y `Attach` retornan mientras el proceso objetivo sigue vivo, se pueden usar las siguientes funciones para terminar el proceso o continuar la ejecución.
`DebuggerStatus Kill();`
`DebuggerStatus Continue(uint32_t timeout);`
TinyInst incluye un binario de cobertura de ejemplo, que se puede invocar usando
`<options> -- <target command line>`
Ejemplo en Windows:
`litecov.exe -instrument_module notepad.exe -coverage_file coverage.txt -- notepad.exe`
## API de instrumentación
### Devoluciones de llamada de eventos del depurador
Estas devoluciones de llamada son solo informativas y el cliente no debe emitir ningún código instrumentado durante ellas. Los clientes deben llamar al mismo manejador definido en la superclase antes de gestionar estos eventos por sí mismos.