tratando de asegurar un código

-2

Estoy tratando de dificultar la modificación de un código. La seguridad es mi preocupación.

Ok, sé lo que dirán sobre la piratería, bla bla bla. Vamos a abstenernos de esa discusión.

Estoy intentando recopilar ideas para hacer cosas de manera diferente en el código.

Cosas como esta por ejemplo:

int delta = value1 - value2;

if (delta > 0) {
   // code is fine
} else {
   // code is tampered
}

se puede parchear fácilmente en binario simplemente reemplazando el equivalente binario por ">" esa sería la instrucción JG (saltar si es mayor) con JLE (saltar si es menor o igual) o incluso reemplazando la resta con la suma.

En este caso, específicamente, ¿qué técnicas puedo usar en su lugar?

¿Qué trucos saben ustedes para hacer que las cosas simples sean difíciles para los crackers?

    
pregunta SpaceDog 27.04.2014 - 11:56
fuente

4 respuestas

5

En última instancia, cualquier código se reducirá a códigos de máquina / códigos de operación. El resultado es el mismo, pero analicemos tanto la distribución del código fuente como el código compilado / máquina:

Si está usando algo como PHP donde tiene el código fuente, podría agregar más bucles y construcciones, pero alguien puede cargar un depurador y rastrear su código de todos modos para eliminar el acceso. Si tiene una obligación contractual u obligación de licencia para proporcionar el código fuente, esto no va a hacer que los clientes estén contentos. Si desea agregar ofuscaciones en el nivel de idioma de nivel superior, esto hará que el código sea difícil de administrar. Agregando ofuscaciones usando un script después, de nuevo, simplemente puede eliminarlo. Cuando se minimizan JavaScript y CSS, resulta molesto rastrear pero no es imposible. Para PHP y similares, puede compilar códigos opc (por ejemplo, ioncube ) y agregar ofuscación, pero no impide que alguien realice el seguimiento. .

Para el código compilado: las construcciones de lenguaje de nivel superior se reducirán a instrucciones más simples. Su compilador hace muchas cosas bajo el capó que pueden reducir todo el esfuerzo que está haciendo en el nivel superior. Una vez más, siempre pueden recorrer su código con un depurador. La ofuscación está agregando complejidad y confusión, pero aún debe haber una ruta de ejecución para las instrucciones correctas. Sería mejor realizar la ofuscación en el momento de la compilación o realizar la ofuscación en el código compilado y tratar de complicar su código fuente. Vea estas preguntas de desbordamiento de SO:

Si no está utilizando un algoritmo especial, si las personas pueden observar el flujo, simplemente lo duplicarán por vista y función en lugar de perder el tiempo para obtener la fuente. Al final, aún pueden copiar su funcionalidad independientemente de su ofuscación.

La otra pregunta que puede estar preguntando es si su archivo fuente fue modificado antes / durante la ejecución. Por ejemplo, ¿este ya no es mi código legítimo, así que no correré? Puede hacer esto a nivel del sistema de archivos utilizando monitoreo de integridad de archivos , como TripWire . También puede utilizar DRM . Cosas como DEP también ayudan a prevenir esto.  Si alguien tiene un parche o pirateo contra su código, es probable que pueda eludir las protecciones de la aplicación cuando coloque su código malicioso también.

    
respondido por el Eric G 27.04.2014 - 18:19
fuente
1

Lo que estás buscando es una ofuscación. Y para su ejemplo específico, control de ofuscación de flujo.

Por ejemplo, podría agregar sentencias ifs y goto innecesarias:

if (!this_is_always_true_and_defined_somewhere_else) {
    goto some_label;
} else {
    if (delta > 0) {
       // code is fine
    } else {
       // code is tampered
    }
}

También puede hacer que la consulta if sea más complicada:

if (!this_is_always_true_and_defined_somewhere_else) {
    goto some_label;
} else {
    if (delta > 0 && complicated_expression_that_is_always_true) {
       // code is fine
    } else {
       // code is tampered
    }
}

Y, por supuesto, puedes hacer lo mismo para la resta:

int delta = (value1 - value2) + (value3 - 4 * value4);

donde value3 y value4 se definen en otra parte y value3 = 4 * value4

Para obtener más recursos sobre ofuscación, consulte aquí , here y aquí

Hay muchos ofuscadores por ahí, y yo usaría uno de ellos en lugar de hacer que tu código sea más difícil de leer. Pero en general, creo que la ofuscación realmente no resuelve nada. Es por eso que DRM todavía existe :)

Editar desde el comentario de @TeunVink : si usas un compilador para generar una versión binaria de tu programa, asegúrate de saber cómo funciona. Muchos compiladores hacen análisis de código muerto, lo que elimina cualquier parte inalcanzable del código. Esto elimina muchos de estos ejemplos, ya que el (pre) compilador simplemente reemplazará o eliminará la complejidad agregada.

    
respondido por el tim 27.04.2014 - 14:32
fuente
0

Los enlaces publicados por otros aquí sobre la ofuscación merecen una lectura. Como usted mismo se nota, un solo punto de prueba puede ser fácilmente parcheado para eliminar las pruebas. Es posible que haya millas en la utilización de efectos secundarios que causen que el código no relacionado se siga rompiendo a menos que un código importante se haya ejecutado y haya dejado valores particulares por ahí, y también que se rompa el código si dichos valores indican que una prueba importante, como una verificación de licencia, ha fallado. El objetivo sería requerir que un ingeniero inverso obtenga un conocimiento más profundo del código que simplemente identificando un punto de código "if (license_check_valid)", y para que ellos determinen qué estado necesitarían falsificar a través de parches para permitir que se omita el código o no se ejecuta según lo previsto y aún así deja el programa en funcionamiento.

Es probable que los optimizadores deshagan las ofuscaciones de flujo de control simples. En lenguajes como C / C ++, las técnicas como el uso de punteros de función para llamadas y la explosión de estos en sus bytes constituyentes en ubicaciones discretas para que nunca se almacenen juntas y solo se vuelvan a ensamblar para realizar una llamada pueden complicar el análisis.

    
respondido por el Nick 01.05.2014 - 15:46
fuente
0

Depende del idioma y del entorno, he tenido éxito al cifrar el código ejecutable y al descifrarlo sobre la marcha. Cambiar la clave entre versiones menores ralentiza significativamente las grietas, Al igual que la comparación de código en el ram vs el código cifrado se comprueba en tiempo de ejecución.

Agarrando el puntero a una función de autenticación, calculando su suma de control y comparándolo con algo que se conoce en algún lugar no relacionado en el código y luego causando "fallas menores" en el software (por ejemplo, para un juego que pierde la velocidad de cuadros o la introducción de fallas en una aplicación científica que arroja estadísticas ligeramente al punto en el que un cracker puede no darse cuenta pero un usuario estaría muy al tanto)

Los temporizadores también son geniales, puedes parecer inocentemente que tienes algo de código de depuración / creación de perfiles cuando realmente estás buscando una aplicación que está siendo depurada. Lo mismo ocurre con la observación para ver si las tablas de interrupciones se están desordenando o si se están lanzando los nmi.

Otro truco personal que me gusta usar es tomar partes de la clave de registro y usarlas como constantes en otras partes del código en lugares no relacionados, una vez más, la clave no es hacer el crack inicial para hacer que el software se ejecute con facilidad, sino más bien para El software se comporta incorrectamente de manera sutil cuando se agrieta.

    
respondido por el Damian Nikodem 09.02.2015 - 17:49
fuente

Lea otras preguntas en las etiquetas