inmensia |
Obtener el punto de entrada de una clase en un fichero Flash
Juan Mellado, 1 Mayo, 2010 - 10:54
A partir de su versión 9, los ficheros Flash admiten bloques de código escritos en ActionScript 3 embebidos en su interior. Aunque lo que almacenan esos bloques dentro de los ficheros no es el código fuente, sino un conjunto de descriptores y cadenas de opcodes resultantes de su compilación. La máquina virtual de ActionScript del plugin de Flash interpreta en tiempo de ejecución esa información y ejecuta el código. Ha estado leyendo las especificaciones de la máquina virtual de Flash, y he acabado escribiendo un pequeño parser en JavaScript que lee las estructuras que contienen el código ActionScript de un fichero SWF dado. Aunque al final me ha interesado más la forma de encontrar el punto de entrada para su ejecución. Un fichero SWF se compone de una serie de bloques con un tipo y unos datos que deben interpretarse en función de ese tipo. Los bloques con el código ActionScript son de tipo DoABC y contienen una estructura de datos llamada abcFile que almacena un pool de constantes, las definiciones de las clases y métodos, y los scripts en forma de cadenas de opcodes. Opcodes de bastante alto nivel, por cierto. Es decir, que no se limitan a operaciones básicas de acceso a memoria, manipulación de registros y control de flujo, como los mnemotécnicos de un microprocesador ordinario, sino que incluyen operaciones tales como instanciar un objeto de una clase o "escapar" un elemento XML. Como resultado de ese procesamiento de alto nivel, una parte importante de la máquina virtual es la gestión de nombres. De paquetes, de clases, de métodos, de variables, ... Algunos conocidos en tiempo de compilación, otros resueltos en tiempo de ejecución, pero todos ellos englobados bajo el término multinames, compuestos por un namespace y un name. Por ejemplo, el multiname "com.inmensia.flash.test:Main" se compone del namespace "com.inmensia.flash.test" y el name "Main". Para probar mi parser he generado un fichero SWF con FlashDevelop utilizando el siguiente código extremadamente sencillo: package {En la siguiente imagen puede verse el objeto abcFile resultante de la ejecución del parser y capturado desde Firebug: ![]() Puede verse como todas las estructuras están rellenas con los valores leidos del SWF. No obstante, el punto de entrada del código dentro un frame que viene indicado en otro bloque del fichero SWF. Más concretamente en uno de tipo SymbolClass. Este bloque almacena una lista de los símbolos de alto nivel almacenados en el fichero, con un id numérico y un nombre. El nombre del símbolo con id igual a 0 es el que sirve de punto de entrada para la ejecución del código contenido en el fichero. La secuencia completa que he seguido para encontrar el primer opcode de la clase "Main" del ejemplo es la siguiente: En el siguiente diagrama puede verse la secuencia de pasos seguida para localizar el punto de entrada saltando de estructura en estructura, además del contenido del bloque SymbolClass referido anteriormente: ![]() He dejado que se vea el pool de strings completo, para que se aprecie la lista de cadenas que se monta a partir de un ejemplo tan sencillo, y la importancia de los nombres dentro de la máquina virtual. Como se observa, se parte de "Main", o lo que es lo mismo, del namespace "" (vacío) y del name "Main". En el pool de strings se localiza el id 3 correspondiente al name, y en el pool de namespaces el id 1 correspondiente a un namespace con id de nombre 1 (vacío) y tipo 22 que indica que corresponde al nombre de un paquete. En la documentación existe una serie de constantes definidas para estos tipos. A continuación, con el id del name y del namespace se localiza el multiname dentro del pool de multinames. Y con el id de dicho multiname la clase asociada dentro del pool de instances. Finalmente, para cada clase existe un atributo iinit que es el id de su método de entrada (constructor), y que permite encontrar la lista de opcodes a ejecutar dentro del pool de method bodies. Como comprobación final he decompilado los opcodes para verificar que se correspondían con el código ActionScript de partida: 208 getlocal_0Sin entrar en mucho detalle, se observa que el método se limita a guardar el scope (ámbito) en la pila, llamar al constructor de la clase base (flash.display.Sprite) sin argumentos, y retornar sin devolver ningún valor. Lo que concuerda con lo esperado. Por último, comentar que este punto de entrada es para una clase concreta como la del ejemplo. El punto de entrada real del fichero [en su totalidad] está determinado por la propiedad init del último registro del pool de scripts dentro del objeto abcFile, que lo que hace precisamente es instanciar nuestra clase "Main" de ejemplo. ¿No encontró lo que buscaba?Utilice el buscador para encontrar más páginas en esta web o en toda Internet. |