TUTORIAL PARA PORTAR PARCHES COMPLEJOS (ASSEMBLING BASICO)
ATENCIÓN: En este tema NO se atenderán solicitudes de parches,
remitirse a los temas dedicados a este fin.
NOTA: Este tutorial es aplicable a todos los modelos soportados por SEtool, sin embargo todos los ejemplos de este tutorial serán para z550 R6GA004, debido soy usuario de este modelo y firmware.
INTRODUCCION:
El objetivo de este tutorial es explicar la manera de portar parches de complejidad moderada, para ello será necesario un acercamiento al assembler básico.
Empiezo con una breve introducción que podrá ser ampliada en los links que se indican durante la misma.
ESTRUCTURA DE LOS PARCHES:
Un parche esta constituido por un encabezado que incluye información del mismo (Modelo y firmware, descripción, autores), la cual no debe ser reconocida por SEtool, por ello, todas estas líneas deben estar precedidas por ";" (Comentadas). Para mayor info click aquí
El cuerpo del parche propiamente dicho, esta constituido por líneas que siguen el siguiente patrón:
Código:
dir: XXXXXXXX YYYYYYYY ;descripción
En donde:
dir es la dirección del firm en la que se realizara el reemplazo que puede ser descripta justamente por la dirección (por ejemplo: 4543839C) o por una base + un offset (por ejemplo 44140000 + 12F839C).
XXXXXXXX es una cadena de valores hexadecimales que se encuentran originalmente en el firm en la dirección indicada anteriormente.
YYYYYYYY es una cadena de valores hexadecimales nuevos que reemplazaran a la anterior.
* IMPORTANTE: Ambas cadenas deben tener igual extensión y solo debe haber un espacio separándolas por cada línea.
* La descripción es optativa y su uso es justificable en el caso de haber más de una opción aplicable a cada línea.
Así, por ejemplo, estos parches son equivalentes:
Código:
;z550 SW-R6GA004
;*àäèî áåç ãà*íèòó*û
;Aumentar Duración de ringtone sms
;(ñ) SiNgle
;(p) sunfire7
+44140000
12F839C: 10270000 C0D40100 ;120 sec
Código:
;z550 SW-R6GA004
;*àäèî áåç ãà*íèòó*û
;Aumentar Duración de ringtone sms
;(ñ) SiNgle
;(p) sunfire7
4543839C: 10270000 C0D40100 ;120 sec
CLASIFICACION DE LOS PARCHES:
Personalmente clasificaría a los parches en 3 categorías:
* Parches sencillos (sin Assembling):Aquellos que solo modifican cadenas de código, generalmente poco extensas, como valores numéricos, temporales, colores, direcciones simples, etc.
El anterior parche, para aumentar la duración de los SMS, es un buen ejemplo.
Podrían también entrar en esta categoría parches que incluyan un bloque de código nuevo poco complejo, como texto en ASCII convertido a hexadecimal, este es el caso de rutas del tipo “tpa/system/settings”, etc.
* Parches moderadamente complejos: (Assembling Básico)Aquellos que incluyen cadenas de código nuevo, generalmente más extensas, con distintos tipos de llamadas internas al mismo parche o incluso a otras partes del firm. Permiten agregar funciones nuevas al teléfono, o modificar en gran medida las existentes.
Necesitan ser desensamblados para portarse.
* Parches Altamente complejos: (Assembling Avanzado)Aquellos que incluyen cadenas de código nuevo muy extensas y complejas. Se necesita gran experiencia y conocimiento del funcionamiento de los parches
. Ejemplo de esto son: Elfpack, Password, Confidenciality, Internal FS move files, etc. --------------------------------------------------------------------------------
TUTORIALES PARA PARCHES SENCILLOS (SIN ASSEMBLING):
Parches sencillos, sin código nuevo:
Minitutorial por Adrian
Minitutorial por Karl05 (Uso de Winhex)
Tutorial por K790player (Tutorial muy completo y explicativo ideal para novatos, o para despejar las dudas que hayan quedado
).
Parches sencillos, con nuevo código nuevo:
Entendiendo patches con FFFF por PabloMDiez
--------------------------------------------------------------------------------
TUTORIAL PARA PARCHES MODERADAMENTE COMPLEJOS (ASSEMBLING BASICO):
Comenzamos con el tutorial correspondiente a este tema. El cual esta basado en el material publicado por JokerXT, que ha sido traducido al ingles y republicado en SE-NSE (Puede consultarse aquí: Modifying/creating Advanced Patches)
Este tutorial esta compuesto por 4 fases. La fase 0 sólo es necesaria realizarla una sola vez por cada Firm de origen disponible. Las fases 1, 2 y 3 se realizarán todas las veces que se porte un parche.
A modo de ejemplo vamos a portar el parche para apagar la radio y el reproductor al desconectar el headset desde R6CA009 a R6GA004:
Código:
;Z550 SW-R6CA009
;?????????? ??????/????? ??? ???????????? ?????????
;Player/radio off when handsfree is disconnected
;(c) IronMaster
+44140000
13a416a: 00210348 6EF191F9
1512490: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 00210948FFB506488CF616F9002804D1
15124a0: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 04488CF611F9002801D0B1F7E9FFFFBD
15124b0: FFFFFFFFFFFFFFFFFFFFFFFF E1FD3D45AD125A4516E90000
SOFTWARE NECESARIO:Si no disponemos de los RAW necesarios, estos pueden generase a partir de los MAIN correspondientes, mediante GExtract o Main2raw. (Ver aqui)
FASE 0: PREPARATIVOS ANTES DE COMENZAR
Instalamos IDA PRO, SMELTER y FASARM, recomiendo ubicar este ultimo en una ruta fácilmente accesible como en el directorio raíz (C:\Armpc\). Colocamos una copia de los Raws en la carpeta Armpc, también recomiendo colocarle nombres sencillos a estos archivos ya que luego van a tener que tipearlos manualmente desde cmd.
Ejecutamos el IDA PRO (32-bit) -> New -> Se abre una ventana para seleccionar el tipo de archivo que van a abrir, seleccionen cualquiera, el IDA luego reconocerá el formato adecuado. Seleccionamos en tipo: "All files (*.*)", buscamos y abrimos el raw de origen. Como dije, le damos "Yes" para que utilice el formato mas adecuado.
También se puede hacer click con el boton derecho del mouse sobre el archivo raw -> Abrir con -> The interactive dissasembler
Se abre la ventana "Load new file", en "processor type" pongan "AMR Processors: AMR710a" le damos "Set" y luego "OK".
Se abre la ventana Disassembly memory organization. En "ROM start address": 0x44140000 (o la base que corresponda a tu modelo, ver mas abajo), colocamos el mismo valor en "Loading address": 0x44140000.
En "ROM size" el offset del ultimo byte del firm. Para z550 R6CA009 es 0x01511F85. Dado que muchos parches agregan bloques de código nuevo después de este valor, es necesario ampliar un poco la sección de firm que va a ser leída por el IDA (con unos 100000 bytes es suficiente). Por esta razón colocamos 0x01611F85. Hacemos lo mismo en "Loading size": 0x01611F85. Una vez modificados estos 4 valores le damos "OK" y esperamos a que se cargue en la database. Cuando nos diga "Generating list of Strings", le damos "Cancel"
Vamos a "Options" -> "General" en el cuadrito de la derecha "Number of opcode bytes" colocamos "4"
Cambiamos a la siguiente solapa: "Analysis". Click sobre "Processor specific analysis options" y habilitamos la opción: "Disable pointer referencing", le damos "OK". Click en "Reanalyze program" y le damos "OK".
Vamos a "Options" -> "Setup data types…" y deshabilitamos "1 byte" y "2 word" (solo queda activado "3 double word") le damos "OK".
Bien, ahora colocamos el cursor sobre la primer dirección, en este caso será 44140000. Toda la columna de direcciones coincidentes se resaltará en amarillo. Presionamos ALT+G, se abre el cuadro “Segment register value”. Dejamos seleccionado “t” y en value reemplazamos “ROM” por “1” y le damos “OK”. Veremos que el valor “CODE 32” cambia a “CODE 16”. Esto lo hacemos para que el IDA interprete las instrucciones leyendo solo 2 pares de Bytes (16-bit). Varias zonas del Firm se deben leer en 32 bit pero generalmente el IDA cambiará automáticamente para interpretarlo correctamente, de lo contrario lo podemos hacer manualmente regresando el “Value” a “ROM”.
Ahora vamos a "File" -> "Save" y luego "File" -> "Close". En el cuadro que nos aparece le damos "Don't pack database" y "Don't save database", luego aceptamos.
Veremos que se ha generado un archivo .idb , podremos cargar esta database cuando queramos haciendo doble click sobre este archivo.
Repetimos todo el mismo proceso con el Raw del Firm de destino.
* Direcciones base para algunos modelos:- 44000000 para K300/K500/K700
- 44020000 para K750/W700/W800/Z520
- 440A0000 para W550/W600
- 44140000 para K310/K510/W300/W710/W810/Z530/Z550
FASE 1: DESEMSAMBLE
Abrimos la idb (database) del firm de origen (R6CA009) y vamos a "File" -> "IDC file..." abrimos el archivo "ApplyPatch.idc".
Inmediatamente se abre otra ventana, en la que seleccionamos el parche a aplicar. Nos pide confirmación, le damos "Yes".
En IDA, el campo de abajo nos indica todas las operaciones realizadas, podemos observar los reemplazos realizados al aplicar el parche.
Para dirigirnos a una dirección especifica presionamos “G” y colocamos en “Jump address”: 454E416A, que es donde se realizó el primer cambio. Para analizar el código presionamos “C”, puede suceder que obtengamos un error: “Command MarkCode failed” en tal caso bajamos una línea y presionamos “C” de nuevo, lo hacemos un par de veces hasta que en un momento “engancha” el código y lo analiza.
Observen que en la zona inferior izquierda de la barra de estado hay un espacio denominado “Analysis State” que nos indica que el IDA esta trabajando, esperemos hasta que se detenga para proseguir. Volvemos a presionar “G” y hacemos lo mismo en el resto de las direcciones modificadas. Hasta que todo el código del parche este analizado.
* El código sin analizar se indica en color mostaza, el ya analizado en rojo o en negro.

Bien, observemos con atención el parche
:
Código:
;Z550 SW-R6CA009
;?????????? ??????/????? ??? ???????????? ?????????
;Player/radio off when handsfree is disconnected
;(c) IronMaster
+44140000
13a416a: 00210348 6EF191F9
1512490: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 00210948FFB506488CF616F9002804D1
15124a0: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 04488CF611F9002801D0B1F7E9FFFFBD
15124b0: FFFFFFFFFFFFFFFFFFFFFFFF E1FD3D45AD125A4516E90000
Primero hay un cambio en el firm original (rojo) y luego hay una sección de código nuevo (azul) que se incorpora desde el offset 1512490 (dirección: 45652490) hasta 15124BB (456524BB).
Vamos a hacer un asm de esta sección. Para ello posicionamos el cursor sobre ROM: 45652490 y seleccionamos “Edit” -> “Begin selection” (o tambien podemos presionar ALT+L). Descendemos hasta marcar todo el código del parche. Vamos a “File” -> “Produce file” -> “Create ASM file”. Y le ponemos un nombre sencillo como “radio.asm”. Se creará el asm en la carpeta donde se encontraba el parche vkp.
Abrimos nuestro asm con el block de notas y encontramos esto:
Código:
;
; +-------------------------------------------------------------------------------------------------------+
; | This file is generated by The Interactive Disassembler (IDA) |
; | Copyright (c) 2007 by DataRescue sa/nv,<ida@datarescue.com> |
; | Licensed to: GVU, Gerhard Uphoff, 1 user, adv, 10/2007 |
; +-------------------------------------------------------------------------------------------------------+
;
; =============== S U B R O U T I N E =======================================
sub_45652490 ; CODE XREF: ROM:454E416Ap
MOV R1, #0
LDR R0, dword_456524B8
PUSH {R0-R7,LR}
LDR R0, off_456524B0
____________BL sub_454DE6C8
CMP R0, #0
____________BNE loc_456524AA
LDR R0, off_456524B4
____________BL sub_454DE6C8
CMP R0, #0
BEQ loc_456524AE
loc_456524AA ; CODE XREF: sub_45652490+Ej
______________BL sub_45604480
loc_456524AE ; CODE XREF: sub_45652490+18j
POP {R0-R7,PC}
; End of function sub_45652490
; ---------------------------------------------------------------------------
off_456524B0 DCD unk_453DFDE1 ; DATA XREF: sub_45652490+6r
off_456524B4 DCD unk_455A12AD ; DATA XREF: sub_45652490+10r
dword_456524B8 DCD 0xE916 ; DATA XREF: sub_45652490+2r
Tenemos que adecuar este asm para que pueda ser procesado por el Fasarm, para ello vamos a hacer lo siguiente:
En el Block de Notas, “Edición” -> “Reemplazar” (atajo: CTRL+R), colocamos buscar: “ADR” y reemplazar por “adr”, Reemplazamos todo.
* (En este caso esa instrucción no esta presente, pero de estarlo hay que reemplazarla).
De nuevo buscamos “#” y lo reemplazamos por “” (nada), así eliminamos todos los signos “#”.
Sacamos todas las lineas comentadas (precedidas por ”;”). Colocamos “ : ” después de cada loc_XXXXXXXX o sub_XXXXXXX que presede cada grupo de instrucciones. Agregamos include "x.inc" al comiezo del parche. Nos queda así:
Código:
include "x.inc"
sub_45652490:
MOV R1, 0
LDR R0, dword_456524B8
PUSH {R0-R7,LR}
LDR R0, off_456524B0
______________BL sub_454DE6C8
CMP R0, 0
______________BNE loc_456524AA
LDR R0, off_456524B4
______________BL sub_454DE6C8
CMP R0, 0
BEQ loc_456524AE
loc_456524AA:
BL sub_45604480
loc_456524AE:
POP {R0-R7,PC}
off_456524B0 DCD unk_453DFDE1
off_456524B4 DCD unk_455A12AD
dword_456524B8 DCD 0xE916
Ahora observemos detenidamente el asm
. Algunos de los elementos de las instrucciones están definidos al final del parche (en rojo), además sabemos que el parche va desde 45652490 a 456524BB, pero algunas direcciones (en azul) están fuera de ese rango. Vamos a definir estas direcciones como nuevos elementos al comienzo del parche de esta manera:
Código:
nombre equ 0xDIRECCION
y reemplazamos la dirección de las instrucciones (incluido el “Sub_”, “Loc_” o “off_”) por el nombre.
Además agregamos la instrucción “org” que define desde donde empezara a escribirse el parche. En este caso será 45652490. Por ultimo le aclaramos al Fasarm que los DCD deben leerse de a 4 bytes por eso le anteponemos “Align 4”. Nos debe quedar así:
Código:
include "x.inc"
patch equ 0x45652490
dir1 equ 0x454DE6C8
dir2 equ 0x45604480
dir3 equ 0x453DFDE1
dir4 equ 0x455A12AD
org patch
sub_45652490:
MOV R1, 0
LDR R0, dword_456524B8
PUSH {R0-R7,LR}
LDR R0, off_456524B0
______________BL dir1
CMP R0, 0
BNE loc_456524AA
______________LDR R0, off_456524B4
BL dir1
CMP R0, 0
BEQ loc_456524AE
loc_456524AA:
BL dir2
loc_456524AE:
POP {R0-R7,PC}
Align 4
off_456524B0 DCD dir3
off_456524B4 DCD dir4
dword_456524B8 DCD 0xE916
Debemos armar otros asm con las demás secciones del parche, en este caso es muy sencillo (una sola línea) así que vamos a agregarlo manualmente al asm anterior con lo que tenemos en el IDA:

Observen que es solo un BL que esta ubicado en 454E416A, ubicacion que voy a llamar patch1. Este BL esta llamando a la subroutine del codigo nuevo, que anteriormente llamamos patch, ahora lo voy a llamar “patch2”, :
Código:
include "x.inc"
patch1 equ 0x454E416A
patch2 equ 0x45652490
dir1 equ 0x454DE6C8
dir2 equ 0x45604480
dir3 equ 0x453DFDE1
dir4 equ 0x455A12AD
org patch1
loc_454E416A:
BL patch2
org patch2
sub_45652490:
MOV R1, 0
LDR R0, dword_456524B8
PUSH {R0-R7,LR}
LDR R0, off_456524B0
______________BL dir1
CMP R0, 0
BNE loc_456524AA
______________LDR R0, off_456524B4
BL dir1
CMP R0, 0
BEQ loc_456524AE
loc_456524AA:
BL dir2
loc_456524AE:
POP {R0-R7,PC}
Align 4
off_456524B0 DCD dir3
off_456524B4 DCD dir4
dword_456524B8 DCD 0xE916
¡Listo!, terminamos el asm.
!45! Es una buena idea reensamblar este asm con el firm original, para comprobar si el vkp generado por el Fasarm coincide con el parche original. (Ver FASE3: REENSAMBLE más adelante).
FASE 2: PORTANDO AL OTRO FIRM
Quitemos el parche que habiamos aplicado ejecutando el IDC “UndoPatch.idc” de la misma forma que el anterior idc seleccionando el parche a quitar, o sea el mismo que aplicamos al comienzo.
Abrimos el Smelter. “Flash” -> “Abrir”, tipo:”Todos los archivos” y seleccionamos el Raw del firm de destino (R6GA004). . “Flash” -> “Cargando base” -> “Enter the Address” y ponemos “44140000” (o la base que corresponda a tu modelo).
En la parte de arriba hay una fila de botones con letras: E, L, M, P… Presionamos la “B” que abre el cuadro “Search bytes” para buscar en el firm.
Vamos a portar todas las direcciones que definimos al principio del asm (las precedidas por “equ”), buscando su equivalente en el nuevo firm.
Nos dirigimos a 454E416A donde se alojaba el “patch1”. Analizamos el código presionando “C” :

Observen que hay un BL en 454E4170, que llama una subroutine en 454F21EC, el valor de estas instrucciones (Branch) depende tanto del origen como del destino. A diferencia de los DCD en que solo dependerán del destino. Mas alla de eso es evidente que tanto origen como destino puede que no se encuentran en las mismas direcciones en ambos firms, por lo tanto estos 4 bytes pueden ser distintos. Para que el Smelter tenga esto en cuenta, utilizamos comodines (“?”) que pueden adoptar cualquier valor. Buscamos el siguiente patrón:
Código:
002103482570????????0be0
¡Genial! encontramos 1 sola coincidencia.
*En esta pantalla del Smelter podemos copiar los datos de la fila selecionada directamente al portapaeles con las teclas F1 a F5.

Abrimos la database (idb) del firm R6GA004 y vamos a la direccion que nos indica el Smelter (454EADDA). Analizamos el código y lo comparamos con el del firm R6CA009. Nos aseguramos que las instrucciones y su entorno son similares. También podemos comparar los destinos del las llamadas a otras partes del firm simplemente posicionando el cursor sobre las instrucciones, como se ve en la siguiente imagen:

Hacemos lo mismo con el resto de las direcciones.
!20!Esta claro que no vamos a encontrar la dirección de “patch2” pues es un código nuevo, ajeno al firm original.
Podemos ubicarlo en cualquier espacio libre disponible en el firm, pero considero que es una buena práctica respetar la posición relativa al último byte de cada firm.
El último de R6CA009 es 45651F84 (offset: 1511F84) y el de R6GA004 es 45664F24 (offset: 1524F24) lo que nos da una diferencia de +12FA0. Asi que sumamos este valor al “patch2” y obtenemos: 45665530.
*En algunos casos van a tener que usar patrones mas amplios para encontrar una coincidencia, y en otros casos inevitablemente tendrán mas de una. Miren atentamente el contexto, y utilicen la que consideren mas apropiada.
Reemplacemos todas estas nuevas direcciones en el asm, queda así:
Código:
include "x.inc"
patch1 equ 0x454EADDA ;454E416A
patch2 equ 0x45665530 ;45652490
dir1 equ 0x454E5344 ;454DE6C8
dir2 equ 0x456172F8 ;45604480
dir3 equ 0x453E6259 ;453DFDE1
dir4 equ 0x455B3E0D ;455A12AD
org patch1
loc_454E416A:
BL patch2
org patch2
sub_45652490:
MOV R1, 0
LDR R0, dword_456524B8
PUSH {R0-R7,LR}
LDR R0, off_456524B0
BL dir1
CMP R0, 0
BNE loc_456524AA
LDR R0, off_456524B4
______________BL dir1
CMP R0, 0
BEQ loc_456524AE
loc_456524AA:
BL dir2
loc_456524AE:
POP {R0-R7,PC}
Align 4
off_456524B0 DCD dir3
off_456524B4 DCD dir4
dword_456524B8 DCD 0xE916
!59!Ahora esta listo para reensamblar.
FASE 3: REENSAMBLE
Copiamos el asm terminado (que llamamos “radio.asm”) a la carpeta armpc. Donde también deberá encontrarse el raw del firm a portar (que llamaremos “r6ga004.raw”).
En la barra de tareas de Windows vamos a “Inicio” -> “Ejecutar”, escribimos “cmd” y aceptamos. Se abre la consola de DOS. Tipeamos:
“cd\” (Va al directorio raiz), le damos enter
“cd armpc” (entra a armpc), le damos enter
“make radio.asm r6ga004.raw 44140000” y le damos enter.
Aparece un mensaje de error que nos dice que no se encuentra el archivo radio.vkp porque deberiamos crear primero el vkp vacio donde escribirá el Fasarm, no le den importancia, el Fasarm creará el archivo de todos modos y lo podremos encontrar en la carpeta armpc. Abrimos el archivo vkp con el block de notas y le colocamos los comentarios y los créditos del port.
!45!Es una buena idea tener guardada una database del firm de destino a la que hayamos aplicado previamente todos los parches anteriores. Así podemos probar el parche y corroborar que no haya conflictos con otros parches.
!57! TERMINAMOS !!!
Espero que este tutorial les haya resultado útil y ahora puedan ser capaces de portar exitosamente la mayoría de los parches de complejidad media.
ANEXO: ERRORES FRECUNTES DEL FASARM !6!
Error: source file not found.
Causa: No se encuentra alguno de los archivos necesarios para crear el parche.
Solución: Verifica haber escrito correctamente los nombres de asm y el raw. Es recomendable ponerles nombres sencillos a estos archivos.
Error: undefined symbol.
Causa: Uno de los elementos del parche no esta definido.
Solución: Cerciorarse de que se hayan definido como “equ 0x…” todas las direcciones que se encuentran fuera del segmento del parche.
Error: illegal instruction.
Causa: La instrucción no es reconocida por el Fasarm.
Solución: Verificar que las instrucciones estén escritas de manera valida. Como es el caso de “adr” en vez de “ADR”.
Error: relative jump out of range
Causa: Las instrucciones BL tiene un cierto alcance (400000) y la dirección de destino se haya en una posición relativa fuera del mismo.
Solución: Supongamos que tenemos un BL que debería enviar de 4566530C a 4525A8B0, seria algo asi:
Código:
destino equ 0x4525A8B0
...
loc_4566530C:
BL destino
…(resto del asm, que termina en 456653EE)…
Pero la diferencia es 40AA5C (esta fuera de alcance). Entonces, agregamos al final del parche una sub con LDR dirigido a un DCD que enviará, a su vez, a la dirección destino. Llamamos al esta nueva sub desde el BL que nos ocasionaba el error. Queda algo así:
Código:
destino equ 0x4525A8AF
...
loc_4566530C:
BL sub_456653EF
…(resto del asm, que termina en 456653EE)…
sub_456653EF:
_____________LDR R3, dword_456653F3
BX R3
align 4
dword_456653F3 DCD destino+1
Error: relative jump destination not aligned
Causa: 
Solución: 
Error: Instruction origin not aligned
Causa: 
Solución: 
Este tutorial estará sujeto a futuras ediciones. Si tienes alguna sugerencia o crees que debería ser necesaria alguna corrección, comunícamelo, con gusto modificaré el tutorial para mejorarlo.
Marcadores