-[ 0x0E ]-------------------------------------------------------------------- -[ El apasionante mundo de los móviles ]------------------------------------- -[ by FCA00000 ]-----------------------------------------------------SET-30-- Bienvenido a un nuevo capitulo de "El apasionante mundo de los móviles". PRESENTACION ************* En episodios anteriores hemos visto cosas que están alrededor del móvil: comandos AT, SMS, SIM Toolkit, ficheros en el SIM, simulacion de teclas, ... Ahora voy a ver algo que me permite cambiar el funcionamiento interno del móvil. Como casi todos los cacharros modernos con un mínimo de funcionalidad, el corazón del móvil es un chip con acceso a una memoria y a unos dispositivos. Los periféricos con los que se comunica el chip son: -radio -teclado -pantalla -iluminación -altavoz -micrófono -infrarrojos -puerto serie -cámara -batería -memoria extraíble Esto lo cuento para que veas que es un dispositivo realmente potente, y todo está integrado en un espacio realmente pequeño. Piensa simplemente en lo que ocuparía (y lo que costaría) instalar todos estos dispositivos en un ordenador. Claro que en este caso son más grandes y tienen mayores capacidades. Lo que quiero decir es que si intentas hacer un emulador de un móvil para un ordenador de sobremesa, posiblemente llevaría mucho trabajo. En realidad no es un dispositivo tan pequeño. En el caso de mi Siemens C45i, contiene un microprocesador C166 de 16 bits, con memoria interna de 4Kb, y memoria flash externa de 4 Mg, además de otra memoria de 1 Mg. Ahora recuerda los tiempos del Spectrum, que tenian 8 bits, 16 Kb de ROM, y 48 Kb de RAM. Y era (es) una máquina realmente magnífica, con juegos extraordinarios. El micro funciona a una velocidad de 25MHz, tiene 76 lineas de entrada/salida, 16 canales de captura de datos, convertidor A/D, unidades de multiplicación, bus externo, 58 modos de interrupcion basado en niveles y permisos, 5 timers, puerto serie incorporado, con arquitectura parcialmente RISC y CISC. Todo ello, con un consumo mínimo de batería y en un espacio reducido. Los fabricantes de móviles entienden que los programas que ellos hacen también pueden tener fallos, así que dejan abierta la posibilidad de cargar nuevas versiones del software. ACTUALIZACION ************* La página web de Siemens contiene actualizaciones para los diversos modelos. Para el modelo S45, la última version oficial es v21 , aunque yo creo que solo existen v5, v16, v18, y v21. Pero lo interesante es que existe un método para modificar el programa incluido. En cierto modo, es una actualización del Sistema Operativo. Para ello hay que conectar el móvil con un ordenador mediante un cable serie, que viene incluido con el teléfono. Mirando con un sniffer de puerto los comandos que se intercambian, veo que usa AT+SQWE=1 , lo que significa que pasa a un modo especial llamado BFB. Este mismo protocolo se usa para meter archivos en la memoria FLEXMEM, por ejemplo juegos en WML (no java) o notas de voz. Simplemente que para en este caso los comandos son mas potentes. Para acceder a la actualizacion del SO, se pasa a un modo llamado bootstrap. Básicamente, se semi-apaga el móvil. Luego se envía un programa pequeño desde el ordenador hacia el móvil, y ese programa se ejecuta. Cuando digo semi-apagar me refiero a que los dispositivos electrónicos nunca se apagan del todo. Simplemente entran en un modo de ahorro de batería. Cuando reciben un señal, se vuelven a poner en marcha. Esta señal viene generada por hardware. Puede ser la pulsación de la tecla de encendido, o un impulso mandado a traves de algun cable. Esto explica porqué cuando conecto el cargador de batería, el móvil es capaz de mostrar un dibujo con una pila. Para que el bootstrap se pueda enviar, el móvil debe enviar una señal indicando que está listo para recibir. Esta señal va por el pin 4 del cable. Pero el cable de datos original tiene cortado ese pin, así que hace falta un cable especial. Cualquier persona que desee liberar un móvil debe tener ese cable, y un programa que altera la EPROM, eliminando una rutina de chequeo. Existen múltiples programas de estos, y hacer el cable no es complicado de construir si se tienen unos mínimos conocimientos de soldadura. Tambien es posible comprarlo, claro. El cable no es el mismo para todos los móviles. Por ejemplo, en los modelos S65, la señal va por el pin 2. Por una casualidad del destino, probé mi cable de datos del S45 con el modelo C35, y funciona. No sé si es porque el cable sirve, o porque el teléfono ya estaba parcheado. Para los atrevidos, el cable original solo necesita ser modificado para que dé la señal de alimentacion por el pin 4. El cargador de batería incluye esta seníl por el pin 3, así que si conectas el pin 1 (masa) del cargador con el pin 1 del cable de datos, y el pin 3 del cargador con el pin 4 del cable de datos, ya te has hecho tu propio cable. Al menos a mí me funciona con el modelo S45. Y no, no me hago responsable de lo que puede pasar si haces la prueba y lo conectas mal. Existe una tecnica para usar el cable por primera vez, parchear el móvil, y luego no hace falta mas el cable. Pero esto lo explicaré mas tarde. Así que las herramientas hardware necesarios son un ordenador con puerto serie, un cable de S45, un teléfono C35 o similar. Las herramientas software son Windows (algunos de los programas sólo funcionan en este SO), y los programas: Siemens Flashing Tools (zSiemenz), por RizaPN, para volcar y grabar la EPROM v_klay, hecho por ValeraVi, para meter un parche Smelter, hecho por avkiev, para investigar lo que hay en un archivo EPROM SPC2, hecho por ACiD [mrp], para modificar los dibujos sfe, por RizaPN, para desensamblar y tracear un archivo EPROM, y hacer parches Siemens EEPROM tool , por Skylord, para ver lo que hay en un archivo EPROM AT Debugger, por BoBa! , para ver lo que pasa por la memoria. Siemens Debugger, por ACiD y SiNgle, para monitorear programas en tiempo real Keil uVision C166, por la compa#ia Keil Software, debuggea programas y compila Documentacion del C166, de la compa#ia Infineon No es mi criterio habitual mencionar autores, programas, o direcciones web, pero en ese caso hago una excepción porque realmente esta gente se lo ha trabajado, y despues de tratar con ellos me doy cuenta de que valen mucho. Ademas me caen bien. La mayoria de estos programas se pueden encontrar en www.gsm-dev.com o en www.gsm-multifund.de/board Dado que Siemens es una empresa alemana, no es de extrañar que la mayoría de la documentacion, los foros, y los programas, estén escritos en esta lengua. Aber du sprichst deutsch, oder? Tampoco es raro encontrar documentación en ruso, sobre todo en las webs de ValeraVi y BoBa! aunque lo básico está ya traducido al inglés. También hay otros muchos programas que incluyen código fuente y te pueden servir para meterte en este mundillo: Siemens Service Mode (flash_2.1.tar.gz), por Wilder. sources.rar , por RizaPN x35_patch , por BoBa! Todos los fuentes de los parches, disponibles en www.gsm-dev.com Tambien puedes pedirles a los autores que te pasen el código fuente de sus programas. A mí nunca me pusieron impedimentos. Recientemente he descubierto que hay una página web en español en cs.comunidad-siemens.com A mí me parece que el nivel es bueno, y hay alguna gente adaptando y desarrollando parches, sobre todo para los nuevos modelos. A ver si después de leer este artículo te pica el gusanillo y te unes también a la comunidad. PRIMEROS PASOS ************** Bueno, pues el primer paso es ver que la cosa funciona. Conecto el cable al ordenador y al móvil, inicio 'Siemens Flashing Tools', y cuando me indica que apague el teléfono, y pulse el boton de encendido brevemente, lo hago, y el programa indica que todo va bien. Selecciono le menu de 'Read Flash', y en menos de 10 minutos obtengo un fichero con la memoria de mi móvil. Hay muchas páginas dedicadas a explicar la diferencia entre el cable original y el cable especial para desbloquear, asi que solo repetire lo que todas dicen: el cable original no sirve. (Claro que todavia no me explico porque el cable del S45 sirve para el C35) Si tienes interes -y asumo que lees este articulo porque lo tienes- no te será difícil contactar con algunas de las muchas empresas que fabrican el cable especial. Y en eBay puedes encontrar Siemens muy baratos. El archivo con la memoria, también conocido como Flash, EEPROM, o FuBu, es conveniente guardarlo en un lugar seguro. Así puedo volver a meterlo en el móvil si algo falla. Cuando se enciende el móvil, hay una rutina que verifica que la memoria no ha sido corrompida. Se toman todos los bytes, y se calcula un checksum. Por eso uno de los primeros pasos es eliminar esta verificación, para poder meter mis programas y modificaciones tranquilamente. Los teléfonos x35 contienen un único chequeo CRC Los teléfonos x45, x50 contienen dos chequeos CRC Los modelos x55 y x60 no contienen chequeo. Para hacerte tu propio parche, puedes usar el programa CRC Patcher http://www.gsmdev.de/page/index.php?c=viewprojektinfo&id=20 Además, en mi caso el teléfono C35 tiene la versión v5, que es bastante antigua y contiene fallos. Decido meter la v18, también porque la mayoría de los parches están desarrollados para esta versión. Esto es un paso importante: los parches oficiales de Siemens ocupan posiciones de memoria totalmente diferentes segun la versión; si la rutina de enviar mensajes en la version v5 empieza en la dirección D01234, puede que empiece en la C43210 en la versión v18. Puede que algunos parches incluyen las modificaciones para hacerlo funcionar en otras versiones, pero no es lo normal. Yo he decidido no usar la version v24 o v25 porque parece que contienen nuevos fallos, y los parches no están desarrollados para estas versiones. Aunque no todos los modelos de Siemens contienen la misma funcionalidad, hay parches que se han desarrollado para un modelo, y luego alguien los adapta a otros modelos, siempre que sea posible. Por ejemplo, BoBa!, ZZToP y bEGEM0t se han encargado de pasar al C35 muchos de los parches que RizaPN o ACiD[mrp] han hecho para el SL45i. Gran trabajo, por otra parte. Como iba diciendo, ya que tengo una copia de la Flash, lo siguiente que hay que hacer es una copia de la EEPROM. Esta otra zona de la memoria contiene datos que se pueden modificar sin problemas, siempre que se tenga cuidado. Me explico: la Flash contiene el programa, teóricamente inalterable, mientras que la EEPROM contiene datos que deben ser almacenados de manera permanente, aunque se pueden cambiar, pero no se deben perder. Notar que la EEPROM no contiene los datos que estan en el SIM. Por ejemplo, la EEPROM almacena la puntuación que has conseguido en el juego del buscaminas. También guarda el nivel de volúmen para el altavoz, el libro de direcciones del teléfono, el bloc de notas , o la clave para el navegador de internet. La EEPROM se compone de unos cuantos ficheros, dependiendo del modelo de móvil hay mas o menos ficheros, y todos los modelos coinciden en usar los mismos indicadores. Por ejemplo, el fichero 5012 del C35i contiene el nivel de batería, mientras que 5076 contiene el mensaje de saludo que aparece al encender el móvil. Este fichero 5012 es especial y también hay que guardarlo, ya que contiene información tal como la carga de la bateriá, y la configuración de los parámetros de fábrica por defecto. Para leer la EEPROM, no es necesario el cable especial; vale con el cable original. Así que puedo leer mi SiemensS45 o el C35. Uso el S45 porque contiene más datos. Si tienes archivos Flash de otros modelos también se pueden investifar. Arranco el Siemens Debugger, y en el botón de 'Setup' uso el puerto COM1. Pulso el botón 'Start Service Mode' , y al cabo de un momento me dice que el BFB no se ha abierto. Esto quiere decir que no tengo acceso a toda la funcionalidad del programa, pero puedo hacer bastantes cosas. EEPROM ************* En la ventana de EEPROM, pulso 'existing only' y tras un momento la lista 'Block name' contiene varios valores. Elijo 'Notes Function 10' , que es el bloque 5179, y veo que aparecen un montón de caracteres, correspondiente al menú del móvil 4-3-5: Notes. A partir de la posición 0C , y en las posiciones pares (0C, 0E, 10, 12, ...) aparece el texto "Hola", que es justamente lo que yo tengo almacenado en la primera entrada del bloc de notas. En la parte hexadecimal veo que el carácter es 48, tal como corresponde a la letra 'H'. Es curioso que la primera nota esté en el bloque 10. Posteriores pruebas revelan que la nota segunda está en el bloque 9, y asi sucesivamente. Armado de valor, hago doble-click sobre la celda 00000C , y escribo '4C'. Entonces aparece el boton 'Save block', indicando que he hecho una modificación y puedo guardarla. Tras pulsar este boton me aparece un mensaje diciendo que se han escrito 112 bytes en el bloque EEPROM 5179. Miro el móvil, y la nota aparece ahora como "Lola", ya que 4C corresponde a la letra 'L'. Antes de que se me echen al cuello todos aquellos que comprenden la codificación ASCII, notar que este es un gran descubrimiento: el teléfono usa la tabla ASCII. Tambien podría usar la EBCBIC, o cualquiera otra que Siemens se haya inventado. No creas que todos los microprocesadores trabajan en ASCII; esto es sólo una convención. Desde el teléfono, es posible marcar esa nota como confidencial. En este caso se pide el código del móvil para protegerla. Cuando apago el teléfono y lo vuelvo a encender, al intentar leer la nota me pide este código. Notar que el móvil lo tengo puesto para que no pida el código cuando lo enciendo: por eso me lo pide ahora al intentar leer la nota. Desde el Siemens Debugger, miro de nuevo el bloque 5179, y veo que la nota original sigue allí! Sólo han cambiado algunos bytes antes de la dirección C0. O sea, que no lo ha cifrado. Esto quiere decir que cualquiera puede coger el móvil de otro, y leer las notas -teóricamente confidenciales- del usuario original usando Siemens Debugger. No muy confidencial, diría yo. La nota original 'sin cifrar' tiene los bytes: 00 00 10 0A 36 FF D4 07 08 1D 04 00 y luego el texto de la nota. La nota confidencial tiene los bytes: 01 00 10 13 14 FF D4 07 08 1D 04 00 y luego la nota. Así que si cambio los bytes desde el 0 hasta el 5 para que sean como el caso inicial, la nota pasa a ser no-confidencial. Es más: simplemente cambiando el primer byte de 01 a 00, la nota es no-confidencial. No sé el significado de los otros bytes, pero no parecen servir para nada en este caso. Probando con otros valores veo que 00 significa no-confidencial, y cualquier otro dato significa confidencial. Estarás contento, no? Ya he hecho el primer crack. Borro la nota desde el télefono, y al mirar el bloque 5179, veo que todavía está allí! Los primeros bytes han cambiado, pero los datos siguen allí. Así que tampoco hay mucha seguridad en este apartado. Cualquiera puede leer una nota antigua, por más que se haya borrado. El bloque este ocupa 112 bytes. No es mucho, pero suficiente para guardar notas de 50 letras, pues cada letra ocupa 2 bytes. La cabecera ocupa otros 12 bytes. Pero también es un sitio ideal para guardar un programa pequeño. A veces la memoria Flash no es el mejor sitio para escribir un mini-parche, pero en 100 bytes se pueden escribir grandes cosas en ensamblador. Luego veré esto con más detalle. En artículos anteriores me quejaba de que, aunque puedo leer muchos de los parámetros del móvil mediante comandos AT, es imposible leer las notas. Bien, ya es posible hacerlo gracias a ACiD[mrp] y Siemens Debugger. También os había enseñado a escribirlas usando el comando de simulación de teclas AT+CKPD , pero he encontrado otro método mejor. Ya veré si soy capaz de automatizar esta tarea. MAS EEPROM ************* Otro bloque fácil de interpretar es 5166: Alarm Clock El fichero ocupa 6 bytes, y en mi caso vale 08 20 00 1F F1 FF Mirando el móvil, yo tengo puesto que suene a las 08:32 de lunes a viernes. La hora 08:32 se escribe en hexadecimal como 08 20. El dato 1F F1 se escribe en binario 00011111 11110001 Haciendo que no suene el martes, tengo 08 20 00 1D F1 FF, donde el dato 1D F1 se escribe en binario 00011101 11110001 Haciendo que no suene el miércoles, tengo 08 20 00 1B F1 FF, donde el dato 1B F1 se escribe en binario 00011011 11110001 O sea, que los días de la semana se marcan en bits desde atras hacia adelante. Todos los días es 7F F1, mientras que 'ningún diá' se escribe 00 F0. El último bit de byte 04 indica si la alarma está activa o no. Así, ya es fácil hacer un programa que sincronice la alarma del ordenador con la del móvil. Hay muchos ficheros interesantes, y entre ellos ha captado mi atención el 5086: '* WAP Profile 1b (CSD Dialup) *' Esta es la explicación preliminar: en un teléfono con WAP, primero se inicia una llamada a un servidor telefónico; algo así como un modem que siempre está escuchando. Cuando uno se da de alta en este servicio, el operador de red manda un SMS para configurar el teléfono, y decirle algunos paramétros, por ejemplo el número de teléfono que tiene que marcar, el nombre de usuario, y la clave. Esto en el caso de una llamada a traves de la red 2G, mediante un CSD. Cuando el teléfono es GPRS estos datos se amplían a un servidor web llamado APN. Para la conexión WAP, otros de los parámetros son el servidor WAP primario, y el puerto. Todos estos datos se guardan en la EEPROM, y, si bien se pueden ver desde el propio teléfono, el dato de la clave está oculto. Pero seguro que está en alguna parte de la memoria. Así que con ayuda del 'Siemens Flashing Tools' hago una copia de la EEPROM. Luego desde el móvil voy y cambio el perfil CSD, y sustituyo la clave, poniendo '2222' en vez de 'xxxxxxxx'. Hago otra copia de la EEPROM, y las comparo. Es posible sacar cada uno de los ficheros independientemente; así resulta más fácil ver lo que ha cambiado. Los bytes que han cambiado pertenecen al fichero 5086, como ya intuia. La nueva clave '2222' aparece en la posición 0x36 (esto es, 54 en decimal), sin cifrar ni nada. Para saber la clave inicial, no tengo más que usar un editor hexdecimal, abrir el archivo original 5086, y mirar a partir del byte 54 . En el caso de mi operador, la clave resulta ser 'wap'. Para el caso de Telefónica, el nombre de usuario es MOVISTAR, y también la clave es MOVISTAR. Esto no es ningún secreto. Y esto es el segundo hack del dia. Otro caso: empiezo una partida al juego 'Balloon Shooter', y hago 130 puntos. Guardo toda la EEPROM. Borro el record, y guardo la EEPROM de nuevo. Comparo los archivos, y difieren en 000087D9: FF 7D O sea: ahora marca FF, pero con 130 puntos marca 7D. El valor 7D es 125, y 255-125=130. Asi que el dato se guarda en negativo. La posicion global 87D9 tiene unos bytes antes, con el texto 'Championship', que coincide con el archivo 'Games 1', en el bloque 5180. El bloque mide 250 bytes. Así que supongo que el record se guarda en el siguiente bloque 5181: 'Games 2'. En efecto, el primer byte es 7D. Nada más fácil que cambiar los primeros bytes a '9F' y '15' para tener 60000 puntos. Lo explico otra vez, porque es otro dato que no hay que olvidar: No sólo se guarda en complemento a 2, sino que el byte menos significativo va primero, como corresponde a una arquitectura little-indian de 16 bits: 65535-60000=5535, que se escribe '0x159F' en hexadecimal. Alterando el orden de los bytes, queda '9F 15', como he dicho antes. Esto es el tercer hack. Cuando se modifica uno de los bloques, no se sobre-escriben los datos, sino que se crea un nuevo bloque, y el anterior se invalida. Por eso la memoria EEPROM necesita ser más grande que toda la suma de los tamaños de los archivos. IMEI EN LA EEPROM ***************** Hay unos ficheros en la EEPROM que contienen información sobre el IMEI: 5009=IMEI Block 00 0076=IMEI Block 01 5008=IMEI Block 02 5077=IMEI Block 03 Todos los móviles tienen un identificador único, creado por el fabricante. Esto sirve, por ejemplo, cuando te roban el móvil. Sólo hay que denunciarlo, y el operador de telefonía lo mete en una base de datos, que comparte con otras operadoras. Cuando se intenta hacer una llamada desde ese móvil, no se permite. También sirve para saber el modelo. Esto hace que cuando haces o recibes una llamada, la red sabe cual teléfono tienes, y puede proporcionar funcionalidad diferente. Un caso es que los tonos de la red (congestión, no hay respuesta, ocupado, ...) pueden ser polifónicos, si tu modelo lo soporta. Otra utilidad es identificar y cambiar los modelos que se sabe tienen algun defecto. Este identificador llamado IMEI se almacena en un archivo de la EEPROM. En teoría se puede modificar para hacerlo aparecer como otro teléfono. Notar que esto es ilegal en la mayoría de los países. Además Siemens ha decidido que esto no sea tan fácil; no se guarda en un fichero en texto claro, sino que está cifrado. Como medida extra, se guarda en varios ficheros, con distintos checksum. Aun asi, resulta sencillo tomarlos de otro teléfono, y copiarlo al mio. Cuando se actualiza la EEPROM o la flash, lo que debe hacerse es una copia de mis datos, meter la flash, y luego restaurar los datos de estos 4 archivos. Si la actualización se hace con el software original proporcionado por Siemens, el funcionamiento es ligeramente distinto: el software obtiene el IMEI con el comando AT+CGSN , despues actualiza la EEPROM, calcula el contenido de los ficheros, y los mete de nuevo. Esto deja la puerta abierta a modificar el IMEI en memoria justo antes de escribirlo. Este comportamiente se puede confirmar viendo el protocolo que usa el programa de actualización original UpdateTool, disponible en la web de Siemens. No me he metido en esto, pero suena interesante, no? Otro fichero que hay que guardar es 0067 = Measurement values for temperature and voltaje Esto guarda el nivel de batería actual y máximo, además de otros datos. Si no guardas este fichero, creerá que el nivel de batería es el de la persona que te ha pasado la EEPROM, seguramente se confundirá a la hora de cargarlo, y el teléfono no te durará encendido ni 5 minutos. Como antes, hay que guardar el tuyo, meter la flash, y restaurar tu fichero. Esto es lo que hacen automáticamente muchos de los programas que sirven para desbloquear el teléfono para usarlo en otras redes. Un programa para esto es AllSiemens , aunque hace falta el cable original. NO TODO ES ORO ************** Otro de los bloques es 5058: Calculator & Currency converter Este móvil tiene una utilidad que permite traducir una moneda en otra. Se puede usar para convertir pesetas en euros, o pulgadas en centímetros. El calculo es una simple regla de tres mediante un factor que se guarda en las posiciones 1D-23 del fichero, mientras que el nombre de las monedas se guarda en las posiciones 64-77 . Pero al cambiar cualquiera de los datos desde el Siemens Debugger, no parece guardarse en el teléfono. De hecho, cuando apago el móvil y lo vuelvo a encender, los datos no estan allí. Es como si fuera de solo lectura. Desde el propio móvil sí se pueden modificar, pero Siemens Debugger no los ve. Parece que se guardan temporalmente en algún otro fichero, aunque sin modificarse en tiempo real. La explicación es el móvil usa un sistema de versiones de ficheros. Cuando modifico un fichero, en realidad se hace una copia, se modifica el nuevo fichero, se marca como activo, y el anterior se marca como inactivo. Usando la aplicacion 'Smelter', voy al menu EEPROM, pulso con el botón derecho del ratón, y marco la opción 'Show deleted blocks'. Esto es util para saber cuales archivos han sido modificados, y se puede ver el original junto con las versiones que se han ido creando. Así veo que hay 4 versiones del fichero 5058, con todos los cambios que he ido haciendo. El móvil no responde al refresco de estos datos, ya que sólo lee el fichero cuando se enciende. Es por esto que no tiene sentido cambiar este fichero desde el ordenador. Lo digo para que no te sorprendas si a veces tus cambios no los ves reflejados inmediatamente. Intentaría entender el formato de los datos usados en la conversión de la moneda, pero no es cuestión de encender y apagar el móvil 200 veces. Hay otros muchos ficheros que se comportan igual. En total, hay definidos unos 500 ficheros, aunque estoy seguro de que nuevos modelos necesitan implementar nuevos ficheros, sobre todo para las redes 3G. Si te decides a jugar con los ficheros, considera hacer una copia. A mí todavía no me ha pasado nada grave, pero es más que probable que algún día me encuentre con que el móvil no funcione y sea debido a algo que he tocado en los ficheros. Por eso es bueno experimentar con otro móvil que no sea el que usas a diario. Ya sabes: los experimentos se hacen con gaseosa. DONDE ESTA LA EEPROM ******************** La EEPROM del C35i se guarda a partir de la direccion 0x3F0000, ocupa en total 0x10000 bytes y la lista de ficheros esta a partir de 3F7CE0. En el S45 la memoria está en dos trozos: en 0x1F0000 ocupando 0x10000 , y en 0x5F0000 ocupando 0x10000. Esto se puede ver con el programa zSiemens. Elige la opción de guardar la EEPROM, y dirá la zona de memoria que debes guardar. Para ver cómo está organizado, empiezo por el modelo mas sencillo. Con un volcado de la Flash del C35i, en la dirección 0x3F7CE0+0x196=0x3F7E76 está el dato 0x20, o sea, 32 en decimal. En 0x3F7CE0+0x196+0x02=0x3F7E78 esta el dato 'D6 6D', que pasado a little-endian (primero el byte menos significativo) quiere decir 6DD6. Sumando la dirección base de la EEPROM (0x3F0000) obtengo 0x3F6DD6. En la direccion 0x3F7CE0+0x196+0x06=0x3F7E7C está el dato 'D4 13' que se lee como 0x13D4 y en decimal es 5076. Todo junto: el bloque 5076 mide 32 bytes y esta a partir de 0x3F6DD6. Este bloque resulta ser 'Personalisation - Greeting Text' así que cuando lo cambio, consigo cambiar el texto que aparece cuando enciendo el teléfono. Por defecto es 'Siemens C35i' pero lo cambio sin más que alterar la EEPROM. Existe una manera infinitamente mas sencilla de ver estos datos: vuelca toda la flash (4Mg) y cárgala en el Smelter. Ve al menu EEPROM, y ordena por el campo llamado Offset. Entonces puedes ver la lista de todos los ficheros. Lo que pasa es que el metodo anterior me va a servir para leer los ficheros desde el propio móvil. Pero no quiero adelantar acontecimientos. Hay dos zonas de EEPROM: una llamada EEFULL y otra EELITE. Unos ficheros estan en una zona, y otros en otra. Creo que para usar la EELITE se necesitan mayores permisos, pero no estoy seguro. HAY VIDA MAS ALLA DE LOS FICHEROS ********************************* Y ya que estoy con el Smelter, explico otras opciones. Para verlas hace falta un archivo con la Flash. Lo normal es usar la que has extraido de tu móvil, pero también es posible encontrar otras versiones de tu modelo, u otras memorias de otros modelos. Esto se hace para comparar parches y adaptarlos. Uno de los modelos que más parches recibe es el SL45v56. Busco su Flash y la cargo en Smelter. El menú de EEPROM ya lo conozco. Pero ahora puedo ver los archivos existentes en otros modelos, y ver los que me faltan en el C35. También puedo sacar configuraciones de otros usuarios, aunque es más que probable que, si pertenecen a otro modelo, no tengan sentido en el mio. TONOS ***** Otro de los menús usados es el de Ringtones. Cada uno de los sonidos (excepto la voz) generados por el móvil se guarda en la memoria. Las melodías modificables por el usuario se guardan en la EEPROM, en los bloques 73='Ringer melodies' y 5071='User defined melodies'. Hay bastantes programas que permiten cambiar estas melodías con un interface mucho más sencillo, así que no me meto en el tema. Pero hay otros tonos que no se pueden cambiar. Entre estos están las melodías predefinidas, y los tonos de operatoria normal del móvil. Por ejemplo, cuando la red esta congestionada, se oye un pitido tut-tut-tut, o cuando se enciende el móvil emite otro pitido. También cuando se sobrepasa la longitud de un SMS, los sonidos de los juegos, o el nivel bajo de batería. Todos estos tonos tienen definido un número, y se encuentran en una posición de la memoria. Smelter nos dice esto, permitiendo además la posibilidad de escucharlo, e incluso guardarlos a un archivo. De esta manera veo que cada nota se compone de dos partes: tono y duración. No hay un dato para el volúmen de cada nota. Cuanto mayor es el tono, suena más agudo. Los datos ocupan cada uno 2 bytes, así que un tono de valor 860 (0x035C) y duración 210 (0x00D2) se guarda como 5C 03 D2 00 Dado que también me dice la posición de memoria donde se guarda, hacer un parche para cambiar un tono es cuestión de segundos. Voy a verlo con un ejemplo. Cuando la batería se va a acabar, el teléfono emite un pitido corto. Dado que caerzco de sentido musical, no he podido identificar cual es ese tono. Pero buscando los sonidos de sólo 1 nota he encontrado 5. Modificando todos ellos hasta encontrarlo, lo he convertido de 860:210 a 860:1, y ahora no se oye. La melodía sigue estando allí y suena, pero la duración es tan corta que es imperceptible. De modo similar a los ficheros de la EEPROM, en el C35 los sonidos están indexados a partir de la direcion 0xC8E786. Cada melodía es un puntero que ocupa 8 posiciones, de las cuales la cuarta indica la direccion de memoria donde se almacenan las notas. Esto me va a servir para identificar cuando se invoca a una melodía particular. DIBUJOS ******* Otra de las posibilidades es modificar los dibujos. Si modificar los sonidos es fácil, los dibujos es todavía más. Uso el programa 'Siemens Picture Change', y cargo la Flash de mi móvil C35i. Me aparece una lista con los identificadores de los dibujos. Elijo el 210, que es el icono de infrarrojos, y me aparece en el cuadro de la izquierda. Lo gracioso de este caso es que este modelo no tiene puerto de infrarrojos! Lo mejor será elegir un dibujo que puede ver: 468 es el icono que indica que el timbre esta apagado, y las llamadas no harán que mi móvil pite. Pulsando el botón derecho lo guardo en un archivo BMP, que luego edito. Después lo vuelvo a cargar haciendo doble-click sobre la lista de la derecha. Pulsando 'save Patch as...' genero un parche para luego meterlo en el móvil. El formato del fichero es RTF, aunque la extension es .vkp (v_klay). La razón para usar RTF es que Word permite incluir iconos y gráficos dentro de sus documentos. Así es posible abrir el fichero con word, y se verá cómo es el dibujo incluido en el parche. No solo eso, sino que además v_klay también mostrará el dibujo al abrir el código del parche. Arrancar el v_klay con el parche, y pulso 'Apply Patch' para transferirlo. Pulso brevemente la tecla de encendido para entrar en el modo bootstrap, y cuando el parche está cargado, apago el teléfono, lo vuelvo a encender, y tengo mi nuevo icono. Cuarto hack del día. Gracias a 'Siemens Picture Change' veo que la dirección es 0x352A29, y esto sirve para saber a qué posición de la memoria va a ir a parar el parche. La dirección, e incluso el identificador de cada icono, es distinto entre versiones y modelos. Por eso los parches para modificar dibujos también tienen que ser adaptados de un modelo a otro. Por ejemplo, en el modelo SL45i com la EEPROM v56 , este icono tiene número 307 y está en la posición 0x4B1F98. MENUS ***** En los teléfonos Siemens los menús están organizados como una lista simple. Cada menú está localizado en una posición de memoria, en la que se dice quien es su padre, el texto que muestra, la rutina a la que salta, y el número de elementos en el caso de contener sub-menús. Con el Smelter no hay más que abrir la Flash, e ir al menú 'Menu'. Al principio aparece la lista pero no el texto del menú, pero si voy a 'Langpack', pulso con el botón derecho, activo 'Show tags' y 'Show texts from firmware', voy de nuevo a 'Menu' y ya me aparecen todos. La importancia de los menús es que son los puntos de entrada para las rutinas. Si quiero modificar alguna funcionalidad, lo normal es recorrer el camino desde el menú de entrada hasta esa funcionalidad. Por ejemplo, si quiero quitar el mensaje 'Minesweeper. With compliments from Microsoft' que sale antes de jugar al buscaminas, empiezo desde el menu Games->Minesweeper hasta llegar al punto donde se referencia este mensaje. El parche más sencillo consiste en cambiar el texto del menú. Pero como en general están traducidos, esto no es necesario, a no ser que lo quieras adaptar a un lenguaje que no está soportado. También es posible cambiar los menús para que estén en otros sitios. En mi móvil es posible definir cada una de las teclas como un acceso directo. Si pulso durante 1 segundo esa tecla puedo ir directamente a un sub-sub-menu. Lo malo es que no todos los sub-sub-menús están disponibles. Puedo elegir: -Un cierto número de teléfono -Conectar a Internet -Sitio web -Listín de teléfonos -Listín de direcciones -Calendario -Alarma -Notas -Calculadora -Conversor de moneda -Nuevo SMS -Iluminación -Ocultar ID -GPRS -IrDA -Juegos -Llamadas perdidas -Llamadas recibidas -Mensajes recibidos -Mensajes enviados -Favoritos -Tarjeta de negocios Pero yo uso frecuentemente el menú de 'Datos de la última llamada' para ver cuanto tiempo he hablado. Y lamentablemente ese menú no está entre los seleccionables. El menú es Registros->Duración->Ultima llamada En la Flash del ME45v28 (que es similar al S45) veo que ése es el menú 011C dependiente de 86, y el punto de entrada es F3F5C0. Su padre es 854CA6. Pero también aparece dependiente del menú 87, con los mismos datos. Así que lo mas fácil (por ahora; luego mostraré otro método mejor) es intercambiar los puntos de entrada entre el menú 'Tarjeta de negocios' y 'Datos de la última llamada'. El menú 'Tarjeta de negocios' tiene numero 0223, depende de 60, y tiene punto de entrada F39310. Su padre es 85351A. Desde el sfe busco la cadena '10,93,F3', ya que los datos de puntos de entrada se guardan en formato inverso. Lo encuentro en 05352A. Notar que es el quinto menu dentro del 60, y 0x05352A - (5-1)*4 = 0x5351A , que es 0x85351A - 0x800000 El otro punto de entrada F3F5C0='C0,F5,F3' se encuentra en 054CA6 y 054CB6 . Esto concuerda con el hecho de que aparece en el menu 86 y 87. Igualmente notar que es el primer menu, y 0x054CA6 - (1-1)*4 = 0x054CA6 , que es 0x854CA6 - 0x800000 O sea, que Smelter nos indica, en la columna 'Entry' del menú, donde está definido este menú. Así que el parche intercambiará esos datos , pero sólo para el menú 86: 0x05352A: 1093F3 C0F5F3 0x054CA6: C0F5F3 1093F3 Lo cargo en el v_klay , lo meto en el móvil, y a partir de ahora el menú 'Tarjeta de negocios' me lleva a 'Datos de la última llamada', y viceversa. Para que la técnica sea perfecta, solo tengo que cambiar los textos de los menús correspondientes. Por curiosidad, en la flash S45i v4 este menú es también el 011C pero depende del 102 y salta a F6A870. MAS DIFICIL TODAVIA ******************* Este es el primer parche complicado. A ver si lo sigues sin perderte. En el móvil la tecla '0' también tiene el símbolo'+' que sirve para escribir números internacionales, por ejemplo +34666.. y si se mantiene pulsada durante un tiempo aparece el menú '+List' para elegir el prefijo de cualquier país. Tanto los móviles como los números de teléfono de la red fija tienen el mismo prefijo. Si recibes una llamada que empieza por +376 sabes que viene desde Andorra. Esto resulta informativo cuando alguien desde China marca mal y acaba llamando a tu móvil. Suena raro, pero yo ya he recibido un par de llamadas desde Rusia y otra desde Indonesia. Pero en general esta lista resulta una tontería. Mi propósito es cambiarlo para que me diga la red española. En España hay hasta el momento 5 operadores de telefonía móvil: Airtel , Movistar, Amena, Xfera, y Moviline. Cada uno de ellos tiene asignado unos dígitos de prefijo nacional. Toda la telefonía móvil empieza por '6', aunque para ser más correcto debería decir que comienza por '+34 6'. A partir de esta base, cada uno tiene un grupo de números. Movistar tiene '+34 606', '+34 609' y '+34 615' y muchos más. Xfera tiene '+34 622'. Airtel tiene '+34 607' , '+34 610' y '+34 617'.... Esta es la lista completa: AIRTEL 600 607 610 617 627 637 647 661 662 666 667 670 677 678 687 697 AMENA 605 615 625 635 650 651 652 653 654 655 656 657 658 MOVILINE 608 689 MOVISTAR 606 609 616 618 619 620 626 628 629 630 636 639 646 649 659 660 669 676 679 680 686 690 696 699 XFERA 622 Cuando quiero llamar a alguien, me interesa saber en cual red está, para elegir el mejor horario que se ajuste a mi tarifa, o llamar desde el teléfono de la oficina. Por eso voy a desarrollar un parche que sustituya la lista de prefijos internacionales por otra de prefijos nacionales para móviles. La lista original tiene 90 países, y la nueva lista tendrá 40, ya que sólo hay otorgados 40 prefijos '+34 6xx'. Todos los cambios los voy a hacer en el C35i, aunque siguiendo el mismo proceso es fácil adaptarlo a otros modelos. Para empezar, busco en la Flash el nombre del primer país de la lista: Algeria. Sí, ya se que en español se dice 'Argelia', pero mi móvil está en inglés. Lo encuentro en la posición 0x3CD06A , seguido por los bytes 0x00 0x95 , y el siguiente país : Andorra (en 0x3CD073) y de nuevo 0x00 0x95 . Luego está Argentina en 0x3CD07C , con su currespondiente 0x00 0x95 . Y después Australia en 0x3CD087 . Asi que para empezar sustituyo 'Algeria' por 'Almeria': 3CD06C: 67 6D Meto el parche, y aparece tal como esperaba. El número de Algeria es +213 asi que busco en el fichero de la flash esa cadena, como si fuera una palabra de 3 letras. No la encuentro. Mi siguiente idea es buscar el byte 213, pero seguro que aparece miles de veces. El siguiente país de la lista es Andorra, con prefijo +376, así que lo traduzco a hexadecimal: 0x01 0x78, y aparece varias veces, pero nunca cerca de 0xD5, que es el valor hexadecimal de +213. Tras un instante de perplejidad, recuerdo que el C166 trabaja en formato little-endian, así que lo que tengo que buscar es 0x78 0x01. Pronto aparece en 0x387C88, y antes de él también está el código de Algeria: 0xD5, 0x00 . 0x387C84: D5 00 20 07 0x387C88: 78 01 21 07 0x387C8C: 36 00 22 07 , correspondiente a +54, el codigo de Argentina Mi corto ni perezoso cambio el byte D5 por D6, y se muestra el +214 en el móvil. Para hacer aparecer el prefijo +34 606 , uso la calculadora de Windows que me lo convierte en hexadecimal : 0x872E = 0x2E 0x87 en little-endian. Ahora el primer elemento de la lista me aparece 'Almeria' con prefijo +34 606 UN PASO MAS *********** El siguiente problema al me enfrento es que no puedo poner 'Movistar-606' en lugar de 'Algeria', porque ocupa más caracteres y no cabe. Sospecho que tiene que haber alguna relación entre la lista de prefijos y la lista de países. Dado que el caracter 0x07 aparece todas las veces, supongo que es un separador. Pero el numero precedente parece un índice. Lo cambio y voy a ver que pasa. Pongo 0x25 en vez de 0x20. Lo que sucede es que el primer país de la lista es ahora Austria, el cual estaba antes en la posicion 5. O sea, que es un índice a la lista de países. Los nombres de los países a su vez están separados por 0x00 0x95. Retraso esto 2 posiciones para incluir 'xx', y ahora la lista es Algeriaxx, dorra, Argentina, ... Es decir, que hay una lista que apunta a los nombres de los paises, los cuales se imprimen hasta encontrar el carácter 0x00. Intento averiguar donde se referencia a esta posición de memoria, pero no encuentro nada. Despues de darle algunas vueltas, se me ocurre una solución: 0x387C84 tendrá +34 606 y usará el tercer byte=20 para apuntar a 0x3CD06A , donde guardaré 'Movistar-606', sustituyendo a 'Algeria' Nadie apuntará a 'Andorra' 0x387C88 tendrá +34 609 y usara el tercer byte=22 para apuntar a 0x3CD07C , donde guardaré 'Movistar-609', sustituyendo a 'Argentina'. Nadie apuntara a 'Australia' Esta es una manera de hacer hueco: uso sólo la mitad de los países. Tambien podría poner 'Mstar606', 'Xfera654' y similares, aunque voy a ver si hay otra manera de hacerlo más bonito y completo. Como estas dos ideas son un poco chapuceras, intento de nuevo encontrar referencias a la lista de países. La manera fácil de sacarlo habría sido usar Smelter para ver las palabras escondidas en la EPROM. Lamentablemente este método falla porque no es capaz de interpretar correctamente el Langpack del C35i, aunque funciona bien con otros modelos. Así que experimentando con el ME45 veo que en esta Flash la palabra 'Algeria' se localiza en el offset 0x061201, y está referenciada desde 0x061CA9. Intento buscar algo similar en mi Flash del C35. Tras muchas pruebas, llego a la conclusión de que 0x3CDA20 es un apuntador al nombre del primer país. En 0x3CDA20 hay los bytes 0x69 0x10. En 0x3CDA22 hay los bytes 0x72 0x10. Decremento el dato que esta en 0x3CDA20 ; esto es, cambio en 0x3CDA20 para que ponga 0x6A 0x10 (recordar: little-indian) y la lista de paises sale: lgeria , Andorra, Argentina, ... El cambio es que la 'A' inicial de Algeria me la he comido. Cambiando en 0x3CDA20 para que ponga 0x72 0x10 hago que la lista de paises sea: Andorra , Andorra, Argentina, ... En resumen, la palabra 'Algeria' aparece en 0x3CD06A y está referenciada desde 0x3CDA20 , con valor 0x1069 Asi que sin mucho cuidado empiezo a modificar los paises en 0x3CD06A : Airtel600<00><95>Airtel607<00><95>Airtel610<00><95>Airtel617<00><95>... y sus referencias en 0x3CDA20 y siguientes: 0x3CDA20: 1069 0x3CDA22: 1069+strlen("Airtel600")+2=1074 0x3CDA24: 1074+strlen("Airtel607")+2=107F 0x3CDA26: 107F+strlen("Airtel610")+2=108A También tengo que cambiar los códigos de los prefjos: 0x387C84: 2887 , porque +34 600 = 0x8728 0x387C88: 2F87 , porque +34 607 = 0x872F 0x387C8C: 3287 , porque +34 610 = 0x8732 0x387C90: 3987 , porque +34 617 = 0x8739 Para hacer un parche a partir de estos datos, se puede usar un programa llamado PATSeach, aunque a mí me resulta más sencillo usar el comando fc del MSDOS y comparar la Flash inicial con mi Flash alterada. Por ejemplo: fc /b C35_original.bin C35_cambia_prefijos.bin que, para el trozo que cambia los numeros (+213 pasa a ser +34 600 , +376 pasa a ser +34 667, +54 pasa a ser +34 610 , +61 pasa a ser +34 617 ) resulta: 387C84: D5 28 387C85: 00 87 387C88: 78 2F 387C89: 01 87 387C8C: 36 32 387C8D: 00 87 387C90: 3D 39 387C91: 00 87 Otro hack satisfactorio. PARCHES AJENOS ************** Un parche fácil: He encontrado por ahí un parche para eliminar el mensaje 'Minesweeper. With compliments from Microsoft' que aparece antes de empezar a jugar con el buscaminas. El parche simplemente dice: ;Firmware: C35 v18 lg4 ;Author : [ZZToP] ;File : Minesweeper.vkp ;Remove message "With compliments of Microsoft" on start Minesweeper 2589BA: DAC4 0D01 O sea, que cambiara soló 2 bytes. Para intentar comprender lo que hace, voy a desensamblar el código original. En vez de empezar por la posicion 2589BA, empiezo 16 bytes antes, en 2589AA. Eso me indicará lo que hay antes del codigo original: sfe d C35_18_From_00.bin,2589AA,20 C00000 E589AA: 88 D0 : mov [-r0], r13 E589AC: 88 C0 : mov [-r0], r12 E589AE: E6 FC 1C 10 : mov r12, #101Ch E589B2: E6 FD E1 03 : mov r13, #3E1h E589B6: E0 0E : mov r14, #0 E589B8: E0 0F : mov r15, #0 E589BA: DA C4 AA 85 : calls 0C4h, loc_C485AA ;<<< esto será cambiado E589BE: 08 04 : add r0, #4 E589C0: DB 00 : rets ;----------------------------------------------- E589C2: F0 CC : mov r12, r12 E589C4: E0 2D : mov r13, #2 E589C6: FA E9 D2 4E : jmps 0E9h, loc_E94ED2 Parece que pone algunas variables en la pila, les asigna valores, y llama a la rutina C485AA. Luego mueve la pila, y retorna en E589C0 . Desenamblando el parche con: sfe d Minesweeper.vkp,2589BA,20 E589BA E589BA: 0D 01 : jmpr cc_UC, loc_E589BE Veo que sustituye el 'calls ... ' por 'jmpr ...' con lo que saltará hasta la instruccion siguiente, en E589BE. Habría sido un poco mas sencillo cambiar el 'calls ... ' por un 'nop', pero así también funciona. O sea, que elimina la llamada a C485AA. Eso quiere decir que C485AA es una rutina que imprime 'Minesweeper. With compliments from Microsoft'. Para verlo con más detalle desensamblo a partir de C485AA-02=C4859A8 : sfe d C35_18_From_00.bin,0485A8,60 0485A8: DB 00 : rets ;--------------------------------------------- 0485AA: 26 F0 66 00 : sub r0, #66h 0485AE: 88 F0 : mov [-r0], r15 0485B0: 88 E0 : mov [-r0], r14 0485B2: 88 C0 : mov [-r0], r12 0485B4: 88 D0 : mov [-r0], r13 0485B6: D4 10 6E 00 : mov r1, [r0+#6Eh] Indica que 0485AA es el comienzo de una subrutina (esto es buena señal: no aterrizo en mitad de la nada) y almacena los registros r12, r13, r14 y r15, que son los que justamente ha asignado en E589AE-E589B8. ?Cómo ha sabido el autor del parche que había que modificar esa dirección, y no otra? Mediante el menú. Antes de E589BA, se han puesto las variables para que r13 y r12 apunten al dibujo con el mensaje. En realidad, el parche fué desarrollado para el modelo S35. El autor del parche para el C35 sólo ha tenido que entender lo que hace el original, buscar la rutina correspondiente en el C35, la ha encontrado en 0485AA, y cambia la zona a sobreescribir. Yo voy a hacer lo mismo. APRENDIENDO DE OTROS ******************** He encontrado otro parche fácil : ;----- without_sim.vkp ------- ;Firmware : SL45v56 ;Author : DeadMans 024C2A: E004 E014 Más simple, imposible. Sólo cambiará 2 bytes en la posición de memoria 0x024C2A para hacer que se pueda trabajar con algunos menús del móvil, aun sin tener insertada la tarjeta SIM. Pero este parche sólo vale para el móvil SL45, version 56. Voy a ver si lo puedo adaptar para mi C35v18. Para trabajar en la adaptación de parches, es necesario entender el modelo original, y el destino. Así que tras un poco de buscar por ahí encuentro la Flash del SL45iv56 en un fichero llamado SL45iv56.bin . Dado que la mayoría de los parches los han hecho los chicos de www.gsm-dev.com y ellos tienen SL45iv56 , no es difícil encontrar una flash. Desensamblando esa zona de memoria en la Flash del SL45v56 con el programa sfe: sfe.exe d SL45iv56.bin,024C2A,20 024C2A: E0 04 : mov r4, #0 ;<<< esto será cambiado 024C2C: DB 00 : rets ;------------------------------------------------ 024C2E: E0 0C : mov r12, #0 024C30: F0 DC : mov r13, r12 024C32: 5C 1D : shl r13, #1 024C34: D7 40 0C 00 : extp #0Ch, #1 024C38: D4 ED 52 23 : mov r14, [r13+#2352h] 024C3C: 48 E3 : cmp r14, #3 024C3E: 3D 02 : jmpr cc_NZ, loc_024C44 024C40: F0 4C : mov r4, r12 024C42: DB 00 : rets Y desensamblando el parche: sfe d without_sim.vkp,180AC,2 0180AC: E0 14 : mov r4, #1 O sea, que el parche hace que, en vez de asignar r4=0 , hace r4=1. Para ver como adapto este parche al C35, uso el sfe para buscar una cadena de bytes parecida sfe f C35_18_From_00.bin E0,04,DB,00,E0,0C,F0,DC,5C,1D 1. 0x0180AC (0306:00AC): E0 04 DB 00 E0 0C F0 DC 5C 1D 2. 0x192AF4 (0364:2AF4): E0 04 DB 00 E0 0C F0 DC 5C 1D 3. 0x192B5A (0364:2B5A): E0 04 DB 00 E0 0C F0 DC 5C 1D Desensamblando estas 3 zonas de memoria, la que más se parece es la primera: sfe d C35_18_From_00.bin,180AC,50 0180AC: E0 04 : mov r4, #0 0180AE: DB 00 : rets ;------------------------------------------------ 0180B0: E0 0C : mov r12, #0 0180B2: F0 DC : mov r13, r12 0180B4: 5C 1D : shl r13, #1 0180B6: D7 40 40 00 : extp #40h, #1 0180BA: D4 ED D0 24 : mov r14, [r13+#24D0h] 0180BE: 48 E3 : cmp r14, #3 0180C0: 3D 02 : jmpr cc_NZ, loc_0180C6 0180C2: F0 4C : mov r4, r12 0180C4: DB 00 : rets Asi que el parche para el C35 no hay mas que: 0180AC: E004 E014 Lo cargo, lo pruebo, y funciona. Ahora ya puedo acceder a algunos de los menús sin tener la tarjeta SIM. Pero no siempre es tan sencillo, claro. ADAPTANDO DE OTROS ****************** Otro parche que he encontrado se llama 111_Do_Not_Allow_To_Enter_112_In_Keylocked_Mode.vkp ;Firmware: SL45 v56 0311BC: EA207012 CC00CC00 que hace que NO se pueda marcar el numero de teléfono de emergencia 112. El parche sólo vale para SL45 v56. Voy a ver si lo puedo traducir para mi C35i. Desensamblo la flash del SL45 v56: 0311B8: 08 02 : add r0, #2 0311BA: 48 40 : cmp r4, #0 0311BC: EA 20 70 12 : jmpa cc_Z, loc_031270 ; <<< #include main(int argc, char *argv[]) { FILE *ap; unsigned char c1=0, c0, c; int i, j; int buscados[10], total=0, exitos=0; long posi[10], posi0=-1, posi10; char cad[200]; ap=fopen(argv[1],"rb"); if(ap==NULL) { printf("No encuentro archivo flash %s \n", argv[1]); exit(1); } /* busca los bytes a partir del argumento 2 */ /* el formato es en hexa: C0 DF 66 ... */ for(i=2;i9) c0=c0+'0'-'A'+10; c1=cad[0]-'0'; if(c1>9) c1=c1+'0'-'A'+10; buscados[total]=c0+c1*16; printf("Buscando %0.1X \n", buscados[total]); posi[total]=-1000; total++; } while(!feof(ap)) { c0=getc(ap); posi0++; for(i=0;i8*total/10 && exitos!=total ) /* exito parcial */ printf("%i en %0.6X -> %0.6X\n", exitos, posi0, posi10 ); if(exitos==total ) printf("*** %i en %0.6X -> %0.6X\n", exitos, posi0, posi10); } } return 1; } Lo ejecuto con di_near C35_18_From_00.bin 08 02 48 40 E6 FC 4A 00 y me salen 5 posibilidades. De ellas la que más se parece es 0219DE: 08 02 : add r0, #2 0219E0: 48 40 : cmp r4, #0 0219E2: 3D 03 : jmpr cc_NZ, loc_0219EA 0219E4: E0 14 : mov r4, #1 0219E6: EA 00 BA 1A : jmpa cc_UC, loc_021ABA 0219EA: loc_0219EA: E6 FC 4A 00 : mov r12, #4Ah que, aunque tiene otras lineas en medio, el resto es idéntica a la rutina del SL45. Ahora tengo 2 saltos: a loc_0219EA y a loc_021ABA. Y para cada uno, hay posibilidades: puedo eliminar el salto, o forzarlo. Empiezo por cambiar jmpr cc_Z, loc_0219EA o sea: 0219E2: 3D03 2D03 y compruebo que al bloquear teclado (Keylocked_Mode), ahora puedo escribir cualquier numero, excepto el '1' y el '2'. Bueno, es una manera de deshabilitar la llamada al número de emergencia. Lo que me interesa no es deshabilitarlo, sino entender cómo funciona. Lo que hace esta rutina es chequear la tecla pulsada cuando el móvil está con el teclado bloqueado. Originalmente, si es '1' o '2', entonces permite esa tecla, aunque hace otro chequeo posterior para ver que los números 1-1-2 están en el orden correcto. Mi parche lo que hace es permitir la tecla si NO es '1' ni '2'. Además, evita el segundo chequeo. Aunque esto parezca una simple conversión, en realidad es otro hack exitoso. OTRA ADAPTACION *************** Hay otro parche llamado 'Call Minutes Beep'. Este es más difícil de entender, asi que si no estás despejado, mejor dejas la lectura para otro momento. Abro el fichero cmb_vibra.vkp con un editor de textos. En las primeras lineas veo que dice: ; Firmware: SL45i v56 ; Author: rc-flitzer O sea, que este parche tampoco vale para mi S45 ni para mi C35. Pero al parecer, el propósito de este parche es cambiar el tiempo y periodo del pitido de cada minuto. El móvil tiene una configuración que hace que cuando estoy hablando, puede emitir un pitido cada minuto. Esto sirve para saber el tiempo que llevo de charla, y el parche me permitirá cortar la llamada justo antes que transcurra un minuto completo, apurando al máximo el coste de la llamada. Además, el modo de vibración tambien se puede activar. Este es el contenido del parche ---------------------------------------------------- 0x001F20: F2F40CFE DAC710D1 ; Olvídate de esta linea. 0x27D6EA: FFFFFFFFFFFFFFFF F2F40CFE88C046F4 ; This value is time, when vibra should start, ; here 50 = 50 seconds. Because of period is 60 seconds the vibra ; sounds ten seconds before every minute. ; Change value if you like, but has to be smaller than the time period. 0x27D6F2: FFFF 3200 ; = 0x32 = 50 decimal 0x27D6F4: FFFFFFFFFFFFFFFFFFFFFFFFFFFF 3D05E6FC2F00DAC314000D0646F4 ; This value is value above plus one for one second vibra. ; You can make two or more seconds, but it's not recommended 0x27D702: FFFF 3300 ; = 0x33 = 0x32 + 1 0x27D704: FFFFFFFFFFFFFFFFFFFFFFFF 9D03E00CDAC3140098C0DB00 ---------------------------------------------------- El primer dato de cada linea (0x27D6EA) indica la posición de memoria donde se tiene que meter. El segundo (FFFFFFFFFFFFFFFF) indican los datos originales. El tercero (F2F40CFE88C046F4) indica los datos que hay que meter. Luego hay algunas lineas con comentarios. En este caso particular, es posible modificar algunos de los parámetros, tal como la duración y el momento en el que debe vibrar. Ahora explico cada uno de ellos. Para la posicion de memoria, hay que entender que viene dada en hexadecimal, ocupando 24 bits. El procesador C166 usa bancos de 64 Kb (16 bits), paginados mediante un indicador de 8 bits, lo que da acceso a 16 Mb (24 bits). La Flash para el C35 ocupa 4 Mb y empieza en 0xC00000 , mientras que para el modelo SL45 ocupa 6 Mb y empieza en 0xA00000. Pero para los parches, la dirección se considera empezando en 0x000000, tal como se encuentra en el fichero con la Flash. En otras palabras, direccion_memoria=0xA00000+direcion_fichero Por eso un parche que dice empezar en 0x27D6EA realmente va a 0xC7D6EA. El segundo dato me dice que en esa posicion debería haber FFFFFFFFFFFFFFFF , lo cual son 8 bytes con el valor 0xFF. Esto sirve para no aplicar 2 veces el parche, y para verificar que efectivamente estoy tratando con la versión adecuada de la Flash. El tercer dato contiene los datos a grabar. El formato permite usar lineas de tantos caracteres como queramos, aunque 16 bytes es un buen número. En esta primera linea veo que los datos son F2F40CFE88C046F4, ocupando 8 bytes. La segunda linea dice que los datos deben ir a 0x27D6F2 . Esto es obvio, pues 0x27D6EA+0x8=0x27D6F2 El autor ha creado la linea 0x27D6F2: FFFF 3200 ; = 0x32 = 50 decimal para explicar claramente que este dato se puede cambiar si deseo que vibre en el segundo 50-esimo, o en otro que se me antoje. Así que arranco el programa v_klay y cargo este fichero. Me pide apagar el móvil y pulsar brevemente el boton de encender. Dado que no tengo un SL45i , el parche ni siquiera se intenta meter en el móvil. Hay una primera linea que no he explicado: 0x001F20: F2F40CFE DAC710D1 Este linea va en la posición de memoria 0xA01F20, y espera encontrar los bytes F2F40CFE para sustituirlos por DAC710D1. Tras cargar la Flash del SL45iv56 en un editor hexadecimal, compruebo que en 0x001F20 yo tengo los bytes F2F40CFE . A DESENSAMBLAR ************** Ahora con el programa sfe (Siemens Flash Explorer) escribo: sfe d SL45iv56.bin,1f00,200 desensambla el fichero SL45iv56.bin desde la posición 1F00 hasta 200 bytes más. No elijo la direccion 01F20 porque me interesa ver un poco de lo que está antes: 001F00: 40 29 : cmp r2, r9 001F02: F0 C4 : mov r12, r4 001F04: F0 D5 : mov r13, r5 001F06: DA A0 0C 2F : calls 0A0h, loc_A02F0C 001F0A: DA DE 6E 15 : calls 0DEh, loc_DE156E 001F0E: 48 41 : cmp r4, #1 001F10: 3D 12 : jmpr cc_NZ, loc_001F36 001F12: DA A0 78 2F : calls 0A0h, loc_A02F78 001F16: E6 FC 3C 00 : mov r12, #3Ch 001F1A: F6 F4 0E FE : mov mem_FE0E, r4 001F1E: 5B CC : divu r12 001F20: F2 F4 0C FE : mov r4, mem_FE0C ; <<<0, salta. ;---------------------------------------------------- 230050: E0 2C :loc_230050;<Reversi->Opciones->Ayuda a partir de ahora no dirá ayuda, sino que hará lo que yo quiera. Y lo que quiero es que imprima en la pantalla del móvil la dirección desde la que lo llamo. El mismo dato que se manda por el puerto, pero por pantalla. IMPRIMIR ******** Para averiguar cómo se hace para imprimir, desensamblo un parche llamado Thermometer.vkp Este parche imprime en la pantalla la temperatura de la batería. Sí, el móvil tiene un pequeñio termómetro para que se apague automáticamente cuando hace mucho calor o mucho frio. No tiene mucha precisión, y dado que está cerca de la batería, no reacciona rápidamente a los cambios de la temperatura ambiente. El parche saca el dato de 0x0C2C08 , hace algunos cálculos, asigna r12=x , r13=y, r14=0x13A+un_indice y llama a 0x0E5ABA4 Tiene en total 60 lineas en ensamblador, pero no voy a aburrir con los detalles. La asignación de r12 y r13 está clara. La pantalla mide 101x54 y se empieza a contar desde la esquina superior izquierda. Estas variables conendrán las coordenadas donde quiero imprimir. La rutina en 0x0E5ABA4 no imprime una letra, sino un dibujo. Siguiendo las indicaciones de antes para usar el 'Siemens Picture Change' , veo que en la posición 0x13A esta el '0', por eso tiene que hacer r14=#13Ah. Para imprimir el '1', el índice es 0x13A+1=0x13B, y así hasta el '9'. Como mi dato es una palabra de 16 bytes, lo escribiré como un código hexadecimal de 4 letras 0-9A-F Por ejemplo, si la dirección es 0x89BA, imprimo los caracteres 8, 9, B, A. Pero lamentablemente el índice 0x13A+0x0A no apunta a la letra 'A', sino a un rectángulo de 6x9 totalmente vacío. Es mas, el índice 0x13A+0x0B = 0x145 apunta a un dibujo de 21x7 de una llave. No todo está perdido. Usando 'Siemens Picture Change' puedo cambiar los dibujos, incluso su tamanio. En un momento edito desde 0x144 hasta 0x14A para que contengan los dibujos de las letras 'A' hasta 'F', y los meto de nuevo en el télefono. Basicamente, si r3 contiene el semi-byte (0-F) a imprimir: mov r12, #32h ; x mov r13, #22h ; y mov r14, r3 and r14, #000Fh add r14, #13Ah ; apuntador base para dibujos calls 0E5ABA4h El segundo problema al que me enfrento es que no voy a tener espacio suficiente en 0C485AAh . Pero la memoria tiene muchas areas vacías. Escojo 0C7FAE0, donde puedo usar 256 bytes. También podría usar 0x2D0000, donde tengo 64kb libres. En el C35i hay 8 bloques de 64Kb que no se usan. Esto da para escribir muchos programas en estas zonas libres. En particular, desde 0x2C6ED2 hasta 0x334000 hay 436Kb libres. Para imprimir toda la dirección IP tengo que llamar a esta subrutina 4 veces con distintas posiciones x. Cada dibujo mide 6x9 así que tengo que variar 'x' en 6+1 pixels. ------------------------- base 0C00000h ; autoconvierte las direcciones. La memoria empieza en 0x0C00000 #include C166.inc #define imprime 0E5ABA4h ; Rutina de la EPROM que imprime un icono org 0C485AAh ; dirección original de la llamada push PSW ; guardo los flags. Sólo se pueden guardar en la pila mov [-r0], r3 ; guardo los registros que modificaré pop r3 ; saco los flags de la pila mov [-r0], r3 ; y los meto en la pila local pop r3 ; extraigo InstructionPointer de la pila push r3 ; y lo meto de nuevo. Ahora lo tengo en r3 movb S0TBUF, rh3 ; Primero saco el byte mas significativo bclr S0TIR ; lo mando al puerto aqui_mismo1: jnb S0TIR, aqui_mismo1 movb S0TBUF, rl3 ; luego la parte baja: el menos significativo bclr S0TIR aqui_mismo2: jnb S0TIR, aqui_mismo2 calls imprime_ip ; una vez 'puerteado', lo muestro en pantalla mov r3, [r0+] ; recupero los flags push r3 ; meto los flags en la pila mov r3, [r0+] ; recupero el registro r3 pop PSW ; saco los flags de la pila rets org 0C7FAE0h ; no hay espacio suficiente en 0C485AA. Pero aquí hay un montón imprime_ip: ; imprime r14 de derecha a izquierda . Si r14=ABCD, imprime ; primero D , luego C, despues B, y al final A ; pero como la posicionX se va decrementanto, aparece ABCD mov [-r0], r12 ; guardo los registros que uso mov [-r0], r13 mov [-r0], r14 mov r14, r3 ; contiene la palabra (16 bits) a imprimir mov r13, #2Ah ; y mov r12, #39h ; x callr mi_imprime ; imprime solo el nibble (4-bits) menos significativo mov r14, r3 shr r14, #04h ; ahora imprimo el segundo nible menos significativo mov r12, #32h ; a la _izquierda_ del anterior dato callr mi_imprime mov r14, r3 shr r14, #08h mov r12, #2Bh ; x callr mi_imprime mov r14, r3 shr r14, #0Ch mov r12, #24h ; x callr mi_imprime mov r14, [r0+] ; recupero los registros mov r13, [r0+] mov r12, [r0+] rets mi_imprime: and r14, #000Fh ; me quedo con la parte baja add r14, #13Ah ; base para pictures mov [-r0], r13 mov [-r0], r3 calls imprime mov r3, [r0+] mov r13, [r0+] ret end -------------------------- Notar que he cambiado el orden de los bytes para que los imprima en big-endian. Como antes, para compilar: sfe a puerto_pantalla.asm d Y para generar el parche: sfe a puerto_pantalla.asm p Lo meto en el móvil, navego por los menús, y veo la dirección tanto en el hyperterminal como en la pantalla del móvil en la zona que hay abajo, en medio. La rutina anterior tampoco es perfecta. Ahora guardo bien los flags, pero todavía hay otros detalles que no tengo en cuenta, ej. las interrupciones. Al menos, ahora tengo algo que se puede llamar desde cualquier sitio. No afectará al programa que llame a mi rutina, pero a mí me será util. Ciertamente me pueden llamar desde otras rutinas en otros segmentos, pero todavía no imprime correctamente la direccion completa. Para ello haría falta extraer también el CSP (Code Segment Pointer) aunque esto es más delicado, pues hace falta saber si me han llamado con una instrucción CALLS (Call Inter-Segment Subroutine, que si guarda en CSP) o desde una instrucción CALLA (Call Subroutine Absolute), CALLI (Call Subroutine Indirect), o CALLR(Call Subroutine Relative), las cuales no usan CSP. MEMORIA ******* Espero que haya quedado suficientemente claro que la zona en la que están almacenados los programas en el C35i empieza en la Flash a partir de 0xC00000 . El teléfono tiene otras zonas de memoria: 0x000000 = inicio. Mide 0x000200 0x000200 = DRAM. Mide 0x00EE00 0x00F000 = SFR/ESFR. Mide 0x001000 y almacena los registros. 0x010000 = ROM del chip. Mide 0x008000 0x010800 = Word-writeable. Mide 0x007800 0x100000 = RAM. Mide 0x040000 0xC00000 = Fullflash. Mide 0x400000 La última dirección es 0xFFFFFF Estos 16Mg de memoria ocupan un espacio de direcciones de 2^24 bits, es decir, 3 bytes. Hay 2 maneras de agruparlos: -en 256 bloques de 64Kb, llamados segmentos. Se usa la notación 0x123456 -en 1024 páginas de 16Kb. Se usa notación 048:3456 La formula para pasar entre uno y otro es dividir entre 0x4000 Asi, 0xFCA123=3F2:2123 , porque 0x3F2*0x4000+0x2123=0xFCA123 Algunos programas tales como el 'AT Debugger' usan notación de páginas, mientras que el resto usan segmentos. Es conveniente usar la calculadora incluida en 'AT Debugger' para hacer las transformaciones. Para acceder a la memoria se puede direccionar de 3 maneras distintas: -Código, usando el Puntero de Segmento de Código. También llamado Modo Corto Es el modo que todos imaginamos; usa la dirección completa: jmpr loc_FCA123 -Datos, usando Puntero a Página de Datos. También llamado Modo Largo. Hay 4 registros DPP0, DPP1, DPP2, DPP3 que apuntan a una página. Se combina con otro valor (offset) para obtener la dirección completa: mov DPP0, #03F2h mov r12, #2123h otro ejemplo : jmps #03F2h, #2123h -Direccionamiento de Datos via Modo Extendido. -Extensión mediante segmento: Primero se usa una instrucción para usar un segmento alternativo, y luego la instrucción para tomar el dato: extp #0FCh, #1h mov r12, #0A123h -Extensión mediante página: Primero se usa una instruccíon para usar una página alternativa, y luego la instruccion para tomar el dato: extp #03F2h, #1h mov r12, #2123h Hay instrucciones que funcionan con segmentos, y otras con páginas: JMPS seg, caddr ; salta a una dirección 'caddr' en un segmento 'seg' JMPA cc, caddr ; salta a una dirección en el mismo segmento CALLS seg, caddr ; llama a la subrutina en 'caddr' del segmento 'seg' CALLA cc, caddr ; llama a la subrutina en la dirección absoluta 'caddr' . RET ; retorna desde una subrutina en el mismo segmento RETS ; retorna desde una subrutina entre segmentos El segmento 0, que va desde 0x000000 hasta 0x010000 ocupa 64 Kb (como todos los demás) y cuando se cambia algun dato en el segmento 1 (direccion 0x100000), también resulta modificado en el segmento 0. O sea: mov r3, #1234h extp #40h, #1h mov 00h, r3 Escribe 1234 en 40:0000 , es decir, 0x100000 Pues bien: el dato en 00:0000 también contiene 1234. De hecho, para escribir en el segmento 0, debo hacerlo en el segmento 1, y se copiará automaticamente. Es por esto que hablaré indistintamente de 0x100000 o de 0x000000. Para leer de la memoria, se puede usar el 'Siemens Debugger' o el 'ATDebugger'. O tambien puedo modificar mi programa para que lo haga. Navegando por los menus aprendo que: Juegos->Wayout->Highscore llama a 3E26 Juegos->Buscaminas->Highscore llama a 1F3A Lo primero que debo es discernir cual menú me ha llamado. Por simplicidad, solo chequeo el byte menor (será #26h o #3Ah) La dirección de memoria que voy a usar es 1000D4=40:00D4 Así que renombro la rutina imprime_ip para llamarla imprime_r3, y queda así: cmpb rl3, #26h ; vengo de Juegos-Wayout-Highscore jmpr cc_Z, go_wayout cmpb rl3, #3Ah ; vengo de Juegos-Buscaminas-Highscore jmpr cc_Z, go_mines go_wayout: extp #40h, #1h mov r3, 0D4h ; lee la memoria calls imprime_r3 jmpr cc_NZ, go_fin go_mines: mov r3, #1234h extp #40h, #1h mov 0D4h, r3 ; escribe '1234' en la memoria calls imprime_r3 jmpr cc_NZ, go_fin go_fin: mov r14, [r0+] ; recupero los registros mov r13, [r0+] mov r12, [r0+] mov r5, [r0+] rets Hala, ya puedo escribir donde me apetezca, y leerlo despues. Claro que esto no es muy versátil. Tendría que permitir elegir la zona de la memoria donde quiero leer/escribir, y pedir también el dato en caso de que quiera escribirlo. Pero para eso ya estan los otros programas que he mencionado antes. Una cosa curiosa es que el 'Siemens Debugger' parece tener problemas a la hora de leer algunas direcciones, en particular me resetea el móvil cuando intento acceder a direcciones entre 0x00E000 y 0x00E400. Funciona si uso 0x10E000 , y los datos parecen ser correctos. Por contra, el 'ATDebugger' tiene otro fallo y es que sólo me deja escribir 5 ó 6 comandos. Al cabo del tiempo, la paridad del puerto cambia y el programa se vuelve loco. La solución es apagar en móvil, lo cual es un fastidio cuando he tardado media hora en preparar el escenario correcto. Por eso me he acostumbrado a usar ambos programas y verifico los datos 2 veces. El 'ATDebugger' necesita que el móvil esté encendido, mientras que el 'Siemens Debugger' necesita que esté apagado, para meter el BootStrap. Pero en el C35i es posible usar un rodeo: -encender el móvil -pulsar el boton de 'Iniciar modo de servicio' -esperar a que se queje de que el modo BFB no se ha iniciado -pulsar el boton de 'Salir del modo de servicio' -pulsar de nuevo el boton de 'Iniciar modo de servicio' -ahora ya se tiene aceso a toda la funcionalidad del 'Siemens Debugger'. Bueno, ahora ya puedo manejarme sin problemas con la memoria. DESARMANDO TRAMPAS ****************** La manera normal de llamar a una subrutina es con JMPS o CALL. Pero existe una manera mas cómoda de llamar a rutinas que se usan habitualmente: los traps. Desde la dirección 0x000000 hasta 0x000200 hay unas rutinas muy breves que gestionan los errores que pueden suceder en tiempo de ejecución. Recordar que el segmento 0x100000 es una copia de 0x000000 . Según el manual, en la posición 0 hay una rutina que se llamará cuando se produce un RESET por hardware, por software, o Watchdog. Brevemente, un Watchdog es una rutina invocada por un dispositivo externo -típicamente el reloj- que tiene que ser respondida por el programa. Si no es respondida, el dispositivo entiende que el programa se ha colgado, y hace un reset del procesador. Sólo hay una rutina que gestiona estos 3 eventos, pero se puede saber cual de los eventos ha sucedido mirando el valor del registro SFR llamado 'WDT Control Register' en la dirección FFAE. Si el bit 1 (llamado WDTR=Watchdog Timer Reset Indication Flag) vale 1, entonces es Watchdog quien llama. Si el bit 2 (llamado SWR=Software Reset Indication Flag) vale 1, entonces es un RESET por Software Si SWR vale 0, entonces es un RESET por Hardware. La rutina llamada desde 0x000000 hace simplemente: jmps 0D4h, 04704h Desensamblando a partir de 0xD44704h veo que hace mov CC7, #10h trap #30h rets Esto es: pone a #10h el registro SFR llamado CC1, que está en la posición FE8E Luego llama al trap número #30h Un trap funciona igual que una interrupción RESET de las anteriores; se mira cual es el número de trap en la tabla que empieza en 0x000000 , y se llama a la rutina. Para calcularlo, se toma el numero de trap y se multiplica por 4. El trap #30h llama a la rutina en 0x0000C0, pues 30h*4h=C0h En 0x0000C0 hay: jmps 0D4h, loc_D44A28 y en 0xD44A28 hay: bfldh PSW, #0F0h, #0F0h extp #3, #4 mov mem_37AA, r0 mov mem_37B6, mem_FE10 mov mem_37B8, DPP0 mov mem_37BA, DPP1 ....... La primera instrucción limpia todos los bits del registro SFR llamado PSW (posición FF10), que contiene los flags. El bit 7 de la parte alta de PSW (bit 7+8=15) se pone a 1. Esto hace que el procesador ejecute este trozo de código en la máxima prioridad, sin permitir que otras tareas lo interrumpan. Esto es normal cuando se procesa una interrupción. luego hace que las siguientes 4 instrucciones usen el segmento #3. Dichas 4 instrucciones hacen: guardar r0 en 3:37AA = 0x00F7AA meter Context Pointer en 3:37B6 = 0x00F7B6 meter el Data Page Pointer DPP0 en 3:37B8 = 0x00F7B8 meter el Data Page Pointer DPP1 en 3:37BA = 0x00F7BA Y un montón de cosas más que involucran muchos registros y no entiendo lo que hacen. No me apetece ponerme a desensamblar 400 páginas de ensamblador. Pero el concepto está claro, no? En total hay 128 traps, y muchas de ellas saltan a 04704h, por lo que entiendo que es una rutina de propósito general capaz de interpretar casi todas las situaciones que se producen. Sin embargo, hay unas pocas traps que saltan a otras rutinas: El trap 20h salta a 0xC3FFFA en 0xC3FFFA hay: rets Esta es la manera más simple de retornar de un trap : no hacer nada. El trap 35h salta a 0xCCFFEE en CCFFEE hay: bset mem_FE0C.13 bset STKOV.6 calls 0D3h, loc_D337B0 reti Y en D337B0 hay: bclr CC5IC.6 bclr CC14IC.6 bclr CC10IC.6 extr #1 bclr CRIC.6 rets O sea, que limpia el bit 6 de las variables del periferico CAPCOM1. Esto no tiene mucho sentido para mí, porque no todas las variables se limpian. Ni tampoco se preservan los registros usados. Es posible que este código en realidad no se llame nunca. Voy a investigar sobre esto. Los traps es una manera eficiente de llamar a una rutina. Para invocarlos, se usa la instruccion trap #35h que se codifica en los bytes 9B 6A Buscando en la memoria estos datos, aparecen 2 veces: Primera vez, en 0xDA48F6. Al desensamblar: trap #35h xorb 7F78h, rl0 movb PWMCON1, #4Dh add r0, r0 add r0, r0 add r0, r0 que no tiene mucho sentido, pues "add r0, r0" no sirve de mucho, y menos hacerlo 3 veces seguidas. Segunda vez, en 0xDA6712. Desensamblando 8 bytes antes, en 0xDA670A : DA6704: 79 53 : orb rh2, #3 DA6706: 96 F1 D2 7C : cmpi2 r1, #7CD2h DA670A: 41 43 : cmpb rl2, rh1 DA670C: 10 81 : addc r8, r1 DA670E: 38 86 : subc r8, #6 DA6710: 6A 59 9B 6A : band mem_FF36.10, S0RBUF.6 DA6714: 54 60 0F E2 : xor 0E20Fh, PECC0 Veo que en realidad forman parte de la instrucción "band mem_FF36.10, S0RBUF.6", que tampoco tiene mucho sentido. Por ello deduzco que la aparición de estos bytes es simple casualidad. Quizás sea parte de un dibujo, o de datos. No es código válido. Entonces, parece que nadie llama al trap 35h... hasta ahora HACIENDO TRAMPAS **************** Como el C166 es un micro de 16 bits, todas las instrucciones ocupan 2 o 4 bytes. Incluso la instrucción más simple NOP se codifica como CC 00 También es necesario que empiecen en una posición par. En el ejemplo anterior, si los bytes 9B 6A estuvieran en la dirección 0xDA6711, yo sabría de inmmediato que no es una intruccion. El mini-tracer de antes tiene un inconveniente: para llamarlo necesito hacer CALLS 0xC485AAh que se codifica como DA C4 AA 85 y ocupa 4 bytes. Sería mejor si ocupara solo 2 bytes. Así podría sustituir cualquier instrucción por una llamada a mi rutina. Gracias a los traps puedo hacerlo: -Establezco que el trap #35h salte a 0xC7FBC0 Para ello solo tengo que variar la memoria 35h*4 para que haga jmps 0xC7FBC0h Es decir, poner bytes FA C7 C0 FB (little-indian) a partir de 0x0000D4 -En mi víctima, llamar a mi trap con trap #35h Es decir, poner bytes 9B 6A -Imprimir la dirección que me ha llamado, y hacer lo que hubiera en la instrucción original Así, una rutina que sea: 98 90 : mov r9, [r0+] F0 C9 : mov r12, r9 DB 00 : rets la sustituiré por: 98 90 : mov r9, [r0+] F0 C9 : mov r12, r9 9B 6A : trap #35h DB 00 : rets La rutina de respuesta al trap es: org 0C7FBC0h mi_trap: mov [-r0], r3 ; guardo r3 porque lo voy a sobrescribir pop r3 ; en la pila está IP , o sea, dónde ha saltado la trampa push r3 ; lo vuelvo a meter. calls imprime_r3 ; y lo imprimo mov r3, [r0+] reti ; salir de la trampa end La rutina de inicialización del trap es: go_mines: mov r3, #0C7FAh extp #40h, #1h mov 0D4h, r3 ; dirección del trap #35h mov r3, #0FBC0h extp #40h, #1h mov 0D6h, r3 calls imprime_r3 jmpr cc_NZ, go_fin Para probar mi trampa, sé que cuando pulso la tecla '#', originalmente llama a D6D580: 9A 08 02 00 : jnb mem_FE10.0, loc_D6D588 Entonces sustituyo esos bytes por 9B6ACC00, que significa trap #35h nop Así que -compilo el parche -lo meto en el móvil -activo el nuevo trap mediante el menú buscaminas->Highscore -verifico que la memoria 0x0000D4 contiene 'jmps 0x0C7FBC0h' -pulso '#' en el teclado -y me muestra la direccion D588, que es el offset de D6D588 Bueno, en realidad me muestra D6D588+2 , pues ésta es la dirección a donde volveré despues de la trampa. Tengo que modificar el parche para además del offset tambien imprima el segmento (0x00D6), pero eso es un detalle menor. Recordar que una instrucción trap mete en la pila los valores: -PSW: flags (Carry, Overflow, ...) -CSP: Code Segment Pointer -IP: Instruction Pointer Me ayudaría todavía más si imprimiera los últimos 10 valores de la pila, y las variables r0, r1, r2, ... Pero eso (más o menos) es lo que hacen los programas 'Siemens Debugger' o el 'ATDebugger'. Me permiten llamar a una subrutina, y me dicen el estado de las variables. Lo bueno es que yo lo he implementado haciendo que el teléfono sea el punto de partida. Ellos hacen que sea el ordenador el que tenga que invocar al móvil. Para sacarle todo el partido que yo quiero, empiezo a sustituir un montón de instrucciones en la Flash. Por ejemplo, puedo cambiar todas las instrucciones mov r9, [r0+] por trap #35h Y anadir un ultimo paso en mi_trap: ...... mov r3, [r0+] mov r9, [r0+] ; <-nueva instruccion reti end Mejor todavía es sustituir rets por trap #35h Así, cada rutina, en vez de salir, me llamará a mi_trap, donde puedo mirar los valores que retorna a la subrutina llamante. Entonces tengo que hacer que vuelva a su sitio original. Voy a explicarlo con más detalle. Suponer que en 0xCC1110 hay: 0xCC1110 : E6 FC 11 00 : mov r12, #11h 0xCC1114 : DA 22 22 22 : calls 022h, loc_222222 0xCC1118 : 46 FC 22 00 : cmp r12, #22h y en 0x222222 hay: 0x222222 : E6 FC 22 00 : mov r12, #22h 0x222226 : DB 00 : rets Cuando 0x111110 se ejecuta, primero se pone r12=#11h, y la instrucción calls hace que en la pila se guarde el valor 0x111118 , pues ésta es la siguiente instrucción que se ejecutará cuando 0x222222 retorne. Para activar mi trampa pongo a partir de 0x222222 : 0x222222 : mov r12, #22h ; esto no cambia 0x222226 : trap #35h ; originalmente decia rets Y cambio mi trap para que no vuelva a la instrucción que sigue al trap, sino a la siguiente instrucción de la llamada inicial: mi_trap: ...... mov [-r0], r6 mov [-r0], r5 mov [-r0], r4 mov [-r0], r3 pop r3 ; en la pila esta IP: 0x2226+2. No lo necesito pop r3 ; en la pila esta CSP: 0x0022. Tampoco lo necesito pop r6 ; en la pila esta PSW pop r5 ; en la pila esta el IP de la dirección que ha ; llamado a la rutina que me ha llamado: 0x1114+4 pop r4 ; en la pila esta el CSP de la dirección que ha ; llamado a la rutina que me ha llamado: 0x00CC push r6 ; mete PSW de nuevo push r4 ; mete CSP (0x00CC) de nuevo push r5 ; mete IP (0x1114+4) de nuevo mov r3, r4 calls imprime_r3 mov r3, r5 calls imprime_r3 mov r3, [r0+] mov r4, [r0+] mov r5, [r0+] mov r6, [r0+] reti ; esto sacara IP, CSP, PSW end Llamo a la rutina 0xCC1110 y efectivamente al retornar desde loc_222222, llama a mi trampa e imprime 0xCC1118 . Parece que la trampa funciona bien. DESMONTANDO TRAMPAS VIEJAS ************************** Para tracear una función necesito que caiga en alguna de mis trampas. Como no tengo ni idea de donde comenzará la función, lo mejor es poner muchas trampas y confiar en que tarde o temprano caiga en alguna. Pero si pongo una trampa al azar en una instrucción rets cualquiera, tengo que asegurarme de que la trampa está en buenas condiciones. En otras palabras: si sustituyo rets por trap #35h , tengo que estar seguro de que el trap #35h va a saltar a 0xC7FBC0. Esto es, que la dirección 0x0000D4 contiene 'jmps 0x0C7FBC0h'. Si miro esta zona de memoria, veo que hay 0000D4: FA CC EE FF : jmps 0CCh, loc_CCFFEE ?Quien ha puesto esos datos? Porque yo también los voy a poner, y el último que los ponga, gana la carrera! Busco en la Flash algo que tenga que ver con CCFFEE y veo que los bytes EE FF (Recordar little-indian) aparecen 25 veces. Los desensamblo todos en 25 minutos, y veo que uno de ellos hace D48B02: E6 FC EE FF : mov r12, #0FFEEh D48B06: E6 FD CC 00 : mov r13, #0CCh D48B0A: DA D3 7E 38 : calls 0D3h, loc_D3387E Humm, tambien aparece cerca el dato #0CCh , lo cual es bastante interesante. Desensamblo loc_D3387E para ver lo que hace: D3387E: 1E E7 : bclr DP6.1 D33880: 88 C0 : mov [-r0], r12 D33882: 88 D0 : mov [-r0], r13 D33884: E6 FC 35 00 : mov r12, #35h D33888: 98 E0 : mov r14, [r0+] D3388A: 98 D0 : mov r13, [r0+] D3388C: DA D4 BA 93 : calls 0D4h, loc_D493BA D33890: D1 80 : extr #1 D33892: E6 B5 0F 00 : mov CRIC, #0Fh D33896: 0A 92 30 30 : bfldl CCM5, #30h, #30h D3389A: DB 00 : rets Fantástico: usa r12 y r13, y ademas hace algo con #35h , que es justamente la trampa que yo intento poner. Investigando un poco más veo que loc_D493BA pone r1 y r13 en la memoria apuntada por r12*4. Eso es coherente con mis datos, y loc_D493BA resulta ser una rutina genérica para estabecer el salto de las trampas. Así que tengo que deshabilitar esta rutina, o bien cambiar D48B02: mov r12, #0FFEEh D48B06: mov r13, #0CCh por D48B02: mov r12, #0FBC0h D48B06: mov r13, #0C7h pues mi_trap está en org 0C7FBC0h. Ahora me enfrento con otro problema: ?que pasa si sustituyo un rets por trap #35h , pero todavía no se ha puesto la trampa? O sea, ?y si todavía no se ha pasado por D48B02? Pues que saltará a 0x0000D4, que apuntará a la nada sideral. Cuelgue asegurado. Para solucionarlo tengo que hacer que mi trampa se ponga realmente pronto. Lo primero que se me ocurre es que el trap #0h debe ponerse muy pronto, ya que es la rutina del Watchdog. Tras un rato de búsqueda encuentro: D44714: 88 80 : mov [-r0], r8 D44716: E0 08 : mov r8, #0 D44718: F0 C8 : loc_144718: D44718: F0 C8 : mov r12, r8 D4471A: E6 FD 04 47 : mov r13, #4704h D4471E: E6 FE D4 00 : mov r14, #0D4h D44722: DA D4 BA 93 : calls 0D4h, loc_D493BA que establece la dirección 0xD44704 como destino del trap #0h. Por supuesto, hace uso de la rutina loc_D493BA para establecer la trampa. Ahora imagina el flujo del programa como una gran red. Existe un punto de partida P0 y un destino P9 (la pulsación de la tecla '#'). En algún punto P4 del camino voy a establecer la trampa. Tengo que evitar que los puntos P2 (entre P0 y P4) llame a la trampa, pero también tengo que hacer que algún P6 (entre P4 y P9) la llame. Empiezo a analizar el código inversamente desde 0xD44714 y después de unas cuantas horas de estudio he aprendido mucho, pero no he llegado a ninguna conclusión clara sobre cual es el comienzo. Lo siguiente que se me ocurre es que una dirección útil podría ser la primera de la Flash: 0xC00000 Desensamblando: C00000: mov r12, #32F8h C00004: mov r13, #3D7h C00008: calls 0C0h, loc_C06866 C0000C: jmps 0C0h, loc_C090D4 C00010: rets y C06866: mov r13, r13 C06868: mov r12, r12 C0686A: mov [-r0], r13 C0686C: mov DPP0, #40h C06870: mov [-r0], r12 C06872: mov r14, mem_100396 C06876: mov [-r0], r14 ................ parece prometedor porque establece todas las variables que usa; no asume que tengan valores válidos. Además pone DPP0=#40h que es el primer segmento. No sólo eso, sino que más tarde define los otros segmentos. Hay otros factores que no me convencen: el primero es que no hace nada con las interrupciones ni el watchdog. Yo esperaría que una rutina de inicialización establecería unos criterios rígidos para que nade la interrumpa. Otro aspecto que me intriga es que use mem_100396 . Allí no hay nada, pues ninguna rutina ha puesto ningun dato. La mejor forma de probarlo es modificando C00000: mov r12, #32F8h para que llame a imprime_r3 , ponga r12=#32F8h , y retorne. Lo hago, y veo que lamentablmente no se llama cuando yo espero. EL PRIMER DIA CREO EL CIELO Y LA TIERRA *************************************** Una de las primeras cosas que se hace cuando se inicializa el micro es poner con valores buenos las variables importantes. Entre ellas se pueden incluir: DPP0 = Data Page Pointer, almacenado en FE00 si 16 bits, o en 0x00 si 8 bits. CSP = Code Segment Pointer, en FE08 o 0x04 CP = Context Pointer CP, almacenado en FE10 si 16 bits, o en 0x08 si 8 bits. SYSCON = System Control Register, en FF12 o 0x89 SP = Stack Pointer Register, en FE12 o 0x09 STKOV = Stack Overflow Register, en FE14 o 0x0A STKUN = Stack Underflow Register, en FE16 o 0x0B Se pone la pila SP con la instrucción mov SP, xxyy que se codifica como E6 09 yy xx Normalmente también se pondrán STKOV y STKUN para definir cuánto puede crecer la pila. Hay 2 asignaciones de la pila en 0xD449A0 y 0xD449AE, y otra en 0xC7FC40 Desensamblando cerca de 0xD449A0: D4498E: B7 48 B7 B7 : srst D44992: 9A D6 03 F0 : jnb TFR.15, loc_D4499C D44996: E6 47 00 00 : mov CC7, #0 D4499A: 0D 29 : jmpr cc_UC, loc_D449EE ;------------------------------------------------------------ D4499C: 9A D6 05 E0 : loc_D4499C: D4499C: 9A D6 05 E0 : jnb TFR.14, loc_D449AA D449A0: E6 09 00 FC : mov SP, #0FC00h D449A4: E6 47 01 00 : mov CC7, #1 D449A8: 0D 22 : jmpr cc_UC, loc_D449EE ;------------------------------------------------------------ D449AA: 9A D6 05 D0 : loc_D449AA: D449AA: 9A D6 05 D0 : jnb TFR.13, loc_D449B8 D449AE: E6 09 00 FC : mov SP, #0FC00h D449B2: E6 47 02 00 : mov CC7, #2 D449B6: 0D 1B : jmpr cc_UC, loc_D449EE .................. D449EE: 76 47 00 02 : loc_D449EE: D449EE: 76 47 00 02 : or CC7, #200h D449F2: F2 D6 1C FF : mov TFR, ZEROS D449F6: FA 00 C0 00 : jmps 0, loc_0000C0 Paso a paso: -srst hace un reset del micro. Esto limpia algunas variables para que el micro pueda trabajar en un entorno seguro. -mira si el bit 15 de TFR esta puesto. TFR=Trap Flag Register. Es decir, si está procesando una trampa provocada por una Interruption No Enmascarable (NMI) externa -si es así, hace CC7=0 y la procesa en loc_D449EE -mira si está activado el bit 14. Es decir, si está procesando un Stack Overflow -si es así, pone la pila SP=FC00, hace CC7=1 y la procesa en loc_D449EE -mira si está activado el bit 13. Es decir, si está procesando un Stack Underflow -si es así, pone la pila SP=FC00, hace CC7=2 y la procesa en loc_D449EE -en loc_D449EE limpia los flags de trampas TFR y salta a 0000C0 Recordar que en 0000C0 está la tabla de saltos, así que es equivalente a trap #30 pues 0x30*4=0xC0 Lo importante es que la rutina 0xD449A0 parece un lugar bueno para llamar a la rutina que coloca la trampa. La otra asignación de la pila se produce en 0xC7FC40 C7FC1A: A5 5A A5 A5 : diswdt C7FC1E: E6 03 03 00 : mov DPP3, #3 C7FC22: E6 02 42 00 : mov DPP2, #42h C7FC26: E6 01 41 00 : mov DPP1, #41h C7FC2A: E6 00 00 00 : mov DPP0, #0 C7FC2E: E6 08 00 FC : mov mem_FE10, #0FC00h C7FC32: CC 00 : nop C7FC34: E6 89 46 14 : mov SYSCON, #1446h C7FC38: E6 0B 00 FC : mov STKUN, #0FC00h C7FC3C: E6 0A 0C FA : mov STKOV, #0FA0Ch C7FC40: E6 09 00 FC : mov SP, #0FC00h C7FC44: CC 00 : nop C7FC46: DA 87 C2 FC : calls 87h, loc_87FCC2 ?Que más se puede pedir? -Deshabilita el watchdog para que nadie le interrumpa. -Pone todos los DPP a valores de segmentos conocidos. -Establece SYSCON a un valor que permite control total de la memoria. -Asigna buenos valores para la pila y sus correspondientes límites. Sin duda esta es una rutina que se llama bastante pronto. Cualquier cosa que haga aqui se va a ejecutar muy temprano y con todo el control a mi merced. Pero también es una gran responsabilidad. Cualquier fallo en esta rutina y el móvil no sera' capaz de inicializarse. Esto incluye que es posible que no se pueda re-cargar la Flash para deshacer el error. Yo aviso. Perfecto; ahora ya puedo sustituir todos los rets que quiera porque sé que la trampa está puesta. DONDE MONTAR TRAMPAS ******************** Buscando en la flash veo que rets aparece unas 70.000 veces. Si sustituyo todos por trap #35h corro el riesgo de que el sistema vaya muy lento debido a todos los datos que tiene que sacar. Además, no todas las veces que sale la cadena DB 00 significa que es rets . Es posible que haya una instrucción del tipo mov r14, #000DBh que se codifica como E6 FE DB 00 pero en realidad no es un rets . Esta situación no la puedo evitar a no ser que analice/desensamble el código. Otro caso es que aparezca en una posición impar. Ya que el C166 es de 16 bits ls instrucciones sólo pueden aparecer en posiciones pares. Hago un pequeño programa (llamado di_calls ) que me extraiga de la flash la lista de subrutinas que son llamadas, y quien las llama: #include #include main(int argc, char *argv[]) { FILE *ap, *ap2; unsigned char c1=0, c0, c2, c3, c; int i, j; long posi0=-1, posi10; long llamados[20000]; int frec[20000], total=0, encontrado; ap=fopen(argv[1],"rb"); if(ap==NULL) { printf("No encuentro archivo flash %s \n", argv[1]); exit(1); } ap2=fopen(argv[1],"rb"); while(!feof(ap)) { c0=getc(ap); posi0++; c1=getc(ap); posi0++; if(c0==0xDA || c0==0xFA) /* calls XXXXXX o jumps XXXXXX */ { c2=getc(ap); posi0++; c3=getc(ap); posi0++; posi10=c1*65536+c3*256+c2; if(c2%2==1) /* debe ser posicion par */ continue; if(c1<0xC0) /* debe llamar a una rutina de la flash */ continue; /* la direccion destino no puede ser 0000 o FFFF */ fseek(ap2, posi10-0xC00000, SEEK_SET); c0=getc(ap2); c1=getc(ap2); if(c0==0 && c1==0) continue; if(c0==0xFF && c1==0xFF) continue; /* miro si ha sido llamada anteriormente */ encontrado=-1; for(i=0;i%0.6X\n", 0xC00000+posi0-3, posi10 ); } } /* imprime aquellas subrutinas llamadas mas de 300 veces */ encontrado=300; printf("*** %i - %i\n", encontrado, total ); for(i=0;iencontrado) printf("+%0.6X * %i\n", llamados[i], frec[i] ); return 1; } Lo invoco con di_calls.exe C35_18_From_00.bin >di_calls.txt que genera un fichero di_calls.txt con 63.000 llamadas, y veo que hay 10 rutinas que se llaman mas de 300 veces ! Debo evitar poner trampas en esas rutinas, y las subrutinas llamadas por ellas. Por ejemplo: 0xD31140 es llamado 1304 veces, y se desensambla: D31140: mov [-r0], r15 D31142: mov [-r0], r14 .......................... D3115C: calls 0D3h, loc_D309A2 ........................... D311F2: rets Para no sobrecargar el debug , NO tengo que sustituir D311F2: rets por D311F2: trap #35h Y en la rutina en loc_D309A2 tampoco debo sustituir su rets por trap #35h. Igualmente en las rutinas llamadas desde loc_D309A2 tampoco sustituyo. Lo que me doy cuenta es que estoy otra vez en el problema de la red: unas rutinas llaman a otras y al final me pierdo. Lo primero que tengo que hacer es crear un flag para que la trampa atrape a sus victimas o las libere. Decido que la rutina mi_trap sólo llamara a imprime_r3 cuando la memoria 0x100800 valga 1. Tendré que ampliar mi_trap : ............. push r5 ; mete IP (0x1114+4) de nuevo extp #40h, #1h mov r3, 0800h ; lee la memoria cmp r3, #1 ; mira el flag jmpr cc_NZ, go_fin_trap; no está activado mov r3, r4 calls imprime_r3 mov r3, r5 calls imprime_r3 go_fin_trap: mov r3, [r0+] ............. reti ; esto sacara IP, CSP, PSW Así al menos no perderé tanto tiempo mandando los datos al puerto. Para escribir en la memoria 0x100800 lo puedo hacer desde el 'Siemens Debugger' o habilitar el menú Juegos->Buscaminas->Highscore para que lo ponga. La primera vez lo pruebo con el parche anterior del número de emergencia 112, que sé que en algun momento pasa por 021AC6: DB 00 : rets el cual sustituyo por 021AC6: 9B 6A : trap #35h Meto el parche, activo el flag en 0x100800 , bloqueo el teclado, y cuando intento escribir el numero '1' , aparece en el puerto serie el dato 021AC8. Perfecto. Ahora me lanzo a la aventura y sustituyo 200 rets al azar. Parcheo la Flash, activo el flag, y el puerto serie empieza a volcar las direcciones de memoria por las que voy pasando. Mando y recibo SMS, hago llamadas, navego por los menús, y obtengo un montón de direcciones interesantes. Quizás demasiadas. Algunas rutinas se llaman demasiadas veces, y decido restaurarlas por el rets original. Como mejora podría crear una lista de rutinas que sí deseo imprimir, y otras que no. La rutina de mi_trap tendrá que ver si la rutina interceptada est'a en una lista u otra, y actuar en consecuencia. NOTAS FINALES ************* Esto es sólo un acercamiento al Sistema Operativo de los teléfonos Siemens y su microprocesador interno. En otro artículo seguiré investigando y desarrollaré más parches. *EOF*