Una guía: ingeniería inversa de ofuscación de código

Publicado: 2021-11-17

Las figuras de ofuscación de código son uno de los enfoques de seguridad de aplicaciones más populares para prevenir la piratería de aplicaciones. Es uno de los esfuerzos de AppSec sugeridos con mayor frecuencia por los especialistas en seguridad de todo el mundo y, a menudo, se ocupa de los requisitos de seguridad mínimos de su aplicación. Esta estrategia se usa con frecuencia como un importante mecanismo de defensa contra los intentos de piratería y protege contra las amenazas típicas, como la inyección de código, la ingeniería inversa y la manipulación de la información personal de los clientes y usuarios de aplicaciones.

Ofuscación del código?

La práctica de ofuscar ejecutables de tal manera que ya no eran comprensibles, inteligibles o prácticos se conoce como ofuscación de código. El código fuente se ha ofuscado hasta el punto de que es incomprensible y difícil de comprender para un tercero, y mucho menos de ejecutar. La interfaz de usuario del usuario final o la salida prevista del código no se ven afectados por la oscuridad. Es solo un paso de precaución para hacer que el código sea inútil para cualquier pirata informático potencial que tenga acceso al código ejecutable de un software.

¿Por qué es necesario ofuscar el código?

La ofuscación del código es especialmente importante para el software de código abierto, que tiene una desventaja significativa en términos de pirateabilidad para beneficio personal. Los desarrolladores garantizan que la propiedad intelectual de su producto está protegida contra los riesgos de seguridad, el acceso ilegal y el descubrimiento de fallas en la aplicación al dificultar la ingeniería inversa de un programa.

Independientemente del tipo de técnica de oscurecimiento utilizada, este enfoque restringe el código fuente peligroso y garantiza diversos niveles de seguridad del programa. Las razones de tiempo, costo y recursos favorecen el abandono de su código cuando está ofuscado, ya que el código descompilado se vuelve ilegible.

Técnicas para la ofuscación de código

La ofuscación funciona en varios niveles: puede implementarse en el nivel de estructura de código semántico/léxico o en el nivel de estructura de datos/flujo de control. Las estrategias de ofuscación también difieren según la acción en el código. En esencia, el equipo de seguridad determina el tipo de ofuscación que se utilizará en el código en cooperación con el equipo de desarrollo.

La ofuscación debe ser renombrada.

Este enfoque implica nombrar variables de manera confusa para que el objetivo real de utilizarlas se oculte inteligentemente. Los descompiladores tienen dificultades para comprender el flujo de control, ya que los métodos y las variables se renombran con varias notaciones y números. Este método de ofuscación se usa comúnmente para disfrazar el código de aplicación de la plataforma Java, .NET y Android. Esto se clasifica como ofuscación de diseño, ya que apunta directamente al código fuente para proporcionar una capa de protección para la aplicación.

Ofuscación de datos

Este método se enfoca en las estructuras de datos utilizadas en el código, haciendo imposible que el hacker acceda al verdadero objetivo del programa. Esto puede implicar cambiar la forma en que el software almacena los datos en la memoria y cómo se procesan esos datos para producir el resultado final. Este procedimiento se puede realizar de varias formas:

1. Ofuscación de agregación
Como resultado, la forma en que se guardan los datos en el software cambia. Los arreglos, por ejemplo, pueden dividirse en varios subarreglos a los que luego se podría hacer referencia en todo el programa.

2. Ofuscación del almacenamiento de datos
Esto tiene un impacto en la forma en que los datos se almacenan en la memoria. Los desarrolladores pueden, por ejemplo, alternar entre el almacenamiento de variables locales y globales para ocultar la verdadera naturaleza del comportamiento de las variables.

3. Obtención de ofuscación bajo demanda
Este enfoque cambia el orden de los datos sin cambiar la funcionalidad del programa/fragmento de código. Los desarrolladores logran esto mediante la creación de un módulo distinto que se invoca para cada instancia de la referencia de variable.

4. Cadenas de cifrado
Esta técnica cifra todas las cadenas legibles, lo que da como resultado un código ilegible. Cuando se ejecuta el software, deben descifrarse en tiempo de ejecución.

5. Ofuscación de control/flujo de código
La forma en que se transmite el control de una parte del código base a otra es crucial para establecer el objetivo del programa. Ocultar este flujo suele ser la forma más rentable de pervertir el flujo del juego. Esta estrategia de ofuscación mantiene a raya a los piratas informáticos al dificultarles descubrir cómo y por qué el código sigue una ruta específica.

La inclusión de declaraciones aleatorias e inesperadas, así como declaraciones de cambio de caso innecesarias (código muerto) que nunca se ejecutarían, es una de las formas más frecuentes de lograr esta estrategia de ofuscación. Estas afirmaciones no tienen otra función que dejar perplejo al hacker objetivo. En el caso de la orientación condicional del programa, este cambio en la secuencia de instrucciones de ejecución del programa es extremadamente útil.

La ofuscación se está depurando.

La información de depuración suele ser útil para determinar información vital sobre el flujo del programa y los defectos mediante la descompilación y recompilación del código fuente. Es fundamental ocultar dichos datos de identificación alterando sus identidades, números de línea o desactivando el acceso a los datos de depuración por completo.

La ofuscación debe ser abordada.

Los errores de programación de memoria se han generalizado en los ataques, especialmente en lenguajes que no son seguros para la memoria, como C y C++. Las fallas de seguridad con frecuencia son causadas por errores como el acceso descontrolado a la matriz. El enfoque de ofuscación de direcciones dificulta la ingeniería inversa, ya que las direcciones virtuales del código y los datos del programa se aleatorizan cada vez que se ejecuta el código convertido. Como resultado, la mayoría de los ataques de errores de memoria no son deterministas y tienen muy pocas probabilidades de éxito.

Codificación personalizada

Los desarrolladores utilizan este enfoque para cifrar cadenas con un algoritmo personalizado y luego proporcionan una función de decodificador para recuperar el código original.

Argumentos pasados ​​en tiempo de ejecución

Es posible modificar el programa para que espere parámetros en tiempo de ejecución. Para poder decodificar las variables, el usuario debe tener tanto el código como la clave de descifrado.

Para desarrollar un método de defensa en capas para proteger las aplicaciones contra diversas amenazas de seguridad, el equipo de seguridad puede optar por implementar más de una técnica al mismo tiempo.

Conclusión

En resumen, la mala dirección por sí sola es ineficaz para combatir las preocupaciones de seguridad avanzadas. Es más difícil desofuscar el código debido a la disponibilidad del software de inteligencia artificial y la habilidad de los piratas informáticos, pero no es imposible. Como resultado, la criptografía no es una panacea para todos los problemas de seguridad del software.
El equipo de desarrollo puede usar una variedad de enfoques de ofuscación de código para asegurar su código en un entorno no confiable, según la necesidad de seguridad, la naturaleza del programa y el punto de referencia de rendimiento. Estos deben llevarse a cabo teniendo en cuenta las ventajas y desventajas de cada enfoque. Esta estrategia debe respaldar otras iniciativas de AppSec, como el cifrado, RASP, las regulaciones de retención de datos, etc. Cuando se combina con soluciones RASP como AppSealing, se convierte en un potente antídoto para las preocupaciones de seguridad actuales.