-[ 0x05 ]-------------------------------------------------------------------- -[ Crack Symbian ]----------------------------------------------------------- -[ by blackngel ]----------------------------------------------------SET-33-- Crack Symbian -------------- Para seguir con el tema de symbian, voy a explicar como se pueden modificar aplicaciones programadas en este sistema operativo. Esto es valido para cualquier telefono Symbian, no solo el SX1. Esto incluye n-gage, Sendo, y la mayoria de los Nokias de nueva generacion. Oficialmente existen 10.000 aplicaciones disponibles, pero a decir verdad yo no me creo esta cifra; si hay mas de 1.000, me daria por contento. Las herramientas son: -un movil Symbian -una aplicacion que deseemos modificar. -desensamblador IDA o similar. -es bueno tener a mano el SDK de symbian. Al menos la documentacion. Las aplicaciones generalmente se descargan desde la pagina web del proveedor, y tienen extension *.sis Hay otro tipo de aplicaciones hechas en java que se proporcionan como un fichero *.jar y otro *.jad . Estos son programas en java, y no son objetivo de este articulo, ya que los explique en un numero anterior de SET. Lo primero es transferir la aplicacion hacia el movil: -por el puerto infrarrojos. Esto es lo que yo uso. -mediante BlueTooth. -copiandola en la tarjeta MMC usando un lector/escritor en el PC Este ultimo metodo no es confortable en los Nokia, porque la MMC esta debajo de la bateria, y para sacarla hay que desmontar el movil. En el SX1 esta en un lateral y se puede extraer incluso con el movil encendido. A continuacion se inicia una aplicacion interna al movil llamada instalador. Esta aplicacion se llama Z:\System\Libs\InstEng.dll que sigue las instrucciones que le dice el fichero *.sis Para ver el contenido de este fichero podemos usar la aplicacion SISTool by Alezz, del Z-Team. Por ejemplo, vamos a analizar la aplicacion FExplorer1.15 , que creo que todo el mundo la tiene, puesto que resulta extremadamente util. Sirve para manejar ficheros: mover, renombrar, transmitir por BlueTooth, ... Los ficheros incluidos en el instalador son: 1) License.txt 2) !:\system\apps\FExplorer\FExplorer.aif 3) !:\system\apps\FExplorer\FExplorer.app 4) !:\system\apps\FExplorer\FExplorer.rsc 5) !:\system\apps\FExplorer\FExplorer.mbm 6) !:\system\apps\FExplorer\EXETEST.EXE 7) !:\system\apps\FExplorer\keys.txt Usando SISTool se ve que el primer fichero tiene un indicador que dice que debe mostrarse durante la instalacion. Ademas presenta las opciones OK y NO para seguir con la instalacion o cancelarla. El programa instalador se encarga de la tarea de presentar este texto, hacer la pregunta, y recoger la respuesta. No es posible solicitar ningun numero de serie, ni nada que se le parezca. Los otros ficheros que empiezan por !:\ indican que se le presentara al usuario la posibilidad de instalarlo en distintas unidades de disco. Esto suele ser: E: para la tarjeta MMC, que es lo que yo voy a usar. C: para la memoria interna no-volatil. En nuestro ejemplo, no pide la unidad de destino 6 veces, sino que con la primera vez le vale. Existen otras posibilidades. Por ejemplo, una linea del tipo C:\system\data\FExplorer.dat siempre se guardara en la unidad C: . Esto es usado comunmente para ficheros de configuracion, claves de autorizacion, y control de uso. Mas tarde veremos un ejemplo, paciencia. Asi que tras responder (3 veces !) a las confirmaciones de instalar la aplicacion, la tenemos en e:\system\apps\FExplorer\FExplorer.app El fichero FExplorer.aif se puede abrir con la aplicacion SISTool by Alezz. Vemos que contiene AIF ID = 0x383A0010 App ID = 0xF17B1F10 1 string = "FExplorer" 2 iconos, con identificadores 000 (el dibujo) y 001 (la mascara) Todo esto sirve para que el menu principal sea capaz de presentar un icono, y el titulo de la aplicacion. El fichero FExplorer.mbm se puede abrir con la aplicacion MBMTool by Alezz. Vemos que contiene 22 dibujos, de los cuales la mitad son iconos, y la otra mitad son las mascaras. El fichero FExplorer.rsc se puede abrir con la aplicacion RSCTool by Alezz. Si todavia no te has convencido de que este tipo es un maestro, no se a que esperas. Vemos que contiene 313 objetos, aglutinados en 92 grupos. Los objetos son de 2 tipos: -numeros enteros de 4 bytes. -cadenas de caracteres, que van precedidas por un valor con su longitud. Existen otros tipos, pero lo normal es encontrarse solo con estos dos. Este fichero suele contener las palabras y frases que se usan en la aplicacion. Por ejemplo, si hay un menu con la palabra "Comprimir Memoria", es casi seguro que esta en este fichero. Es frecuente encontrarse que una aplicacion incluye varios ficheros FExplorer.r01, FExplorer.r02, ... FExplorer.rXX Cada fichero contiene las frases en un idioma distinto. El fichero *.r01 se usa cuando instalas la aplicacion en Ingles. El r02 sirve para Frances, r04 para espanyol, el r56 para Gujarati, del que puedes obtener mas informacion en http://en.wikipedia.org/wiki/Gujarati_language Por tanto el fichero *.sis incluye muchos lenguajes, pero solo uno de ellos se instala en el movil. Lo bueno es que este fichero es facil de modificar. Hay gente que ha traducido aplicaciones ajenas para adaptarlas a su propio idioma. Si bien esto no se puede considerar como un acto de crackear el programa, lo cierto es que es mejor pedirle permiso al autor. Quizas se alegre e incluya la traduccion en la siguiente version. Mas interesante es saber que la forma de acceder a uno de tales ficheros desde un programa Symbian es usar la funcion RResourceFile::OpenL Para leer los datos dentro de este fichero se usa la clase TResourceReader::Read_xxx Para acelerar la carga de menus, Symbian definio un fichero de extension *.rss que se compila y se mete en el *.rsc y se lee de un golpe usando la funcion CEikEdwin::ConstructFromResourceL(menu_ID); Cada opcion dentro del menu tiene un identificador unico. Este es un ejemplo de FCA00000.rss RESOURCE MENU_PANE r_FCA00000_menu { items = { MENU_ITEM {command = 0x0102; txt = "HacerAlgo";}, MENU_ITEM {command = 0x0103; txt = "OtraCosa";}, MENU_ITEM {command = 0x0104; txt = "MuchoMas";}, MENU_ITEM {command = EAknSoftkeyExit; txt = "Exit";} }; } Hay otro detalle digno de mencionar: cada aplicacion tambien tiene un identificador unico. En teoria hay que solicitarselo a la companyia Symbian, pero es mas comun inventarse uno propio. Si coincide con el de alguna otra aplicacion, mala suerte. En particular mi aplicacion tiene el identificador 0xFCA00000 Para obtener el identificador de cada menu simplemente hay que combinar ambos: 0xFCA00000 + 0x0102 = 0xFCA00102 Por lo tanto en el fichero FCA00000.rsc aparecen los bytes 02 01 0A FC que son la representacion en little-indian de 0xFCA00102 En el programa habra una intruccion del tipo: if(menu_elegido==0xFCA00102) { ...... } Este sera un buen punto de inicio para empezar a seguir el flujo del programa. Los programas Symbian solo funcionan en procesadores ARM, que usan un lenguaje ensamblador mas simple que el que encuentras en un ordenador PC. Para desensamblar los programas, la mejor herramienta que yo conozco es el IDA-Disassembler. Conoce las instrucciones ARM y saca un listado muy limpio. Por ejemplo me sorprendio que la secuencia de instrucciones MOV R0, 0x77 ADD R0, 0x100 la muestra como MOV R0, 0x177 haciendo que el listado sea mas comprimido que lo que sacan otros desensambladores. Por favor soporta a sus creadores y compralo: es una herramiente magnifica. Una cosa a recordar es que los programas siempre aparecen desensamblados a partir de la direccion 0x10000000. Cuando se cargan en memoria se ejecutaran en cualquier otra direccion de memoria, normalmente 0xFFF?0000 para los primeros 16 programas que se ejecuten. Como creo haber dicho en otro articulo, symbian es un sistema operativo en el que los programas completan el link en tiempo de carga. Lo explico: cuando compilas el programa que llama a una rutina del sistema operativo, no sabes a priori en que direccion de memoria esta dicha rutina. Solo sabes el nombre. Asi que el programa compilado contiene una referencia a un indicador fijo. Cuando quieras ejecutar el programa, el sistema operativo lo carga en memoria, y arranca un cargador (second-phase loader) que ajusta las direcciones de las rutinas usadas. Vamos a verlo con un ejemplo: Este es un trozo de un program escrito en lenguage C/C++ para symbian: RFile myFile; myFile.Replace(fileSession, "c:\\myfile", EFileWrite); se traduce en codigo ensamblador en algo asi: LDR R1, [r0+X] ; en algun sitio existe una referencia a fileSession LDR R2, =p_C_myFile ; puntero a un puntero al String "c:\\myfile" MOV R3, #0x200 ; EFileWrite es una constante que vale 0x200 BL stub_RFile_Replace ; rutina que saltara a RFile::Replace, la cual ; necesita 3 argumentos: R1, R2, y R3 ...... p_C_myFile DCD C_myFile ; puntero al String "c:\\myfile" C_myFile DCA "c:\\myfile" ; String "c:\\myfile" ...... stub_RFile_Replace: LDR R12, =p_Replace__5RFileR3RFsRC7TDesC16Ui ; direccion que apunta ; a la rutina destino LDR R12, [R12] ; carga el dato de dicha direccion BX R12 ; y salta ...... p_Replace__5RFileR3RFsRC7TDesC16Ui DCD Replace__5RFileR3RFsRC7TDesC16Ui Replace__5RFileR3RFsRC7TDesC16Ui IMPORT Replace__5RFileR3RFsRC7TDesC16Ui ...... por pasos: -primero se preparan los 3 argumentos necesarios para stub_RFile_Replace -luego se llama al stub -el stub lee en Replace__5RFileR3RFsRC7TDesC16Ui la rutina a la que debe saltar -este dato ha sido rellenado por el Sistema Operativo cuando ha cargado en memoria el programa Visto de otro modo, la rutina stub_RFile_Replace es equivalente a: int (void *)lista_funciones[]; int R12 = lista_funciones[index_p_Replace__5RFileR3RFsRC7TDesC16Ui]; (void *)funcion = *(R12); call funcion(R1, R2, R3); Si no lo has entendido bien, te recomiendo que consultes algun otro documento en el que explique la carga dinamica de programas; es una tecnica muy comun en sistemas operativos de disco. Por eso es posible saber a cuales funciones llama un programa. Esto lo aprovecha IDA y muestra algo asi: 10003C40 MOV R0, R5 10003C44 BL stub_DriveAndPath__C10TParseBase ; TParseBase::stub_DriveAndPath(void) 10003C48 ADD R3, SP, #0x18 Aunque no sepamos lo que hace este programa en la rutina en 10003C40, sabemos que llama a TParseBase::DriveAndPath(void), que es una funcion que retorna la unidad y la ruta en la que esta instalado el programa. A partir de aqui empieza la tarea de investigacion. ----------------------------- Como ya es habitual, vamos a trabajar en un caso real. En el movil SX1 de Siemens es posible actualizar uno mismo el firmware que viene incluido de serie. No esta al alcance de cualquiera poder alterarlo para que haga las cosas que uno quiere, pero hay un grupo llamado Z-TeAm que ha hecho realmente muchos cambios. En un telefono Symbian existe las unidades: - Z: que contiene los programas. Es de solo lectura. Ocupa 16 Mb. - E: que esta en la tarjeta MMC. Obviamente aqui se pueden copiar programas - C: tambien es de lectura y escritura. Ocupa 4 Mb. - A: que es de solo lectura. Teoricamente. Ocupa 4 Mb. Hay 1Mb libre Aqui es donde esta lo bueno: el Z-TeAm ha conseguido que sea posible meter programas en esta ultima unidad A: , aprovechando el espacio libre. Pero no se puede escribir desde el propio telefono, sino desde un ordenador. Basicamente uno tiene que crear una estructura de directorios similar a la que quiere que vaya a A: , y convertirlo en un mega-fichero de 4 Mb. Luego se mete en el movil. La unidad A: contiene unos cuantos programas que no son imprescindibles. Ademas se pueden meter en la memoria MMC. Pero en A: queda espacio de sobra para instalar unos cuantos programas. Uno de los programas mas utiles es el FExplorer 1.15 mencionado anteriormente. Asi que seria recomendable tenerlo en la unidad A para que siempre estuviera accesible aunque cambie la tarjeta MMC. El problema es que FExplorer se empenya en buscar el archivo de configuracion en la misma unidad en la que esta instalado. Obviamente no le gusta que este en A: porque no puede sobre-escribirlo. La solucion es enganyarlo para que lo lea desde C: y no desde A: . El archivo de configuracion se llama FEgen.ini Cargamos FEXplorer.app en el desensamblador IDA y al cabo de 3 minutos produce el codigo desensamblado. La palabra "FEgen" la encuentro en: 100195B8 aFegen unicode 5, ,0 y un poco mas abajo, encuentro 100195D0 a_ini unicode 4, <.ini>,0 busco referencias a estas direcciones: 10003C90 off_10003C90 DCD aFegen que a su vez viene desde: 10003C74 ADD R4, R4, #8 10003C78 ADD R0, SP, #0x10 10003C7C LDR R1, =aFegen 10003C80 BL s__7TPtrC16PCUs ; TPtrC16::TPtrC16(ushort const *) 10003C84 MOV R0, R4 O sea, que llama a la funcion TPtrC16::TPtrC16 que segun el manual de Symbian sirve para iniciar una cadena. No es de extranyar que esta rutina tan comun se llame en 350 sitios distintos a lo largo del programa. Un poco mas adelante hace: 10003CC0 LDR R1, =a_ini 10003CC4 BL s__7TPtrC16PCUs ; TPtrC16::TPtrC16(ushort const *) 10003CC8 MOV R0, R4 10003CCC MOV R1, SP 10003CD0 BL s_Append__6TDes16RC7TDesC16 ; TDes16::Append(TDesC16 const &) que sirve para concatenar una cadena a otra. A mi me parece que vamos en la direccion adecuada. Ahora falta ver donde le ha antepuesto el nombre del directorio. Para ello investigo el codigo antes de 10003C74 y me encuentro con: 10003C44 BL stub_DriveAndPath__C10TParseBase .... 10003C58 BL s_Copy__6TDes16RC7TDesC16 y la documentacion del API me confirma que TParseBase::DriveAndPath me devuelve una cadena conteniendo la unidad y el directorio. Por eso deduzco que el codigo original es algo asi: String unidad_y_directorio; String ruta_completa; unidad_y_directorio = TParseBase::DriveAndPath(); ruta_completa.Copy(unidad_y_directorio); ruta_completa.Append(String("FEgen"); ruta_completa.Append(String(".ini")); Ahora, para conseguir eliminar la unidad de disco de la ruta, tengo que hacer unidad_y_directorio = "C:\" + TParseBase::Path(); es decir, que no llame a TParseBase::DriveAndPath() , sino a TParseBase::Path(); lamentablemente no existe la rutina TParseBase::Path(); Pero la solucion mas rapida es hacer que no use en absoluto el nombre del disco donde esta la aplicacion: String unidad_y_directorio; String ruta_completa; unidad_y_directorio = TParseBase::DriveAndPath(); //ruta_completa.Copy(unidad_y_directorio); // <--comentar esta linea ruta_completa.Append(String("c:\FE"); // el archivo es c:\FE en vez de FEgen ruta_completa.Append(String(".ini")); En otras palabras: no uso la ruta original de la aplicacion, sino que el archivo al final sera c:\FE.ini ?Porque no he usado c:\FEgen ? Pues porque "FEgen" ocupa 5 caracteres, y por tanto "c:\FEgen" ocuparia 8, lo que me obligaria a hacer hueco en el programa. Recordar que estoy modificando el archivo binario, no el codigo fuente. Cuando se altera un binario, no es facil hacer hueco en medio del programa. Los cambios son: ..... 10003C58 NOP ; inicialmente era BL s_Copy__6TDes16RC7TDesC16 ..... 100195B8 aFegen unicode 5, ,0 ; inicialmente era ..... Para los que esten interesados en codigo binario, la instruccion BL s_Copy__6TDes16RC7TDesC16 tiene codigo 394800EB y la instruccion NOP tiene codigo 0000A0E1 Para probarlo, modifico FExplorer.app y lo transfiero al movil. Inicio la aplicacion y confirmo que ha creado el fichero c:\FE.ini Y esta todo listo para meterlo en la unidad A: tal como queria conseguir. Como veis, no es mucho mas distinto que desensamblar programas para PC. ------------------------------------ Al principio he comentado la estructura de un fichero .sis de instalacion. Ahora me gustaria anyadir que hay algunas posibilidades mas complejas. Una de ellas es que se pueden instalar distintos ficheros dependiendo de: -fabricante: Ericsson, Motorola, Nokia, Panasonic, Psion, ... -modelo -velocidad de la CPU -memoria -numero de teclas -numero de luces LED -tamanyo de pantalla -lenguajes disponibles .... Otra funcionalidad es que se puede ejecutar la aplicacion tras la instalacion. Esto es util cuando el programador desea: -crear una serie de directorios -verificar que existe un cierto fichero -solicitar un codigo de proteccion o numero de serie -conectarse a una pagina web para obtener algun otro dato -enviar un SMS para informar al programador ..... y en caso de que alguna condicion no sea correcta, se devuelve un codigo de error al instalador, que automaticamente desinstala el programa. La mayoria de los programas contienen unicamente: -la aplicacion principal XXX.app -el icono y nombre del programa en XXX.aif -los dibujos que usa XXX.mbm -los sonidos XXX.mid -los mensajes en XXX.rsc , XXX.r01, XXX.r02 , ... -archivo de configuracion XXX.ini o XXX.cfg -ayuda o notas en XXX.hlp o XXX.txt Algunos programas mas complejos incluyen: -librerias XXX.dll -programas servidores XXX.exe para tareas criticas -reconocedores XXX.mdl -bases de datos XXX.db o XXX.dat Son particularmente utiles los ficheros XXX.mdl que se ejecutan cuando se inicia el movil. Si estas pensando en crear un antivirus (o un virus) , un protector de pantalla (o un sniffer de teclas), o algo que se parezca a un LKM (Loadable Kernel Module) debes mirar en esta direccion. ------------------------------------ Dado que este articulo explica como modificar aplicaciones Symbian, voy a explicar otra tecnica. Por si no ha quedado claro lo repito otra vez: cada programa, tal como esta en el disco (MMC o C:), contiene solo referencias a rutinas del sistema operativo. Cuando se carga en memoria, esas referencias se convierten en las direcciones especificas de las rutinas. Estas direcciones son distintas segun el modelo de movil, e incluso segun la version del Sistema Operativo. Por ejemplo, para el Siemens-SX1 existen mas de 20 versiones distintas de sistema operativo, segun el idioma con que han sido fabricados: la version 15 en Espanyol y la version 15 en Ruso tienen distintas direcciones de rutinas. Por cada rutina externa que es invocada desde el programa, debe de haber un "lanzador" hacia ella. Eso se conoce como Stub. Aqui hay un par de ejemplos: .... ;--------------------------------------------------------------------------- stub_CCoeControl::SizeChanged(void) LDR R12, =SizeChanged__11CCoeControl LDR R12, [R12] BX R12 off_1001F674 DCD SizeChanged__11CCoeControl ; CCoeControl::SizeChanged(void) ;--------------------------------------------------------------------------- stub_CCoeControl::PositionChanged(void) LDR R12, =PositionChanged__11CCoeControl LDR R12, [R12] BX R12 off_1001F684 DCD PositionChanged__11CCoeControl ; CCoeControl::PositionChanged(void) ;--------------------------------------------------------------------------- .... Si un programa llama a 200 rutinas externas (creeme, 200 es un numero normal) entonces hay 200 stubs. Vamos a analizar uno cualquiera de estos stubs. -Siempre usa 3 instrucciones y 1 dato ; cada uno de estos elementos ocupa 4 bytes, lo cual da 16 bytes -todos hacen lo mismo; simplemente cambia la direccion desde la que obtienen la direccion de la rutina de destino. (Si, es una direccion que apunta a otra direccion) -usan el registro R12, sin importarles lo que hubiera antes. Esto parece indicar que R12 es realmente de usar y tirar. Si recordais otro articulo anterior para el Siemens S45, yo contaba que seria util hacer un traceador para saber cuales rutinas eran llamadas por un programa. Vamos a ver si tambien lo puedo hacer para Symbian. El objetivo es definir una rutina que se llame cada vez que pase algo interesante, y que diga de donde viene, a donde va, y que datos usa. ?Como se define "sucede algo interesante"? Pues muy facil: cualquier llamada al sistema operativo es interesante. Puedo interceptar cada uno de los stubs: en lugar de stub_XXX(void) LDR R12, =XXX LDR R12, [R12] BX R12 off_XXX4 DCD XXX ; XXX lo transformo en stub_XXX(void) LDR R12, =XXX LDR R12, [R12] B mi_debugger ; <---- esta es la linea que cambio off_XXX4 DCD XXX ; XXX Hay que tener cuidado en varios aspectos: 1-la rutina mi_debugger no puede cambiar ningun registro 2-debe finalizar con BX R12 , como en el original 3-el programa original debe modificarse para incluir esta rutina debugeadora. Por tanto hay que buscar un hueco libre en algun lugar del programa; por ejemplo un string que no se use. 4-debido a la arquitectura ARM, la rutina mi_debugger debe estar en el mismo segmento de memoria que stub_XXX La primera restriccion es facil de cumplir: solo hay que guardar temporalmente en la pila los registros que necesitemos usar, y al final hay que recuperar los valores originales. Lo segundo es trivial. La tercera condicion obliga a usar un debugger pequenyo. Pero hay un truco: podemos saltar a cualquier otra rutina. Lo malo es que hay que actuar manteniendo la cuarta regla. Ahora, olvidate por un momento de que los programas se cargan en direcciones de memoria virtuales: suponte que existe una direccion fija (llamada mi_debugger_grande) y que cualquier programa puede saltar a ella. (Aviso: el siguiente parrafo solo lo entenderas si sabes de arquitectura ARM) Para saltar a esta rutina podemos usar la instruccion: - B (branch) , pero solo permite saltar al mismo segmento de memoria, es decir, esta limitado a saltos de maximo 0xFFFF bytes - BL (branch location), que admite saltos largos pero modifica el registro LR - BX (branch extended), que necesita un registro, en la forma BX Rb Usare este tercer modo. Ahora necesito un registro Rb que pueda corromper sin alterar el programa, por ejemplo R11 porque no he visto ningun programa que lo use. Es cierto que lo usa el kernel a veces, pero no interfiere. Entonces queda: mi_debugger: LDR R11, =mi_debugger_grande BX R11 off_XXX3 DCD mi_debugger_grande Y ahora es cuando viene la sorpresa: de verdad existe tal direccion de memoria ! De hecho existen muchas, por ejemplo 0x85740000. La explicacion vendra en un parrafo posterior. Por tanto queda (en pseudo-codigo) org 0x85740000 mi_debugger_grande: guarda_registros dump_registros dump_direccion_origen dump_direccion_destino restaura_registros BX R12 Si te interesa de verdad este debugger, sigue leyendo. Para guardar los registros usare la pila. Seguro que modificare los registros R1, R2, ... R7 asi que los puedo almacenar todos con una unica instruccion STMFD SP!, {R1-R7} ; equivalente a push R1, push R2, ... push R7 Decido que para almacenar los datos interesantes usare la direccion de memoria 0x85750000 y siguientes: LDR R7, =0x85750000 El primer dato de esta zona sera un contador que me dice cuantos datos he guardado, y me sirve para saber donde meter el siguiente. LDR R6, [R7] Ahora debo incrementarlo. Cada vez que se invoca al debugger grabare 8 datos de 4 bytes. Asi que el contador se incrementa en 32 cada vez. En hexadecimal 32 vale 0x20 ADD R6, #0x20 y lo vuelvo a meter en 0x85750000 STR R6, [R7] Ahora debo apuntar al primer byte que esta libre: ADD R7, R6 y empiezo a meter los datos; primero los argumentos R1, R2, R3 enviados a la rutina: STR R1, [R7+#0x00] STR R2, [R7+#0x04] STR R3, [R7+#0x08] El registro R0 tambien es util STR R0, [R7+#0x0C] Ahora la direccion origen. En Symbian, las rutinas se llaman con la instruccion BL stub_XXX que hace que el registro LR almacene la direccion a la que se debe retornar. Por eso lo puedo "dumpear" haciendo STR LR, [R7+#0x10] La direccion destino es justamente R12 STR R12, [R7+#0x14] Y ahora me queda hueco para otros 2 registros: uno es la pila SP (Stack pointer). Pero para obtener el valor original debo substraer los 7 datos R1-R7 que he metido al principio, que ocupan 4 bytes cada uno MOV R1, SP SUB R1, #0x07*4 STR R1, [R7+#0x18] y el otro es el registro PC, que contiene los flags (N, Z, V, I). El resto de los flags no interesan, pero aun asi los guardo tambien STR PC, [R7+#0x1C] recupero los registros de la pila: LDMFD SP!, {R1-R7} ; equivalente a pop R7, pop R6, ... pop R2, pop R1 y salto a donde debo saltar BX R12 Para poner todo el tinglado en marcha necesito varios programas: -Uno en ensamblador ARM con las 20 instrucciones anteriores. Lo compilo con GCC-ARM y me genera un mini-fichero de 20*4 bytes. Al resultado lo llamo 0x85740000.bin -Otro en el PC que transfiera este fichero al movil. Dado que tengo infrarrojos en el movil y en el ordenador, uso el IrFtp de Windows. -Otro en el movil que cargue 0x85740000.bin en la direccion 0x85740000 . Este programa lo hago en Symbian. Lo explicare en un parrafo posterior -El programa victima, adecuadamente parcheado -para eso me hago un programa parcheador. Basicamente: -busca LDR R12, [R12] ; bytes 00C09CE5 BX R12 ; bytes 1CFF2FE1 -y los substituye por LDR R12, [R12] ; bytes 00C09CE5 B mi_debugger ; bytes xyzt00EA ,donde xyzt depende de donde puedo meter mi_debugger -busca un hueco libre donde escribir el lanzador mi_debugger: LDR R11, =0x85740000 BX R11 off_XXX3 DCD 0x85740000 -como ocupa 3 instrucciones, necesito 3*4 bytes. Estos 12 bytes los localizo yo a mano. Normalmente lo que hago es machacar una zona del programa que me parezca que no se usa. -Otro programa que vuelca la traza generada a partir de 0x85750000 -Para transferirlo al PC uso de nuevo el IrFTP -Hago otro programa para visualizar estos datos. Las rutinas "destino" son del sistema operativo, por lo que puedo darles nombre. Lo unico que necesito es saber la direccion donde estan almacenadas cada una. Las rutinas "origen" son del programa victima, y obviamente no puedo saber sus nombres. En esto consiste el arte del desensamblado, ?no? -------------------------------- Este es el programa Symbian que mete el fichero 0x85740000.bin en la direccion 0x85740000 RFs fileSession; TInt open_result, direccion, valor; TBuf8<4> four_bytes; _LIT(x85740000_bin,"c:\\0x85740000.bin"); fileSession.Connect(); // conecta con el servidor de archivos open_result=filep.Open(fileSession, x85740000_bin, EFileRead); // abre el fichero 0x85740000.bin if(open_result==KErrNone) // si todo ha ido bien ... { direccion = 0x85740000; for(i=0;i<20*4;i+=4) // bucle de 20 instrucciones { filep.Read(four_bytes); // cada instruccion ocupa 4 bytes, que // meto en un array valor=four_bytes[0]%256 // y lo meto en un TInt, que ocupa 4 bytes + (four_bytes[1]%256)*256 + (four_bytes[2]%256)*256*256 + (four_bytes[3]%256)*256*256*256 ; Mem::Copy(&valor, direccion, sizeof(TInt)); // lo meto en memoria direccion+=4; // y salto a la siguiente direccion } } El programa inverso que mete las tramas en un fichero es similar, usando como origen la direccion 0x85750000 . ------------------------- Como ejemplo, voy a modificar el programa Spectrian V1.51 by White Cloud. Esta aplicacion es un emulador de ZX-Spectrum para telefonos moviles. Lo puedes obtener desde www.whitecloudsoftware.com Se compone de varios ficheros, y el programa se llama Spectrian.app Al ser un programa comercial, necesita un numero de serie, o de lo contrario caduca a los 30 dias. Simplemente por diversion, voy a intentar eliminar esta limitacion. Una vez mas te emplazo a pagar por el software que uses. Primero hay que ver como actua el programa: lo arranco, y veo que si no esta registrado, aparece un mensaje indicando el modo de registrarlo (pagando, claro). Este mensaje permanece durante 3 segundos, que se que hay que transformarlo en milisegundos, dando la cifra 3000000 , o sea, 0x2DC6C0. Desensamblo con IDA, y busco los sitios donde se usa el dato 0x2DC6C0. Lo encuentro en la rutina 1000262C. Cambio el valor a 1 segundo con mi editor hexadecimal, transfiero el programa parcheado, y ahora efectivamente el mensaje aparece solo durante 1 segundo. Pero con esto no consigo eliminarlo. Asi que voy a usar mi debugger. Esta aplicacion usa (10020EB8-1001EBB8)/4 = 0x8C0 stubs, desde 1001EBB8 ; CBase::newL(unsigned int) 1001EBB8 LDR R12, =newL__5CBaseUi 1001EBBC LDR R12, [R12] 1001EBC0 BX R12 1001EBC4 off_1001EBC4 DCD newL__5CBaseUi ..... hasta ..... 10020EB8 ; PlpVariant::GetMachineIdL(TBuf<128> &) 10020EB8 LDR R12, =GetMachineIdL__10PlpVariantRt4TBuf1i128 10020EBC LDR R12, [R12] 10020EC0 BX R12 10020EC4 off_10020EC4 DCD GetMachineIdL__10PlpVariantRt4TBuf1i128 Parcheo estas 2240 rutinas haciendo que salten a la direccion libre 0x10022550 org 0x10022550 mi_debugger: LDR R11, =mi_debugger_grande BX R11 off_XXX3 DCD mi_debugger_grande mi_debugger_grande DCD 85740000 Y en la direccion 0x85740000 coloco mi debugger. Pongo en marcha el programa victima, y una vez que ha salido el mensaje diciendo que no esta registrado, vuelco la memoria a partir de 0x85750000, que es donde mi debugger ha escrito la traza de las rutinas interceptadas. Por ejemplo, una de tales trazas me dice R0=00401628 R1=004037C4 R2=00000004 R3=80000368 R12=502801F0 R4=00000000 LR=FFFD3934 SP=00403844 ?Como se interpreta esto? Lo primero es el dato LR=FFFD3934 que indica la direccion del programa desde el que se ha llamado a la rutina debugeada. El desensamblador IDA cree que todos los programas se ejecutan a partir de la direccion 0x10000000. Esto no es del todo correcto, pues el cargador de Symbian se encarga de buscar una direccion de memoria libre en el propio telefono. Debido al sistema de memoria paginada, esto suele ser 0xFFF?0000 , en nuestro caso 0xFFFD0000 Por tanto LR=FFFD3934 equivale a la direccion 0x10003934 en el desensamblado. Vamos a mirar el codigo en esa direccion: 10003928 MOV R2, #4 1000392C BL sub_1001EE78 10003930 ADD R0, SP, #0x148 10003934 BL sub_10020EB8 <---- aqui lo hemos interceptado 10003938 MOV R4, #0 1000393C ADD R5, SP, #0x40 Y tambien 10020EB8 ; PlpVariant::GetMachineIdL(TBuf<128> &) 10020EB8 LDR R12, =GetMachineIdL__10PlpVariantRt4TBuf1i128 10020EBC LDR R12, [R12] 10020EC0 BX R12 10020EC4 off_10020EC4 DCD GetMachineIdL__10PlpVariantRt4TBuf1i128 Combinando con R12=502801F0 esto quiere decir que la rutina PlpVariant::GetMachineIdL(TBuf<128> &) esta (en mi modelo de movil) en la direccion 0x502801F0 y Spectrian la invoca desde 10003934 . En otros modelos de moviles, estara en otra direccion. Mas tarde explicare una consecuencia importante de esto. Siguiendo con la explicacion de la traza, la rutina PlpVariant::GetMachineIdL necesita un argumento TBuf<128> & que combinado con R1=004037C4 significa que la variable usada como argumento esta en la direccion 004037C4 Si tuviera un debugger en condiciones podria ver el valor de esta variable. Lo importante es saber que el segmento 0x00400000 contiene los datos del programa en ejecucion, es decir, toda la zona de variables completa. Asimismo, R0=00401628 indica que la zona de variables locales a esta rutina esta en la direccion 00401628. El valor R2=00000004 es consistente con la linea 10003928 MOV R2, #4 Por hacer un pequenyo resumen: -valores de 0x0040???? indican variables del programa -valores de 0x50?????? indican direcciones de rutinas del sistema operativo -valores de 0xFFF????? rutinas del programa, equivalente a 0x100????? en IDA Ya que tenemos las trampas preparadas, vamos a ver que atrapamos. En el programa encuentro la palabra "RegCode2" que parece bastante sugestiva: 1002254C aRegcode2 unicode 8 , ,0 Esto es tipico de Symbian: cada palabra es en realidad una estructura de datos: -el primero (ocupa 4 bytes) es la longitud de la palabra -el segundo es la palabra, donde cada letra ocupa 2 bytes en formato unicode -el ultimo (2 bytes) es 00 00 , indicando el fin de cadena A lo que iba: IDA me dice que esta palabra esta referenciada desde 10003384 LDR R1, =Regcode2 10003388 ADD R0, SP, #0x28 1000338C SUB R0, R0, #4 10003390 BL Compare__C7TDesC16RC7TDesC16 ; TDesC16::Compare(TDesC16 const &) 10003394 CMP R0, #0 10003398 BNE loc_100033B8 O sea, que en [SP, #0x28] hay un puntero, y se compara con la palabra "Regcode2" Si no son iguales, salta a loc_100033B8 Si son iguales, se hace ... 100033AC BL Val__6TLex16Rl ; TLex16::Val(long &) 100033B0 LDR R3, [SP,#0x59C+var_59C] que sirve para transformar una cadena del tipo "1234" en su valor numerico 1234. Bueno, parece que esta es una buena rutina para investigar. Asi que busco en mis trazas donde se ha llamado a esta rutina TLex16::Val(long &) A partir de ahi, con el desensamblado en una ventana, y el traceado en otra, me hago una idea de lo que hace el programa, y dispongo de la posibilidad de analizarlo off-line. Para completar este parrafo, dire que hay un fichero Spectrian.prf que contiene la cadena Regcode2=xxxxxxx y la rutina previamente analizada se encarga de leerla usando TFileText::Read(TDes16 &) Mas tarde, se llama a PlpVariant::GetMachineIdL(TBuf<128> para averiguar el numero de serie unico del movil. Luego se calcula un codigo y se compara con xxxxxxx usando TDesC16::Compare(TDesC16 const &)const Si la comparacion no es correcta, entonces se hace: 10000A30 MOV R5, #0 mientras que si el programa esta satisfactoriamente registrado entonces 10000A24 MOV R5, #1 saltando en ambos casos a sub_10003824 donde se verifica este valor. Si es distinto de 0, entonces no aparece la pantalla de registro. Resulta trivial parchear el programa para que evite esta ultima comparacion, y siempre se piense que el progama esta registrado. Ahora, a jugar al Saimazoom ! --------------------- Otro programa muy util para Symbian es TomTomCityMaps. Contiene planos de varias ciudades del mundo. Existe otras versiones TomTomMobile y TomTomNavigator pero ocupan mucha mas memoria. El problema con CityMaps es que no funciona en el SX1. Puedes iniciar el programa, pero se queda en la pantalla de inicio. Cuando pulsas una tecla da un error, aunque no finaliza el programa. No tengo ni idea de si podre arreglarlo, pero al menos lo intentare. La estrategia es la misma: interceptar todas las rutinas para ver lo que hacen. Cuento con la ventaja de que el programa funciona en un movil Nokia, por lo que puedo instalar el programa parcheado en ambos. Si una rutina devuelve un resultado totalmente diferente (mas alla de lo razonable) entonces habra que investigar en detalle dicha rutina. El programa llama a (100624D0-1005F7D4)/4 = 0x0B3F rutinas del sistema operativo, y hay 12 bytes libres en 100634A0, suficientes para poner mi_debugger. Arranco el programa, y en cuanto da el mensaje de error, vuelco la memoria a partir de 0x85750000. Una de las ultimas rutinas ejecutadas ha sido: R0=0040F838 R1=00407304 R2=100059BE R3=80000368 R12=5015A6DC R4=00000000 LR=FFF548F0 SP=0040873C O sea, que se llama desde FFF548F0 (equivalente en IDA a 100048F0) a la rutina en 5015A6DC. Segun IDA, la rutina es CListBoxData::Reserved_2(void) Esto es un poco raro. El codigo desensamblado que precede a 100048D8 no contiene llamadas a rutinas relacionadas con la clase CListBoxData , sino que son llamadas a AVKON , por lo que me extranya que se llame a una rutina que, ademas, tiene el extranyo nombre "Reserved_2". El desensamblado es: 100048DC MOV R1, R0 100048E0 MOV R6, #0 100048E4 ADD R4, SP, #0x2C 100048E8 MOV R0, R4 100048EC LDR R2, =(loc_100059BC+2) 100048F0 BL sub_10060F34 ; CListBoxData::Reserved_2(void) 100048F4 MOV R0, R4 100048F8 BL sub_100617F4 ; TRect::Width 100048FC ADD R1, SP, #0x1C 10004900 STR R0, [SP,#0x98+var_7C] 10004904 STR R6, [R1,#4] 10004908 MOV R0, R5 1000490C BL sub_10061804 ; TSize::TSize Tambien hay que fijarse en que justo antes de llamar la rutina en 100048F0 se establecen los argumentos R0, R1 y R2, lo cual no es consistente con que CListBoxData::Reserved_2(void) no acepte argumentos. Esto me hace sospechar que IDA no ha desensamblado bien la rutina. La manera de comprobarlo es mirar la rutina que hay en R12=5015A6DC Lo he mencionado en otro articulo, pero merece la pena repetirlo: yo tengo un listado completo de las direcciones de las rutinas del mi movil Siemens-SX1. No tengo el codigo fuente de Symbian, pero se el nombre de cada rutina, y con eso y un poco de imaginacion me hago una idea de su uso. En particular miro R12=5015A6DC y descubro que es CPeriodic::Start(TTimeIntervalMicroSeconds32, TTimeIntervalMicroSeconds32, TCallBack) y no CListBoxData::Reserved_2(void) como IDA me habia dicho. Esto tiene mejor pinta. Esta rutina admite 3 argumentos, y el tercero es la direccion de una rutina que se llamara cuando transcurra el tiempo establecido. En mi caso esta rutina CallBack se define en 100048EC LDR R2, =(loc_100059BC+2) El codigo 100059BC MVN R7, #0 100059C0 LDR R1, [R5,#0xA0] 100059C4 ADD R2, R4, R4,LSL#1 100059C8 RSB R2, R4, R2,LSL#3 parece ciertamente una rutina, pero hay algo intrigante: ?Porque se llama a loc_100059BC+2 ? Esto significa saltar en medio de la instruccion MVN R7, #0 y eso no es posible. O bien salta a 100059BC, o a 100059C0. Nunca a 100059BC+2 En la arquitectura ARM, las instrucciones estan siempre en direcciones multiplo de 4. Al menos eso es lo que dice el manual de ARM. Lo que me extranya es que funcione en un Nokia. Tras posteriores investigaciones concluyo que el Nokia siempre redondea las direcciones hacia el multiplo de 4. Pero el SX1 no lo hace. Asi que el cambio es evidente: en 100048EC debe apuntar a loc_100059BC en vez de loc_100059BC+2 Hago el cambio, y el programa ahora funciona ! Ya puedo ir a Valencia sin temor a perderme por sus calles. ------------- Como he dicho antes, cada modelo de movil tiene las rutinas del sistema operativo en direcciones de memoria distintos. La carga dinamica de programas convierte las direcciones indexadas en direcciones reales, y IDA es capaz de interpretarlas, aunque a veces se equivoque. Mi listado del SX1 incluye mas de 30.000 rutinas del sistema operativo, aunque posiblemente menos del 80% son usadas por algun programa. En el movil existe una tabla que contiene las direcciones de todas las rutinas. En el SX1 esta tabla esta en 0x50F00000 y llega hasta 0x50F25000 , haciendo un total de 40.000 rutinas. En el Nokia N70, van desde 0x500FF000 hasta 0x50130000, unas 50.000 rutinas. Si cambiamos en la ROM la direccion de esta rutina, podemos hacer que salte a una rutina propia. En los moviles Siemens es posible actualizar la memoria uno mismo. En los Nokia supongo que tambien, aunque creo que hace falta un cable especial. Sea la funcion CCoeControl::SetDimmed(int) que en mi SX1 esta en la direccion 0x5065C93C, referenciada desde 0x50F16340 que sirve para ocultar(1) o mostrar(0) un menu. Sin duda, se llamara haciendo LDR R12, =SetDimmed__11CCoeControli LDR R12, [R12] BX R12 off_10000F1C DCD SetDimmed__11CCoeControli Para saber donde esta ubicada esta rutina en el Nokia N70, hago un programa en Symbian que oculta el menu. Lo parcheo con mi debugger e intercepto la llamada a CCoeControl::SetDimmed(int) Miro el registro R12, que contiene la direccion real de la rutina, y averiguo que esta en 0x50787148 Supongamos que queremos que nunca se oculten los menus en ninguna aplicacion. Obviamente puedo parchear la rutina 5065C93C (o 50787148 en el N70), pero es mas flexible hacer: -hacer que 0x50F16340 no apunte a 0x5065C93C, sino a 0x5071BE90 -buscar un espacio libre en la ROM, por ejemplo en 0x5071BE90 -desensamblar la rutina en 5065C93C -modificarla a mi gusto, es decir, haciendo que no considere el primer argumento, sino que siempre muestre el menu -compilarla usando el GCC-ARM o el compilador Kiel -meter el codigo generado en la direccion 0x5071BE90 Esto me permite modificar el sistema operativo a mi gusto, siempre que sea capaz de entender lo que hace la rutina parcheada, claro. --------------------------------------------- Uno de los problemas mencionados es que IDA no es siempre capaz de entender correctamente las llamadas a rutinas externas. Un programa Symbian de tipo APP contiene una cabecera llamada E32ImageHeader o TRomImageHeader definido en el SDK en e32rom.h , definiendo los parametros del programa, tales como version, fecha de construccion, tamanyo de la pila, numero de librerias usadas, y nombres de tales librerias. Por cada libreria hay una lista de las funciones usadas dentro de ella. Por ejemplo, hago un programa prueba.app que llama a TFindLogicalChannel::Next(TFullName& aResult) que segun la documentacion del SDK, esta declarado en e32std.h y tengo que linkar con la libreria euser.lib que usara euser.dll Por eso IDA muestra: ; Segment type: Externs .... ; Imports from EUSER[100039e5].DLL .... IMPORT Next__19TFindLogicalChannelRt4TBuf1i256 .... Vemos que incluye las palabras TFindLogicalChannel y Next pero ?que son todos esos numeros? Pues son los tipos de argumentos. Por ejemplo, una longitud de TBuf se llama "i1". Asi que empezando por el final: TBuf1i256 quiere decir que el argumento recibido es (TBuf<256> &) que es lo mismo que TFullName& aResult Luego, Rt4 es un puntero a TBuf . Despues, _19T significa que es un metodo publico de la clase TFindLogicalChannel. En realidad esto se puede deducir de los ficheros *.h del SDK. Como IDA no es capaz de entender los argumentos ni los datos de salida, presenta el nombre largo, y eres tu el que tiene que interpretarlos. Ahora bien, la palabra "TFindLogicalChannel" no esta dentro de prueba.app , asi que la pregunta es ?de donde los saca IDA ? Si miras el programa prueba.app en binario veras que Next__19TFindLogicalChannelRt4TBuf1i256 esta representado por los bytes 0xFC020000 que pasados a little-indian son 0x000002FC o sea 764 en decimal. Ahora vas al directorio del SDK donde tengas euser.lib que en mi caso es C:\Symbian\6.1\Siemens\SX1\bin\epoc32\release\armi\urel y haces ar -xv euser.lib ds00764.o el cual extrae de la libreria euser.lib el fichero ds00764.o Dentro de el encuentras la palabra Next__19TFindLogicalChannelRt4TBuf1i256 como era de esperar. Asi que IDA debe tener en algun sitio una lista que le dice que la liberia euser.lib contiene la rutina 0x000002FC y se llama Next__19TFindLogicalChannelRt4TBuf1i256 Y algunas de las rutinas no contienen el nombre correcto. Por eso se confunde con alguna rutinas. Lamentablemente no he encontrado esta lista en IDA, asi que supongo que esta comprimido. Pero lo que si puedo hacer es ayudarle: 1-dejo que desensamble el programa (quizas con algun error) 2-lo exporto a un fichero de texto 3-extraigo la zona de rutina importadas 4-miro las librerias, ej. user.dll 5-miro las funciones, ej. 0x000002FC 6-lo paso a decimal: 764 7-extraigo la funcion 764 de user.lib usando "ar" 8-saco el nombre de la rutina desde el fichero extraido ds00764.o 9-saco los nombres de los argumentos con la utilidad dumpbin 10-los meto en un fichero prueba.idc 11-le digo a IDA que re-lea los nombres de las rutinas desde prueba.idc Para los pasos 7-9 sigo las instrucciones de Mika Raento en www.cs.helsinki.fi/u/mraento/symbian/reverse.html que basicamente explica como obtener los nombres de los argumentos (proceso conocido como "demangling"). Tambien uso este procedimiento para analizar el listado producido por mi_debugger. Recordar que R12 vale la rutina Symbian que es invocada LR es la rutina invocante Mencionar que el SDK incluido en IDA 4.9 permite arreglar estos fallos y regenerar el archivo que contiene la lista de funciones externas. Pero esto lo dejo para otro articulo en el que contare cosas sobre IDA. --------------------------------------------- ?Que se puede hacer con esta metodologia? Uno de los parches que mas me ha gustado hacer es cambiar la unidad Z: por C: Me explico: las aplicaciones internas del movil estan en el disco Z:, que es de solo lectura (se pueden cambiar en el SX1 usando un program especial y re-escribiendo la flash, pero es un rollo hacer esto). Estas aplicaciones usan ficheros con datos que estan tambien en Z: Por ejemplo, la aplicacion del reloj (Clock.app) usa unos dibujos que estan en Z:\System\Data\Clock.mbm Si no te gustan estos dibujos, no puedes poner otros. Pero si consiguiera que busque C:\System\Data\Clock.mbm en vez de Z:\System\Data\Clock.mbm entonces podria cambiar los dibujos, ya que C: es de lectura y escritura. ?Como se sabe donde buscar? En principio, la aplicacion Clock.app es la que decide donde estan los dibujos que va a usar. Normalmente se calcula el directorio donde ella misma esta instalada (Z:\System\Data\Clock.app) y los busca en su mismo directorio. Otras veces, sin embargo, incluye la ruta completa, es decir, que Z:\System\Data\Clock.app contiene la palabra Z:\System\Data\Clock.mbm Es este caso solo hay que parchear la memoria flash usando la unidad C: , es decir, en el fichero Z:\System\Data\Clock.app hay que reemplazar Z:\System\Data\Clock.mbm por C:\System\Data\Clock.mbm Esto es lo que hacen muchos de los parches. Lo malo es que sirve solo para este programa Clock.app y este fichero Clock.mbm en concreto. Seria mas flexible hacer un metodo generico. La manera de abrir un archivo es llamando a la rutina RFile::Open(RFs &, TDesC16 const &, unsigned int) donde el segundo argumento es el nombre del fichero, incluyendo la unidad de disco y el directorio. Esta rutina esta en 0x50195C1C, referenciada desde 0x50F03C7C Asi que solo tengo que parchear esta funcion: -si el nombre del fichero comienza por "Z:" entonces: -sustituyelo, poniendo C: al principio -busca -si no lo encuentra, busca el original (en Z: ) . Devuelve el resultado -si lo encuentra, devuelve el resultado (exito) -si no, llama a la rutina original sin cambiar nada En lenguage C++/ASM : org 0x50F03C7C call mi_RFile::Open // el original hace call 0x50195C1C mi_RFile::Open(RFs & mi_RFs, TDesC16 const & mi_archivo, unsigned int mi_flag) { TDesC16 & mi_archivo_en_C; if(mi_archivo.StartsWith("Z:")) { mi_archivo_en_C=mi_archivo.Replace("Z:", "C:"); result = original_RFile::Open(mi_RFs, mi_archivo_en_C, mi_flag); // en 0x50195C1C if(result<>KErrNone) return original_RFile::Open(mi_RFs, mi_archivo, mi_flag); else return result; } else { return original_RFile::Open(mi_RFs, mi_archivo, mi_flag); } } Obviamente esta idea no es nueva: cualquier rootkit de PC en Linux o Windows hace esto. No solo he aumentado la flexibilidad; ahora un monton de ficheros no se obtienen desde Z: sino desde C: , lo cual libera espacio que puedo usar para mis propias rutinas. Es mas, puedo extender esta rutina para que me diga cuales son los ficheros que se intentan abrir. Cuando cualquier aplicacion abra un fichero, yo lo sabre. Un sniffer para moviles similar a Filemon (www.sysinternals.com). ------------- Hay una aplicacion de pago llamada SystemExplorer by Justek (www.justek.us) que permite trabajar con ficheros. La diferencia con FExplorer es que puede mostrar el contenido de ficheros con formato de base de datos. Por ejemplo el fichero c:\system\data\cdbv2.dat es una base de datos. Este fabuloso programa (ayuda a sus autores ! ) tiene una proteccion para que solo se pueda usar durante 15 dias. Luego caduca. Gracias al parche anterior averiguo que uno de los ficheros que abre es C:\system\data\lm2004.dat Desensamblo el programa SystemExplorer.app y veo que efectivamente hace algo con este fichero. Asi que cierro el programa, borro el fichero lm2004.dat , lo inicio de nuevo, y veo con satisfaccion que me permite usarlo durante otros 15 dias. Ha sido demasiado facil crackearlo. ------------- Como hemos visto, modificar programas Symbian no es mas complicado que modificar programas de Windows. Por supuesto no hay tanta documentacion, pero la tecnica de interceptar rutinas funciona bastante bien. Mi agradecimiento a entusiastas como "18+2", Eric Bustarret, MacKam, Mika Raento, y el Z-TeAm que han hecho accesibles estos conocimientos. Y por supuesto, tantos y tantos programadores de Symbian repartidos por todo el mundo. Ellos son los que hacen que cada dia sea mejor que el anterior. *EOF*