Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Ingeniería inversa a librerías java
#1
Sé que algunos de vosotros programáis/programábais en Java, así que a lo mejor suena la flauta si os pregunto.

Veréis, tengo entre manos cierto proyecto Android. El proyecto ni siquiera tiene entry point de ninguna clase, pues resulta que es un plugin. Dicho .APK sólo sirve como vehículo y la aplicación principal se encarga de cargarlo todo mediante reflection. Esto tiene la desventaja de que a la hora de compilar, puedes usar rutas relativas a la hora programar, pero en tiempo de ejecución explotará por todas partes, pues al usar reflection sobre la clase ésta pasa a ser parte de la aplicación principal y buscará entre sus recursos, y no los del proyecto plugin.

Para solucionar esto, calculo la ruta absoluta cuando haga falta gracias a que Android te puede dar la ruta de instalación de cualquier aplicación con una llamada a la API. Hasta ahí todo muy estable y correcto, la verdad es que me mola cómo me ha quedado el sistema de plugins.



Ahora bien, si resulta que necesito incrustarle un .JAR, la cosa se jode. No puedo editarlo pues no tengo su código fuente. Hay una llamada en el .JAR para cargar una librería nativa System.loadLibrary() que explotará si se llama dos veces, y para colmo está en el constructor. Es la primera vez que veo un programa Java suicidarse a lo bestia incluso con un try { } catch(Exception ex).

Sé que llamadas son y dónde están, porque le he pasado el Java Decompiler al fichero .jar en cuestión. Aunque me ha servido para detectar el problema, éste produce una basura de código, imposible de reutilizar y plagado de errores al estilo variables duplicadas, con nombres alienígenas y cosas por el estilo. Descartada la opción de importar los .java descompilados al Eclipse.



Si pudiese editar el fichero .class problemático para saltarse ese método, podría llamarlo una sola vez desde fuera y todo serían arcoiris de colores.

¿Habéis enredado con esto alguna vez? ¿Alguna otra solución creativa?
[Imagen: z4kSKUd.png]
Responder
#2
Se puede decompilar solo ese .class a .java, tocarlo, compilarlo y volver a empaquetar todo en jar.

Por como lo has descrito no se si te daba problemas al decompilar todos los class de jar o solo el que te daba problemas.

Luego a mayores, no se si se parece a lo que quieres hacer, sin decompilar nada, dependiendo que quieras de ese jar (una clase o muchas) podrias crear un nuevo ClassLoader desde un URL (debia terminar en "!jar" o algo así) e instanciar con el la clase a mano con reflection.
[Imagen: IUmqKJR.png]




Responder
#3
El source que me da el descompilador de java me da muchos errores y son muchas clases.

No puedo volver a compilar esa clase porque esta depende de las otras. ¿O sí?

No entiendo lo otro. ¿Para qué necesitaría extender el ClassLoader (que por cierto, es el PathClassLoader)? Quiero el objeto entero pero no puedo porque el System.loadLibrary() problemático está en el constructor.
[Imagen: z4kSKUd.png]
Responder
#4
2º frase, si.
-O descomprimes el jar y dejas las .class con la estructura de paquetes en el "/bin" o "/classes" de tu proyecto (uno nuevo para reahcer el jar, y sin la class que da problemas)
-O (esta deberia funcionar fijo) te haces un jar con todas menos la problemática e importas ese jar a un nuevo proyecto que tenga sólo el .class->.java a modificar.
Con eso puedes compilar la clase que da guerra y con ese class recompilado y el resto de class viejos rehacer el jar de nuevo.

No decia extender el Classloader sino crear una instancia de. Algo asi como (de memoria):
Código:
try{
ClassLoader cl=new ClassLoader (new URL(" bla bla .jar"+"!jar"));
Class problema=cl.load (no me acuerdo);
Object o=problema.newInstance();
si no querias poner ese jar problemático en el claspath y arrancar instancias solo esa clase. Pero te entendi mal, el problema está en el constructor de esa clase, no en el jar en si. Mea culpa.
[Imagen: IUmqKJR.png]




Responder
#5
¡SÍÍÍÍÍÍÍ! ¡Epic winrar! (nunca mejor dicho)

Escogí la segunda opción, la de borrar el .class chungo del .jar con el WinRAR. Luego cogí el source y creé la misma estructura de paquetes y lo metí ahí. Tras reparar las guarradas que hizo con ella el compilador, ¡arcoiris de colores!

O casi, porque resulta que si cargas clases por reflection que hagan uso de librerías nativas, si no las cargas desde la misma clase reflejada, explota, y con la segunda instancia que creas, la librería nativa sigue cargada pero misteriosamente no puedes enlazar con nada, y como en java no puedes descargar en tiempo ejecución librerías nativas... Esto lo he evitado haciendo que la clase plugin sea un singleton estático que vive durante toda la aplicación.

¡Mil gracias, majo!
[Imagen: z4kSKUd.png]
Responder
#6
(05-10-2013, 01:48 PM)Reaper45 escribió: resulta que si cargas clases por reflection que hagan uso de librerías nativas, si no las cargas desde la misma clase reflejada, explota [...]

Algo bastante lógico, le estás montando un pollo de puta madre a la VM.
[Imagen: YpRAA7X.png]
"Es como el que se mataba a pajas con U-jin y hoy en día o es Boku no Piko o ni se le levanta." - AniList
Responder
#7
Seguro que por dentro la lía parda, pero no creo que deba explotar de esa forma al llamar de nuevo al System.load("libreria") y dejar la librería ahí colgada al destruirse el objeto. Por otra parte me ha servido para entender la diferencia entre Exception, Error y Throwable.

Entiendo que al reflejar la clase, esta pasa a ser parte del programa que la refleja y que el compilador no te avise de que los recursos en rutas relativas no te vayan a funcionar... Debería tener algún mecanismo para que al crear instancias de algo la VM permita ajustar la ruta relativa.
[Imagen: z4kSKUd.png]
Responder
#8
Yo creo que la culpa es de quien hizo el jar, no de lo que pretende Reaper. Quien la hizo debio hacer la carga de la lib con un singleton como le ha tocado hacer a este con el class->java->class parcheado
[Imagen: IUmqKJR.png]




Responder
#9
Ahí está la cosa, que si la clase es cargada normalmente puedes llamar a System.load() todas las veces que te de la gana. Su planteamiento era válido.
[Imagen: z4kSKUd.png]
Responder
#10
Peta la VM solo por llamarla "legalmente" luego no lo era. Ese trocito debio estar aislado, no pensó que nadie la fuera usar asi o ni se lo planteo = No robusto.

¿Petaba la VM sin mas o te lanzaba un "java.lang.Error?
try { } catch(Throwable t).
[Imagen: IUmqKJR.png]




Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)