Copy Link
Add to Bookmark
Report
SET 033 0X05
-[ 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, <FEgen>,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, <c:\FE>,0 ; inicialmente era <FEgen>
.....
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 , <RegCode2>,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*