¿Qué es la ofuscación de código? Cómo disfrazar su código para hacerlo más seguro

En los primeros días de la informática, los desarrolladores no tenían que preocuparse por las redes. Solo podían concentrarse en asegurarse de que su software cumpliera su propósito previsto y no fallara con demasiada frecuencia.

Y la persona promedio que entró en contacto con ese software no fue una amenaza. La mayoría de los usuarios ni siquiera se molestarían en leer los manuales de usuario enviados en la caja del software, y mucho menos en buscar vulnerabilidades en el código.

Luego, apareció Internet y lo cambió todo.

Casi de la noche a la mañana, las redes informáticas se interconectaron. Y a medida que la complejidad crecía, también lo hacían las probabilidades de que alguien encontrara su camino en esas redes que no pertenecían allí.

Y la mayoría de las veces, esas personas tendrían las habilidades necesarias para explotar el código defectuoso.

Y eso nos lleva al día de hoy. Es una época de amenazas de ciberseguridad sin precedentes. Y las noticias de ciberataques parecen llegar a diario.

En respuesta, los administradores de red despliegan sistemas defensivos cada vez más sofisticados para fortalecer sus redes contra intrusos. Y ahora esperan que los desarrolladores de software hagan un esfuerzo adicional para asegurar su código y evitar el acceso no autorizado.

Y, sin embargo, el endurecimiento del código informático todavía no se enseña mucho en las escuelas de codificación. Pero se está convirtiendo en una necesidad en el desarrollo de aplicaciones modernas.

Para ayudar a remediar eso, en este artículo explicaré qué es la ofuscación de código. Y también le daré una descripción general de las seis técnicas de ofuscación de código más importantes que se utilizan en la actualidad para que pueda comenzar en el camino hacia la escritura de software más seguro.

¿Qué es la ofuscación de código?

Como sugiere su nombre, la ofuscación de código se refiere a una serie de técnicas de programación diseñadas para disfrazar elementos del código de un programa. Es la forma principal en que los programadores pueden defender su trabajo contra el acceso no autorizado o la alteración por parte de piratas informáticos o ladrones de propiedad intelectual.

Y lo más importante, las técnicas de ofuscación de código pueden alterar la estructura y los métodos que utiliza un programa para operar, pero nunca alteran la salida de un programa.

El problema es que muchas técnicas de ofuscación de código pueden aumentar la sobrecarga de un programa y aumentar el tiempo de ejecución.

Por esa razón, es fundamental comprender qué técnicas están relativamente libres de penalizaciones y cuáles pueden causar problemas de rendimiento. Una vez que conozca los costos, es posible equilibrar la protección y el rendimiento en una aplicación del mundo real.

Aquí están las seis técnicas de ofuscación de código más utilizadas en la actualidad.

1. Eliminar datos superfluos

La primera técnica de refuerzo de código que debe aplicarse en todos los casos es deshacerse de todo lo que no sea necesario en su código.

Hacer esto optimizará su base de código y reducirá la superficie de ataque que está defendiendo.

Esto significa eliminar funciones redundantes, depurar información y tantos metadatos como sea posible. En resumen, cualquier cosa que pueda brindarle a un atacante una hoja de ruta que lo lleve a una vulnerabilidad.

2. Transforma los datos

Lo siguiente que debe hacer es transformar los datos que procesa su código para que sean irreconocibles.

Tácticas como reemplazar valores con expresiones, alterar el formato del almacenamiento de datos que usa o incluso usar versiones binarias de los números de su código, agregan complejidad. Y esa complejidad hará que sea difícil para cualquier persona que realice ingeniería inversa en su código para obtener algo útil de él.

Por ejemplo, puede utilizar el cifrado de cadenas para que las cadenas de texto sin formato de su código sean ilegibles. El cifrado de cadenas puede usar una codificación base64 simple, que convertiría este código:

String s = "Hello World"; Into: String s = new String(decryptString("SGVsbG8gV29ybGQ="));

Aunque no es difícil para un programador experimentado detectar lo que está sucediendo aquí, tener que lidiar con el descifrado de numerosas cadenas consume mucho tiempo y es frustrante.

Y cuando se combinan con algunas de las otras técnicas de ofuscación de código, las transformaciones de datos son una primera línea de defensa efectiva.

3. Utilice la ofuscación de órdenes de proceso

Uno de los requisitos desafiantes de la ofuscación de código es que aún necesita que su código funcione según lo previsto cuando haya terminado.

Pero no hay nada que diga que debe ejecutar su código en un orden lógico. Si mezcla el orden de las operaciones de su código, aún puede lograr el resultado correcto, pero hará que sea mucho más difícil para un tercero entender lo que está haciendo su código.

La única advertencia es que debe tener cuidado de no crear demasiados bucles sin sentido y callejones sin salida porque puede ralentizar accidentalmente el tiempo de ejecución de su código.

Como ejemplo, observe el siguiente fragmento, que calcula la suma y el promedio de 100 números:

int i=1, sum=0, avg=0 while (i = 100) { sum+=i; avg=sum/i; i++; }int i=1, sum=0, avg=0 while (i = 100) { sum+=i; avg=sum/i; i++; }

By adding a conditional variable, it's possible to disguise what the code is doing. This is because an analysis of the function would require knowledge of what's being input into it to begin with.

In the following snippet, the conditional variable 'random' creates a more complex code structure that makes it far harder to decipher:

int random = 1; while (random != 0) { switch (random) { Case 1: { i=0; sum=1; avg=1; random = 2; break; } case 2: { if (i = 100) random = 3; else random = 0; break; } case 3: { sum+=i;avg=sum/i ; i++; random = 2; break; } } }

4. Try Debug Obfuscation

Sometimes, a determined attacker can learn all kinds of useful information about your code by examining its debug information.

And in some cases, they might find the keys to unraveling some of the other obfuscation techniques you're using.

So wherever possible, it's a good idea to remove access to debugging information. And when that's not an option, masking any identifying information in the debugging report is essential.

5. Use Address Randomization

For almost thirty years, errors related to memory handling have been the most common software vulnerabilities hackers exploit – even though every programmer knows that the problem persists.

And it's not just among beginners. Around 70% of the vulnerabilities in Google's Chrome web browser stem from memory errors.

The reality is, it's all but impossible to prevent all memory programming errors, especially if you're using languages like C and C++. But what you can do is include some memory randomization features in your code that will help.

At execution, if your code and data's virtual addresses get assigned random values, it gets much harder to find and exploit any unpatched vulnerabilities.

Plus, it adds another benefit, too. It makes it so that even a successful hack of your code is difficult – if not impossible – to replicate. That alone makes it much less likely that an attacker will waste their time trying to hack your software.

6. Rotate the Obfuscated Code

As much as the above techniques work to frustrate attackers, they're far from a perfect defense. Anyone with enough time and skills will still find a way to defeat them. But that brings us to one of the most essential obfuscation techniques of all.

Since all obfuscation techniques aim to increase the complexity of an attacker's work, anything you can do to set them back to square one is a great defensive measure. So, to keep your code protected, use the internet to your advantage.

You can issue periodic updates that rotate the nature and specifics of the obfuscation techniques you're using. Every time you do, all the work someone may have been putting into cracking your software becomes a waste of time.

If you rotate your obfuscation tactics often enough, it won't be worth it for anyone to try and keep up an analysis long enough to succeed.

Security Through Obscurity

The bottom line here is that there's no such thing as 'unhackable' code. No matter how hard a programmer tries, there's always going to be a vulnerability somewhere. Not that you shouldn't keep trying, though.

But in the real world, your code doesn't have to be perfect. It just has to be hard enough to crack that nobody in their right mind would bother trying. And for those who aren't in their right mind, it just has to be complicated and time-consuming enough to keep them at bay.

And that's just what the six tactics above can help you accomplish. But remember, no defense comes without a cost. When deploying these options, make sure to weigh the execution-time penalties they may create against the benefits they provide.

If you're working on something especially sensitive, throwing every possible curveball might be worth it. But if you're writing a quote of the day generator – maybe don't worry as much.

However you choose to proceed, though, don't ever forget to take the time to harden your code in one way or another. It's just the right way to do things in a world filled with cybersecurity threats around every corner.

Featured photo by ThisIsEngineering from Pexels.