¿Cómo bloquear las clases Java compiladas para evitar la descompilación?


96

¿Cómo bloqueo las clases Java compiladas para evitar la descompilación?

Sé que este tema debe ser muy bien discutido en Internet, pero no pude llegar a ninguna conclusión después de referirlos.

Mucha gente sugiere ofuscator, pero simplemente renombran clases, métodos y campos con secuencias de caracteres difíciles de recordar, pero ¿qué pasa con los valores constantes sensibles?

Por ejemplo, ha desarrollado el componente de cifrado y descifrado basado en una técnica de cifrado basada en contraseña. Ahora, en este caso, cualquier persona promedio de Java puede usar JAD para descompilar el archivo de clase y recuperar fácilmente el valor de la contraseña (definida como constante), así como la sal y, a su vez, puede descifrar los datos escribiendo un pequeño programa independiente.

¿O estos componentes sensibles deberían construirse en código nativo (por ejemplo, VC ++) y llamarlos a través de JNI ?


Incluso el código nativo desensamblado es bastante legible para algunas personas de todos modos, probablemente tendría que usar algún ofuscador o ensamblaje hecho a mano para que no sea obvio (el C ++ común compilado con optimización es lo suficientemente legible). Cualquier código que se ejecute en el dispositivo del usuario, puede ser interceptado. Aunque los requisitos de costo / habilidad de tal interceptación pueden ser bastante altos, por ejemplo, romper el código de chips "a prueba de manipulaciones" de tarjetas inteligentes no es trivial, solo es factible con el mejor equipo y habilidad. Con las clases de Java ... No me molestaría mucho, probablemente puedas encriptarlas lo suficiente como para rechazar a los niños del script, no más.
Ped7g

Respuestas:


96

Algunos de los ofuscadores de código de bytes de Java más avanzados hacen mucho más que alterar los nombres de las clases. Zelix KlassMaster , por ejemplo, también puede codificar el flujo de su código de una manera que lo hace realmente difícil de seguir y funciona como un excelente optimizador de código ...

Además, muchos de los ofuscadores también pueden codificar sus constantes de cadena y eliminar el código no utilizado.

Otra posible solución (que no excluye necesariamente la ofuscación) es utilizar archivos JAR cifrados y un cargador de clases personalizado que realice el descifrado (preferiblemente utilizando la biblioteca de tiempo de ejecución nativa).

En tercer lugar (y posiblemente ofrece la protección más fuerte) es utilizar compiladores nativos de antemano como GCC o Excelsior JET , por ejemplo, que compilan su código Java directamente en un binario nativo específico de la plataforma.

En cualquier caso, debes recordar que, como dice el refrán en estonio, "Los candados son para animales". Lo que significa que cada fragmento de código está disponible (cargado en la memoria) durante el tiempo de ejecución y con suficiente habilidad, determinación y motivación, las personas pueden descompilar, descifrar y piratear su código ... Su trabajo es simplemente hacer que el proceso sea tan incómodo como puedes y aún hacer que funcione ...


13
+1 para "Las cerraduras son para animales". Supongo que el término apropiado aquí sería script kiddies.
Antimony

Te refieres a GCJ, y está muerto.
Marqués de Lorne

1
El cifrado de archivos jar de Componio también está muerto. Utilice JarProtector en su lugar.
J.Profi

16

Siempre que tengan acceso tanto a los datos cifrados como al software que los descifra, básicamente no hay forma de que pueda hacer esto completamente seguro. La forma en que esto se ha resuelto antes es usar algún tipo de caja negra externa para manejar el cifrado / descifrado, como dongles, servidores de autenticación remota, etc. Pero incluso entonces, dado que el usuario tiene acceso completo a su propio sistema, esto solo hace que las cosas difícil, no imposible, a menos que pueda vincular su producto directamente a la funcionalidad almacenada en la "caja negra", como, por ejemplo, los servidores de juegos en línea.


13

Descargo de responsabilidad: no soy un experto en seguridad.

Esto suena como una mala idea: estás permitiendo que alguien encripte cosas con una clave 'oculta' que le das. No creo que esto se pueda asegurar.

Quizás las teclas asimétricas podrían funcionar:

  • implementar una licencia cifrada con una clave pública para descifrar
  • deje que el cliente cree una nueva licencia y se la envíe para que la encripte
  • envíe una nueva licencia al cliente.

No estoy seguro, pero creo que el cliente puede cifrar la clave de licencia con la clave pública que le dio. A continuación, puede descifrarlo con su clave privada y volver a cifrarlo también.

Puede mantener un par de claves públicas / privadas por separado por cliente para asegurarse de que realmente está recibiendo cosas del cliente correcto; ahora usted es responsable de las claves ...


2
He usado esta técnica antes y funciona bien. Sin embargo, desde una perspectiva de ataque, el primer enfoque sería simplemente modificar el código que realiza la verificación de la licencia y eliminarlo. Hay cosas que puedes hacer para hacer que este vector de ataque sea más difícil, pero si le das al atacante el control del hardware, estás destinado a fallar con un atacante capacitado y debidamente motivado. En la práctica, el objetivo es mantener honestas a la mayoría de las personas honestas.
Jim Rush

12

No importa lo que haga, se puede "descompilar". Diablos, puedes simplemente desmontarlo. O mire un volcado de memoria para encontrar sus constantes. Verá, la computadora necesita conocerlos, por lo que su código también lo necesitará.

¿Qué hacer con esto?

Trate de no enviar la clave como una constante codificada en su código: manténgala como una configuración por usuario. Haga que el usuario sea responsable de cuidar esa clave.


6

@jatanp: o mejor aún, pueden descompilar, eliminar el código de licencia y volver a compilar. Con Java, realmente no creo que exista una solución adecuada y a prueba de piratería para este problema. Ni siquiera un pequeño dongle malvado podría evitar esto con Java.

Mis propios gerentes de negocios se preocupan por esto y yo pienso demasiado. Pero, de nuevo, vendemos nuestra aplicación a grandes corporaciones que tienden a cumplir con las condiciones de la licencia, generalmente un entorno seguro gracias a los contadores de granos y los abogados. El acto de descompilar en sí mismo puede ser ilegal si su licencia está escrita correctamente.

Entonces, tengo que preguntar, ¿ realmente necesita una protección reforzada como la que busca para su aplicación? ¿Cómo es su base de clientes? (¿Corporaciones? O las masas de jugadores adolescentes, ¿dónde esto sería más un problema?)


De hecho, existe una solución adecuada a prueba de piratería que, por cierto, parece un dongle: excelsior-usa.com/blog/excelsior-jet/…
Dmitry Leskov

@DmitryLeskov 'resistente a la piratería', tal vez. Pero es simplemente un obstáculo para cualquiera que quiera en el código. Al final del día, el código de bytes debe ejecutarse en una plataforma de host sin cifrar. Punto final.
Stu Thompson

No has leído la publicación a la que he vinculado. El código de bytes se convierte al código de la CPU del dongle y se cifra. Cuando el usuario final ejecuta la aplicación protegida, ese código cifrado se transfiere al "dongle". El dongle lo descifra y lo ejecuta en su CPU.
Dmitry Leskov

2
Jugadores adolescentes corporativos.
odiszapc

3

Si está buscando una solución de licencias, puede consultar la API de TrueLicense . Se basa en el uso de claves asimétricas. Sin embargo, no significa que su aplicación no se pueda descifrar. Cada aplicación se puede descifrar con suficiente esfuerzo. Lo realmente importante es, como respondió Stu , averiguar qué tan fuerte protección necesita.


2

No creo que exista ningún método eficaz contra la piratería fuera de línea. La industria de los videojuegos ha tratado de encontrar eso muchas veces y sus programas siempre han sido resquebrajados. La única solución es que el programa debe ejecutarse en línea conectado con sus servidores, de modo que pueda verificar la clave de lincense, y que solo haya una conexión activa por parte del licenciatario a la vez. Así es como funciona World of Warcraft o Diablo . Incluso aunque existen servidores privados desarrollados para que ellos eludan la seguridad.

Habiendo dicho eso, no creo que las medianas / grandes corporaciones usen software copiado ilegalmente, porque el costo de la licencia para ellas es mínimo (quizás, no sé cuánto vas a cobrar por tu programa) en comparación con el costo de una versión de prueba.


2

Puede utilizar el cifrado de código de bytes sin miedo.

El hecho es que el documento citado anteriormente "Cracking Java byte-code encryption" contiene una falacia lógica. El reclamo principal del documento es que antes de ejecutar todas las clases se deben descifrar y pasar al ClassLoader.defineClass(...)método . Pero esto no es cierto.

La suposición omitida aquí es que se ejecutan en un entorno de tiempo de ejecución de Java auténtico o estándar . Nada puede obligar a la aplicación java protegida no solo a iniciar estas clases, sino incluso a descifrarlas y pasarlas ClassLoader. En otras palabras, si está en JRE estándar, no puede interceptar el defineClass(...)método porque el java estándar no tiene API para este propósito, y si usa JRE modificado con parcheado ClassLoadero cualquier otro "truco de pirata informático", no puede hacerlo porque está protegido La aplicación java no funcionará en absoluto y, por lo tanto, no tendrá nada que interceptar. Y no importa en absoluto qué "buscador de parches" se utiliza o qué truco utilizan los piratas informáticos. Estos detalles técnicos son una historia bastante diferente.


¿Cómo piensa exactamente detectar una JVM parcheada? De todos modos, todo esto hace que las cosas sean un poco más difíciles.
Antimony

¿No puedes encontrar una llamada a defineClass () en tu lanzador de aplicaciones? Cuando realiza esa llamada, debe entregar una matriz de bytes descifrados de todos modos. ¿No es ese otro punto donde la fuente original podría filtrarse?
Ascendente

4
Realmente no estoy de acuerdo con esta respuesta. Para mí, esto suena como, "Pregunta: ¿Cuál es la forma más fácil de encontrar Pi? Respuesta: Tome 2 * Pi y divida por dos". No estoy en desacuerdo con la idea, pero ¿podría incluir más detalles? Por ejemplo, ¿espera que el programa principal esté escrito en Java puro? ¿Eso incluye el código que busca modificaciones?
Patrick M

-1

P: Si cifro mis archivos .class y uso un cargador de clases personalizado para cargarlos y descifrarlos sobre la marcha, ¿evitará la descompilación?

R: El problema de prevenir la descompilación del código de bytes de Java es casi tan antiguo como el lenguaje mismo. A pesar de la variedad de herramientas de ofuscación disponibles en el mercado, los programadores Java novatos continúan pensando en formas nuevas e inteligentes de proteger su propiedad intelectual. En esta entrega de Java Q&A, disiparé algunos mitos sobre una idea que se repite con frecuencia en los foros de discusión.

La extrema facilidad con la que los archivos .class de Java se pueden reconstruir en fuentes de Java que se parecen mucho a los originales tiene mucho que ver con los objetivos y compensaciones del diseño de códigos de bytes de Java. Entre otras cosas, el código de bytes de Java fue diseñado para ser compacto, independencia de plataforma, movilidad de red y facilidad de análisis por intérpretes de código de bytes y compiladores dinámicos JIT (just-in-time) / HotSpot. Podría decirse que los archivos .class compilados expresan la intención del programador con tanta claridad que podrían ser más fáciles de analizar que el código fuente original.

Se pueden hacer varias cosas, si no para evitar la descompilación por completo, al menos para hacerlo más difícil. Por ejemplo, como paso posterior a la compilación, podría aplicar un masaje a los datos .class para hacer que el código de bytes sea más difícil de leer cuando se descompila o más difícil de descompilar en un código Java válido (o ambos). Técnicas como realizar una sobrecarga extrema de nombres de métodos funcionan bien para el primero y manipular el flujo de control para crear estructuras de control que no se pueden representar a través de la sintaxis de Java funcionan bien para el segundo. Los ofuscadores comerciales más exitosos utilizan una combinación de estas y otras técnicas.

Desafortunadamente, ambos enfoques deben cambiar el código que ejecutará la JVM, y muchos usuarios temen (con razón) que esta transformación pueda agregar nuevos errores a sus aplicaciones. Además, el cambio de nombre de métodos y campos puede hacer que las llamadas de reflexión dejen de funcionar. Cambiar los nombres de paquetes y clases reales puede romper varias otras API de Java (JNDI (Interfaz de directorio y nombres de Java), proveedores de URL, etc.). Además de los nombres alterados, si se altera la asociación entre las compensaciones de código de bytes de clase y los números de línea de origen, la recuperación de los seguimientos originales de la pila de excepciones podría resultar difícil.

Luego está la opción de ofuscar el código fuente original de Java. Pero fundamentalmente esto causa un conjunto similar de problemas. ¿Encriptar, no ofuscar?

Tal vez lo anterior te haya hecho pensar: "Bueno, ¿y si en lugar de manipular el código de bytes cifro todas mis clases después de la compilación y las descifro sobre la marcha dentro de la JVM (lo que se puede hacer con un cargador de clases personalizado)? Entonces la JVM ejecuta mi código de bytes original y, sin embargo, no hay nada que descompilar o realizar ingeniería inversa, ¿verdad? "

Desafortunadamente, estaría equivocado, tanto al pensar que fue el primero en tener esta idea como al pensar que realmente funciona. Y la razón no tiene nada que ver con la solidez de su esquema de cifrado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.