SET 39 Call For Papers

¿Eres un hacker? Si deseas pasar a formar parte de la historia del hacking hispano, colabora con la próxima edición de SET 39 enviándonos un artículo. No esperes más, esta es tu oportunidad de demostrar lo que sabes. Ayúdanos a construir una revista de hackers para hackers. SET Staff

SET 33

92477 visitas

IDA para neofitos

      11438

Autor: FCA00000
-[ 0x0D ]--------------------------------------------------------------------
-[ IDA para neofitos ]-------------------------------------------------------
-[ by FCA00000 ]-----------------------------------------------------SET-33--

IDA_info

En este articulo se cuenta informacion relevante al desensamblador
IDA = The Interactive Disassembler, y modos de mejorarlo.
Si has leido alguno de los textos escritos por mi, habras encontrado que
continuamente hago referencia a este desensamblador.
Tras muchas horas pasadas con este programa, creo que seria util compartir
con vosotros lo que yo he aprendido.

En la primera parte explico como hacerlo funcionar. Luego comento algunos
trucos que a mi me resultan utiles, y al final cuento varias maneras de
mejorarlo, completando la funcionalidad que se echa de menos.

----------------
Yo lo uso porque es el mejor para desensamblar programas de ARM, usado en
moviles Symbian. Tambien es capaz de desensamblar codigo de otros
procesadores, tales como Z80, 80x86, NET, Playstation, XBox, e incluso
Java y programas de Linux y Windows CE.

La ultima version que yo conozco es IDA Pro Advanced 5.0
Es una lastima que este disponible en tantos sitios de warez: eso solo hace
que los autores (www.Datarescue.com) pierdan interes en seguir desarrollando
su producto. Como siempre digo: si usas una aplicacion, comprala.

Recuerda que algunas leyes prohiben el desensamblado de programas ajenos.
En general se admite que desensambles programas hechos por ti.
Por tanto, desensamblar un virus que te ha infectado es ilegal :-%

----------------
Este parrafo explica por encima como manejarse con IDA. Obviamente la
mejor manera de adquirir practica es experimentando, asi que no te
extranye si vamos un poco rapido al principio.

Tras iniciar el programa lo primero que se hace es abrir el programa que
quieres desensamblar.
Si es capaz de identificar el procesador para el que esta escrito el
programa, lo sugiere. Si no, solicita el tipo de procesador.
La mayoria de las aplicaciones que yo he destripado han sido identificadas
correctamente. He tenido dificultades con los programas del ZX-Spectrum,
porque no entiende el formato, pero eso es normal.
Tambien da problemas con los programas extraidos de la memoria de los
moviles Symbian, pues la cabecera es incorrecta, y se lia al encontrar el
punto de entrada.

Este problema es facilmente solucionable eligiendo el tipo de fichero
como Binary en lugar de EPOC.
Esto me permite escribir el punto de entrada, y la direccion de carga, que
para Symbian resulta ser 0x64 bytes menos de lo que indica el programa a
desensamblar. Para los programas del Spectrum, hay que mirar el formato en
el que se guardan. El particular el formato SNA contiene una cabecera que
ocupa 48 bytes, seguido por el volcado de la memoria a partir de la
direccion 0x4000.

Entonces empieza automaticamente a desensamblar el programa, y a continuacion
presenta el listado; bien en modo de arbol de rutinas, bien en modo texto.
 
Lo importante de un desensamblado es poder seguir el flujo de informacion.
Si una rutina llama a otra, puedes hacer doble-click para verla.
Pulsando "escape" vuelves a la inicial.
Seleccionando una rutina, o una etiqueta, puedes pulsar "X" para ver desde
donde se llama; posiblemente desde varios sitios.
El menu View-OpenSubviews->FunctionCalls habilita una ventana flotante para
hacer mas facil esta tarea. Asi sabes de donde vienes, a donde vas, y
porque tan rapido.

Puedes abrir una ventana nueva (Alt+Enter) para investigar 2 rutinas a la vez.

Con las teclas F12 y CTRL+F12 puedes ver el flujo completo de las rutinas,
presentado en la aplicacion WinGraph (licencia GPL).
Eso si, el grafico completo de todas las rutinas puede que sea bestialmente
grande.
Mas eficiente es colocar el cursor en una rutina determinada y usar el boton
derecho para sacar el grafico parcial de "Chart of xrefs to".

IDA permite escribir comentarios en el codigo pulsando ";".
Para renombrar las subrutinas y constantes hay que marcarlas con el cursor y
pulsar "N".
Si quieres ver un dato en otra base numerica (Hex/Dec/Oct/Bin/ASCII) solo
hay que marcarla y pulsar el boton derecho del raton.

Una parte fundamental del desensamblado es saber la representacion real de 
los datos. Para ello puedes abrir la vista HexDump para ver en hexadecimal 
los codigos de las instrucciones.
Posiblemente tambien quieras usar BotonDerecho->SynchronizeWith->IDA View-A
para ver exactamente los datos de la instruccion que estas analizando.
Es una lastima que no permita modificar los datos en vivo, pero cualquier 
editor hexadecimal te sirve para esto.

Normalmente los programas llaman a otras rutinas del sistema operativo.
IDA sabe cuales son estas rutinas y sus parametros.
Un ejemplo de desensamblado de un programa en Windows tiene las instrucciones
.text:000129FB    push    offset SourceString ; SourceString
.text:00012A00    push    [ebp+DestinationString] ; DestinationString
.text:00012A03    mov     [ecx], eax
.text:00012A05    call    ds:RtlInitUnicodeString

y luego
.rdata:00013018 ; void __stdcall RtlInitUnicodeString(PUNICODE_STRING
																			 DestinationString,PCWSTR SourceString)
.rdata:00013018 RtlInitUnicodeString dd ?    ; DATA XREF: sub_129A05

O sea, que sabe que  00012A05  llama a  RtlInitUnicodeString  y que los 
argumentos se definen en  000129FB y 00012A00

No solo esto, sino que es capaz de decir las librerias importadas por un 
programa. Puede extaer informacion de modulos compilados con informacion de 
debug, usados comunmente en Windows y Linux.

Tambien entiende constantes alfanumericas en varias implementaciones.
Una palabra, por ejemplo "Ayax" se puede representar con los bytes:
41 79 61 78 00 -> un byte por letra y el terminador 00 , tipico de lenguaje C
41 79 61 78 24 -> un byte por letra y el terminador 00 , usado en MS-DOS
41 00 79 00 61 00 78 00 00 00  -> dos bytes por letra y el terminador
																	doble-00 , tipico de unicode
04 00 00 00 41 00 79 00 61 00 78 00 00 00  -> cuatro bytes indicando la
																longitud, seguidos por dos bytes por letra
														y el terminador doble-00 , tipico de unicode de 
														Symbian, llamado Unicode-Width-Pascal-4
Hay otros mas pero estos son los que IDA reconoce sin muchos problemas.
Bueno, el ultimo formato si da problemas, pero los veremos despues.

Para buscar un texto, instruccion, constante o cualquier otra cosa, usas las 
teclas Alt-T y lo escribes en el cuadro de dialogo. Para buscar datos en la 
ventana de representacion hexadecimal usas Alt-B

Otra opcion bastante potente es exportar los datos desensamblados. En el 
menu Options->General->Analysis->TargetAssembler puedes elegir un ensamblador
. Luego en el menu File->ProduceFile->Create_ASM_File puedes extraer el 
listado, y ensamblarlo de nuevo.
En Symbian hay que hacerle algunos ajustes, pero acaba funcionando igual
que el original. Todo depende del tiempo que quieras dedicarle.

Otra manera de extraer datos es usando el menu
ProduceFile-Dump_database_to_IDC_file
El archivo generado contendra la informacion relevante para IDA: inicio de 
las rutinas, nombres dados a las variables, comentarios, referencias, 
constantes, puntos de entrada, segmentos, ...
Esto tiene un gran utilidad para hacer que IDA haga cosas que no estaban 
consideradas por los creadores de la herramienta, y sera usado en el tercer 
apartado de este articulo.

Otras ventanas utiles son las que muestran en una lista todas las funciones 
importadas y exportadas, o internas. Similarmente se puede ver el listado de 
todas las cadenas de texto: Shift-F12 . No te olvides de pulsar la etiqueta
"String" para ordenarlas.

Yo suelo abrir la ventana de desensamblado, el FunctionCalls, y el volcado 
Hexadecimal. A veces abro 2 desensamblados. Con esto, me apanyo, aunque un 
monitor de 20 pulgadas no me vendria mal.

Es bastante util el menu Jump-MarkPosition (Alt-M) para marcar una posicion.
Luego se puede volver a ella usando Ctrl-M . Obviamente lo mejor es que se 
pueden marcar varias posiciones y darles nombre que sean intuitivos.
Como no todo podia ser perfecto, esta informacion no se guarda en el IDC .

Bueno; hasta aqui es un minimo manual de uso.

---------------
Ahora comentare algunos trucos que yo encuentro utiles. Estan motivados por 
el uso que yo le doy a esta herramienta, habitualmente desensamblando 
programas para Symbian.

Lo primero es que el desensamblado automatico empieza por la rutina de 
inicio, y desensambla en forma de arbol: si A llama a B, entonces B tambien 
sera desensamblada. Esto se llama desensamblado de flujo lineal.
Pero si alguna rutina no esta llamada desde otra, quizas no la desensambla.
IDA tiene una metodologia de desensamblado llamada "Recursive traversal"
en la que intenta everiguar si un trozo de bytes es codigo o datos.
Pero como todo artifacto fabricado por humanos, a veces falla.

Este problema no se percibe normalemente al desensamblar un programa, pero 
si en las librerias.
La solucion es marcar la primera linea del programa (Alt-L), hacer scroll 
hasta la ultima (Ctrl-PageDown), y pulsar "c" para convertirlo en codigo.
Lo mismo sirve para convertirlo en una cadena de caracteres, si notamos que 
en realidad son caracteres imprimibles.

El segundo se refiere a la busqueda. Normalmente pulsas Alt-T para decir el 
texto que quieres buscar, y luego Ctrl-T sigue la busqueda.
Pero es mucho mas eficiente poner el cursor en la palabra a buscar, y 
pulsar Alt-FlechaAbajo, o Alt-FlechaArriba . Por supuesto esto sirve para 
cualquier palabra: datos, nombres de rutinas, o incluso instrucciones.
Por poner un ejemplo, suponer que estas analizando una rutina que usa el 
registro R8, y quieres ver donde se ha inicializado. Asi que pones el cursor
en la palabra "R8" y Alt-FlechaArriba te lleva a la instruccion anterior 
que usa tal registro. No va a resolver el hambre en el mundo, pero acelera 
el trabajo de analisis.


Otro truco tiene que ver con las constantes. Es posible asignarles nombres, 
o elegir de los nombres estandar de Windows, que quizas esten definidos en 
otro sitio.  (Nota: ?Porque solo funcionara en Windows, y no en Symbian?)
Supongamos este codigo en windows:
.text:0001290F  call    ds:KfReleaseSpinLock
.text:00012915  mov     eax, 0C000009Ah

Ahora bien: ?que es el valor 0x0C000009Ah? Desde luego no parece elegido al 
azar.
Asi que pongo el cursor sobre este valor, pulso el boton derecho, y digo 
"Use standard symbolic constants".
Me sugiere utilizar el simbolo STATUS_INSUFFICIENT_RESOURCES , lo cual es 
consistente con la funcion KfReleaseSpinLock

Esto desde luego ayuda a saber lo que esta haciendo el programa.

Claro que a veces hay que romperse un poco la cabeza: el valor 0x39h en 
windows tiene estos posibles significados:
ATM_CAUSE_BEARER_CAPABILITY_UNAUTHORIZED
CR_INVALID_CONFLICT_LIST
DPFLTR_IDEP_ID
FILE_DEVICE_KSEC
LANG_HINDI
....
y por supuesto, mirando el codigo alrededor:
00012BC8     mov     di, [ecx]
00012BCB     cmp     di, 30h
00012BCF     jb      short loc_12BD7
00012BD1     cmp     di, 39h
00012BD5     jbe     short loc_12BDE

nos da la pista de que se compara si el valor de  di  esta entre "0" y "9", 
es decir, verifica que es numerico.
O sea, que no es ninguna de estas constantes, sino simplemente el valor "9".

Si hubieramos elegido LANG_HINDI , al hacer doble-click el propio IDA abre 
la ventana de Enumeraciones de tipo MACRO_LANG que nos indica que otros 
posibles valores son:
LANG_AFRIKAANS   = 36h
LANG_GEORGIAN    = 37h
LANG_FAEROESE    = 38h
LANG_HINDI       = 39h
LANG_MALAY       = 3Eh
.....

y esto tambien ayuda a la hora de cambiar una variable por otra. Supongamos 
que en otro programa se chequea que el lenguaje de instalacion es LANG_HINDI,
pero nuestro ordenador esta instalado en lenguaje LANG_MALAY . Entonces hay 
que cambiar la comparacion
cmp     di, 39h
por
cmp     di, 3Eh

pero vamos, dudo que existan protecciones de este tipo.


A lo que iba, que en seguida me despisto. 
A veces la variable no esta conocida en ninguna de las librerias por defecto.
Bueno, en esta ventana "Enums" es posible definir nuevos simbolos y usarlos 
en cualquiera de las posteriores sesiones de desensamblado.

-------------------
Otro truco: habras notado que si seleccionas una palabra, se marca en color 
amarillo. Esto permite identificar rapidamente en pantalla todas las 
ocurrencias de dicha palabra. Pero si pinchas en cualquier otro punto, 
pierdes la seleccion. Para evitar esto puedes usar el icono
"Lock the current highlight".

Junto a este icono hay otro con muchos colorines que muestra un mapa del 
programa. En color Azul oscuro corresponde al codigo desensamblado, en rosa 
las funciones importadas, en gris los datos, burdeos para el codigo que no 
tiene sentido, marron para las areas vacias, y azul claro para las funciones
de librerias.
Pues bien, es posible adecuar este area para que muestre otros tipos de 
informaciones. Para ello se usa el dropdown llamado "Aditional display". 
Por ejemplo, seleccionando "Marked positions" nos muestra un punto rojo en 
el sitio donde hayamos puesto marcas.
Esto sirve para tener una vision de zonas de programa. Lastima que desde 
esta ventana no se puede saltar a la direccion donde esta el codigo.

Cuando desensamblas un programa es bastante frecuente tener que mirar a la 
vez en 4 sitios, asi que una navegacion eficiente es fundamental.

Ah, cuando buscas algo a lo largo del programa, esta ventanita muestra un 
cursor que indica donde esta buscando. Asi sabes el porcentaje que lleva 
analizado.

Otros de los puntos fuertes de IDA es que incluye un debugger. No lo he 
usado apenas asi que no voy a comentar nada. Mi esperanza era que fuese 
capaz de simular procesadores ARM, pero solo funciona para Windows y Linux,
los cuales, como digo, no he investigado en profundidad.

El mejor truco que puedo recomendar es usar un monitor grande. O dos. No se 
como lo hago, pero nunca tengo suficiente espacio para trabajar comodamente.

Estos consejos ayudan a manejarse con el programa, pero la verdadera 
potencia es que deja varias puertas abiertas para complementar la tarea.

-------------------
Para comprender un programa, un debugger casi nunca es suficiente por si 
mismo. A menudo hay que realizar tareas especificas que los disenyadores 
de IDA no habian previsto.

Por ejemplo, suponer que quiero buscar todas aquellas variables que se 
inician con un valor entre 0x30 y 0x39 .
La unica manera es usar la opcion "Buscar" para localizar  0x3  (notar que 
me he dejado el ultimo digito) y anotar uno por uno los datos. Pero esto 
tambien encuentra datos tales como 0x3F , 0x399999 , ...

Gracias a que puedo extraer la informacion en un fichero ASM, puedo hacer un 
mini-programa en Perl (o usando  grep , o AWK) para buscar esas ocurrencias:
grep "0x3?" salida.asm


Supongamos una tarea ligeramente mas compleja: sacar aquellas rutinas que:
-comparan un valor con otro
-siguen 4 o menos instrucciones 
-saltan a otro sitio si el resultado no es cero

Un ejemplo seria:
01002E81   cmp     dword_1008828, ebx
01002E87   mov     eax, [ebp+wParam]
01002E8A   jnz     short loc_1002EF1

Esto se puede hacer tambien el Perl, algo asi:

-lee linea
-si es "cmp" entonces haz cnt=1
-si es "jnz" y cnt>0 entonces haz cnt=-1 , y muestra la direccion
-si cnt>0 entonces incrementa cnt
-si cnt>4 entonces cnt=-1

No es tan dificil, sobre todo haciendolo en Perl.


Otro caso: tomar una rutina, y ver desde donde es llamada, hasta 3 niveles 
de profundidad.
Para verlo mas claro suponer que la rutina se llama A. Entonces son validas:
- B, si llama a A
- C, si llama a B
- D, si llama a C

pero si E llama a D, entonces A esta mas alla de 3 niveles, y no vale.

Ahora las cosas se le complican a Perl, pues solo es capaz de leer lineas 
secuencialmente; no puede ir hacia atras, y mucho menos hacer arboles de 
llamadas.
Bueno, si que se puede hacer, pero yo no se como :-)

Lo que necesitamos es un sistema que pueda moverse por el codigo adelante y
hacia atras, siguiendo flujos de subrutinas y multiples caminos. ?Quien 
puede hacer esto? Pues el propio IDA.

Sus desarrolladores tuvieron la misma idea, y decidieron permitir que se 
pudiera re-programar. Para ello inventaron un lenguaje llamado  idc  que es 
muy parecido al lenguaje C .

Para saber las cosas que se pueden hacer es bueno abrir el fichero de ayuda,
y saltar al tema "Index of IDC functions". Presenta unas 400 funciones, pero
tranquilo, que la mitad no se usan. El resto contiene muchas que son 
parecidas entre si: ej, GetStrucNextOff es similar a  GetStrucPrevOff .

Las funciones tambien estan documentadas en el fichero   idc.idc , por si 
quieres imprimirlas todas.

Vamos con un ejemplo sencillo: strstr
La declaracion es:
long strstr(string str,string substr);  // find a substring, -1 = not found

O sea, que necesita un primer argumento con una frase, y un segundo 
argumento con la palabra a buscar.
Asi, este programa:


#include <idc.idc>
static main(void)
 {
 auto frase, palabra;
 frase = "Hay palabras dentro de esta frase.";
 palabra = "palabra";
 if( strstr(frase,palabra) >= 1)
	{ 
	Message("Encontrado!");
	}
 else
	{
	Message("No encontrado!");
	}
 return;
 }


Al cargarlo y ejecutarlo con F2 mostrara el mensaje "Encontrado!" en la 
ventana que esta en la parte inferior de IDA, llamada "Messages Window".
Si no ves esta area, amplia la barra inferior de la aplicacion.

Tambien se puede usar la funcion
Warning
para mostarlo en una ventana de dialogo.

Otro programilla; esta vez le solicito al usuario una direccion de programa, 
y le digo a IDA que desensamble 8 bytes a partir de ahi:

#include <idc.idc>
static main(void)
 {
 auto mi_dir;
 mi_dir=0x0;
 mi_dir=AskAddr(mi_dir,"Introduce una direccion");
 AnalyzeArea(mi_dir,mi_dir+8);
 return;
 }


Un poco mas amigable es que el usuario ponga el cursor en una direccion, y 
desensamble desde ahi.
Para ello se usa

long ScreenEA(); // the current screen ea (linear address of cursor)

de este modo:
mi_dir=ScreenEA(); // en vez de mi_dir=0x0;

Para el caso que he propuesto de las busquedas en 3 niveles, debo usar
long    RfirstB (long To);  // Get first code xref to "To"
que busca referencias hacia esta direccion

y sus hermana
long    RnextB  (long To,long current); // Get next code xref to "To"
que busca posteriores referencias.

Nota: existen variaciones de estas funciones que buscan referencias desde 
codigo/datos, adelante/atras, estandar/extendidas.

El programa queda asi:

#include <idc.idc>
static main(void)
 {
 auto mi_dir;
 AnalyzeArea(INF_MIN_EA,INF_MAX_EA); // primero hay que analizar el codigo 
														 // completo para que IDA marque las referencias
 mi_dir=ScreenEA();
 mi_dir=AskAddr(mi_dir,"Introduce una direccion");
 for ( x=RfirstB(ea); x != BADADDR; x=RnextB(ea,x) ) // por cada direccion
	{                                                 // que apunta a mi_dir ...
	Message("Nivel 1: " + atoa(x) + "\n");           // imprimela
	for ( y=RfirstB(x); y != BADADDR; y=RnextB(ea,y) ) // y busca aquellas que
	 {                                                //  la re-referencian
	 Message("Nivel 2: " + atoa(y) + "\n");     // imprime las de segundo nivel
	 for ( z=RfirstB(y); z != BADADDR; z=RnextB(ea,z) ) // y sigue buscando las
		{                                            //  que la re-re-referencian
		Message("Nivel 3: " + atoa(z) + "\n");
		}
	 }
 return;
 }

Esto saca un listado, que es posible mandar a un fichero usando la variable
set IDALOG=c:\refs3Nivel.txt

Mas elegante es mandarlo a un fichero nombrado como la direccion misma:
nombre_archivo = "c:\\" + "refs_" + atoa(mi_dir) + ".txt"

my_archivo = fopen(nombre_archivo, "w");
.....
dato_hacia_fichero = "Nivel 3: " + atoa(z) + "\n";
writestr(my_archivo, dato_hacia_fichero);
....
fclose(my_archivo);

Como ves, bastante parecido al lenguaje C . Esto simplifica la curva de
aprendizaje, suponiendo que ya sabes programar en C , claro.

-------------------
Antes he dicho que no es posible guardar las marcas que pones cuando estas 
trabajando en el programa. Bueno, es posible hacerlo en lenguaje idc :
#include <idc.idc>
static main(void)
{
 for (slot = 1; slot < 1023; slot = slot + 1)
	{
	pos = GetMarkedPos(slot);
	if (pos>=0)
	 {
	 Message("Marca " + slot + " en direccion " + ltoa(pos) +
					 " con nombre " + GetMarkComment(slot) + "\n");
	 }
	}
}


La mayoria de las cosas que se hacen a mano es posible tambien hacerlas
desde un programa.
Hemos visto antes que se le pueden dar nombre a las constantes.
?Quieres saber como se hace desde idc ? Muy facil; usando

success SetConstName(long const_id,string name);
// ** set a comment of a symbolic constant
//         arguments:      const_id - id of const
//                         cmt     - new comment for the constant
//                         repeatable - 0:set regular comment
//                                      1:set repeatable comment
//         returns:        1-ok,0-failed


Por ejemplo:
SetConstName(0xFCA00000, "El_autor" );
hara que todas las ocurrencias de 0xFCA00000 pasen a llamarse "El_autor" .

Unas funciones muy utiles son las que convierten uno o mas bytes en otro 
tipo de datos.
Por ejemplo, en Symbian es comun que los bytes
10 00 ?? ??
se refieran a un UID - identificador de aplicacion.
Obviamente IDA no es consciente de ello, pero podemos forzarle:

dir_base = BeginEA();
dir_data = Dword (dir_base + 4 * 0x12 ); // el valor en la
													 // direccion (base+4*0x12) dice donde empieza el 
													// segmento de datos
dir_end = MaxEA(); // final del fichero analizado
for (dir=dir_data; dir<dir_end; dir=dir+4 ) // recorre el programa
 {
 dato = Dword(dir); // considera 4 bytes como un double-word, en memoria
 if (dato>=0x10000000 && dato<=0x1000FFFF  ) // si es 1000???? , entonces...
	{
	MakeWord(dir); // convierte los 4 bytes en una Double-Word, en el listado
	MakeName( dir, "UID_" + ltoa(dir,16) ) ; // le da nombre "UID_1000????"
	}
 }


-------------------
Si no nos gustan los nombres de subrutinas que IDA ha generado se pueden 
cambiar con
MakeName (long ea,string name);  // assign a name to a location

Incluso a veces no me gustan los nombres de las instrucciones, asi que los 
renombro usando la funcion
SetManualInsn (long ea, string insn);

Este es un caso que yo necesito usar porque mi compilador no es capaz de 
entender la instruccion
STMFD   SP!, ...
sino que quiere que se llame
STMFD!  SP, ...

Por eso tengo una rutina que hace

for (my_dir=dir_base; my_dir<dir_end; my_dir=my_dir+4 )
 {
 ins=GetManualInsn(my_dir);
 if(strstr(ins,"STMFD   SP!")
	 {
	 ins_nueva="STMFD!  SP,"; // nueva instrucci;on
	 ins_nueva=ins_nueva+substr(ins,11,-1); // concatena los caracteres 
																				 // desde 11 hasta el final
	 SetManualInsn(my_dir,ins_nueva);
	 }
 }


Ah, y podemos generar el fichero ASM con todo el desensamblado:
GenerateFile( OFILE_ASM,
							fopen("salida.ASM","w"),
							dir_base,
							dir_end,
							GENFLG_MAPDMNG);

?Recordais que he dicho que no se puede modificar el programa binario 
cargado? Menti. Solo hay que usar la funcion
void    PatchByte       (long ea,long value);

Vamos con otro ejemplo: supongamos que quiero parchear un programa para que 
cambie unos bytes por otros.
Para ello me invento un formato:
replace:3B284ADD3C202060CDA800682D18-FF284ADD3C202060CDA800682D18
(en realidad no me lo he inventado: es el formato usado para parchear 
programas del Siemens-SX1. Notar que un fichero puede contener varias 
lineas con varios parches.)

La cadena inicial antes de ":" es lo que hay que buscar, y la cadena que 
sigue son los nuevos datos.
Cada 2 caracteres se combinan para generar un byte. Por ejemplo 3B significa 
el byte 0x3B .

Como veis, en este caso la cadena inicial y final solo se diferencian en el
primer byte. Los restantes son para comprobar que solo queremos cambiar 
esta occurencia: si encuentra
3B211111111111
entonces no lo cambiara.

Para aplicar este parche a un fichero cargado en IDA hago un programilla:

#include <idc.idc>
static main(void)
{
parchea();
}

static parchea()
{
auto patchFileName, patchFile, string;
patchFileName = AskFileEx(0,"*.sxp","Elige el archivo con el parche");
patchFile = fopen(patchFileName, "rb"); // abre el archivo con los parches
while(string != -1) // sigue mientras no llegue al final del fichero
 {
 cad_leida = readstr(patchFile);  // lee una cadena completa del fichero
 if (strstr(cad_leida,"replace:") ==0) // si include la palabra "replace:" ...
	{
	pos_destino = strstr( cad_leida, "-" ); // busca el separador
	cadena_original=substr( cad_leida, 8, pos_destino); // parte anterior al separador
	cadena_destino=substr( cad_leida, pos_destino,-8); // parte posterior al separador

	dir_base = BeginEA();                  // empieza desde el inicio

	encontrado=FindBinary(dir_base, SEARCH_NEXT, cadena_original); // busca
	while(encontrado != BADADDR) // si lo encuentra...
	 {
	 for (i=1; i<strlen(cadena_destino); i=i+2) // parte la cadena destino en trozo de 2 letras
		{
		nuevo_byte_ascii=substr(cadena_destino,i,i+1); // obtiene este trozo
		nuevo_byte_hex = xtol(nuevo_byte_ascii);   // lo convierte a Hex
		PatchByte(encontrado+i,nuevo_byte_hex);   // lo modifica en IDA
		}
	 }
	}
 }
}

Para ejecutar este script (y todos los demas) hay que ir al menu
File->IDC File
y cargarlo.

-------------------
Un poco mas comodo es usar una tecla de acceso rapido. El fichero ida.idc se 
ejecuta al iniciar la aplicacion, asi que podemos incluir

AddHotkey("Shift-P","parchea");

Y en cualquier momento puedo pulsar Shift-P para invocarlo.

Si te fastidia ir al menu "File->IDC File" puedes redefinir todas las 
teclas de acceso directo en el fichero idagui.cfg
La mayoria de los menus no tienen teclas asignadas, pero puedes hacerlo.
Por ejemplo, este menu de cargar ficheros IDC tiene en idagui.cfg la linea
"Execute" =  0  // Execute IDC file
que puedes cambiar a
"Execute" =  "Shift-F3"  // Execute IDC file

Eso si, ten cuidado de no asignar varias acciones a la misma tecla.
Y recuerda que puedes cambiarlas sobre la marcha en un script usando
AddHotkey .

Tambien puedes ejecutar un comando cualquiera con el menu Shift-F2 .
Esto es util si no quieres hacer un programa completo.

-------------------
A veces queremos parchear el fichero binario directamente en el disco.
Para ello se usan las funciones fgetc/fputc como en cualquir programa en
lenguaje C.

Si esto no es suficiente puedes usar la funcion Exec para ejecutar cualquier
otro programa. Uno de estos casos esta provocado por el hecho de que IDA no 
es capaz de recompilar codigo ensamblador para procesadores ARM.
Supongamos que tengo un programa original en ARM con una rutina que hace
MOV R0, #0x28
lo cual se escribe con los bytes
28 00 A0 E3

Pretendo cambiarlo por
MOV R0, #0x29
pero IDA no sabe como ensamblarlo. Por eso defino una combinacion de teclas 
SHift-K
que invoca a un script que hace:

nueva_instruccion=AskStr("","Nueva instruccion?"); // pide instruccion, ej. "MOV R0, #0x29"
my_archivo = fopen("instruccion.asm", "w");      // abre fichero de salida
writestr(my_archivo, nueva_instruccion);       // escribe el codigo assembler
fclose(my_archivo);
Exec("compilaARM.bat instruccion.asm");          // compila la instruccion 
																					 // con un compilador externo

my_archivo = fopen("instruccion.bin", "r");    // mira si se ha generado correctamente
if(my_archivo==0)                       // si no, se queja
	Message("Archivo no existe\n");
else                        // todo correcto
 {
 ea=ScreenEA();            // mira donde tiene que parchear
 for(i=0;i<4;i=i+1)        // cada instruccion ARM ocupa 4 bytes
	{
	fgetc(my_archivo);      // que extrae del fichero
	PatchByte(ea+i);        // y mete en la memoria de IDA
	}
 fclose(my_archivo);
 }



Otro ejemplo en el que uso la funcion Exec es cuando necesito hacer muchas 
cosas sobre el fichero desensamblado. Un caso tipico es un programa que 
llama a otra rutina externa, y quiero saber los registros que modifica.
Veamoslo ma claro:
Tengo una rutina que hace
MOV     R1, R5
BL      TTime::MicroSecondsFrom(TTime)

y quiero saber si TTime::MicroSecondsFrom(TTime) altera el registro R4 .
En tal caso debere guardarlo antes de llamarla si no quiero perder su valor.

Esta rutina esta en otra libreria Euser.dll , lo que me obligaria a cargarlo,
desensamblarlo con IDA, e investigar un poco.

En lugar de eso, hago un fichero IDC que
-invoca otra sesion de IDA, usando Exec
-carga Euser.dll, usando la opcion  input-file
-lo desensambla, si no lo esta previamente, usando AnalyzeArea
-salta a la rutina TTime::MicroSecondsFrom() , usando LocByName
-desde el principio hasta el fina de la rutina ...
-mira si aparece la palabra R4 , usando strstr
-en tal caso asume que se esta modificando.

una excepcion a esto es cuando la primera instruccion es del tipo
STMFD   SP!, {R4-R6,LR}
que indica que la propia rutina invocada se encarga de guardar los registros
que va a modificar.
Es facil de detectar: si la primera linea en assembler de la funcion
contiene la palabras "STM" y "R4" entonces se que se guarda.

Por supuesto, esto no es del todo correcto: podria suceder que
TTime::MicroSecondsFrom() llame a otra rutina
TInt64::operator_substract(TInt64 const &)
y que esta modificara R4.

Pero lo importante es que Exec permite automatizar este proceso.

---------------------
No incluyo el codigo de este programa  idc  porque es demasiado largo.
Si quieres ver muchos ejemplos de scripts, mira en el directorio
IDA\idc\*.idc
Yo tambien he encontrado algunos ejemplos en foros dedicados a reprogramacion
de moviles.
Y el sitio adecuado para preguntar es www.openrce.org , que tiene una bonita
coleccion de scripts. Mira tambien la seccion de links porque apunta a 
varios proyectos de open-source muy interesantes.

---------------------
En otro articulo comente que IDA es capaz de desensamblar programas de 
Symbian pero para algunas de las rutinas externas no sabe su nombre correcto.
Por ejemplo cree que la rutina
CPeriodic::Start
se llama
CListBoxData::Reserved_2



En aquel momento yo no sabia donde estaba esta definicion. Bueno, pues la 
he encontrado.
Con la version original de IDA (ojo, no con la version pirata que circula 
por ahi) se incluyen en el directorio idsutil3 un par de programillas muy 
simples.
El primero en el que centrare mi atencion es ZIPIDS.EXE para descomprimir 
los ficheros de tipo IDS :
ZIPIDS -u C:\Ida\ids\epoc6\arm\euser.ids
File: euser.ids  ... {1875 entries [0/0/0]}  unpacked

y genera

euser.idt
con este contenido:
;DECLARATION 
;ALIGNMENT 2

; Module Name and Description
0 Name=EUSER
;---------------------------------------
1 Name=memset
2 Name=memcpy
3 Name=newL__5CBaseUi
4 Name=ASin__4MathRdRCd
5 Name=ATan__4MathRdRCd
6 Name=ATan__4MathRdRCdT2
.....
302 Name=DaysInMonth__C5TTime
.....
1644 Name=__t13CArrayFixFlat1Zii
1645 Name=_._t13CArrayFixFlat1Z4TUid
1646 Name=__t13CArrayFixFlat1Z4TUidi
;------------------EOF------------------

Recordar que en Symbian (y tambien en las DLL de windows) cuando un progama 
quiere invocar a una rutina, no la llama por el nombre, sino por un indice 
relativo a la libreria.
Por ejemplo, si un programa quiere llamar a la funcion TTime::DaysInMonth
entonces incluye una referencia a EUSER y llama a la funcion 302
Para solucionar el problema cuando la misma rutina existe varias veces con 
el mismo nombre pero con distintos argumentos, es necesario incluir el tipo 
de variables. Por eso el nombre es "decorado" con indicadores y obtiene el 
nombre
DaysInMonth__C5TTime

Este proceso se llama "mangling".

Como digo, esta es la lista que esta dentro del fichero   euser.ids  que 
es el que IDA usa para nombrar las rutinas.

Pero el telefono (y el emulador) usa los de la libreria real  euser.lib
que puedo investigar con
AR2IDT.EXE C:\Symbian\6.1\Series60\Epoc32\Release\armi\urel\euser.lib
que produce
0 Name=EUSER
1 Name=memset
2 Name=memcpy
3 Name=newL__5CBaseUi
......
302 Name=DaysInMonth__C5TTime
.....
1644 Name=__t13CArrayFixFlat1Zii
1645 Name=_._t13CArrayFixFlat1Z4TUid
1646 Name=__t13CArrayFixFlat1Z4TUidi
1647 Name=__7RRegioniP5TRecti
1648 Name=ChunkHeap__8UserHeapR6RChunkii
......
1678 Name=Start__20CActiveSchedulerWait
1679 Name=_._20CActiveSchedulerWait

Por si no te has dado cuenta, en la referencia incluida por defecto en IDA 
existen solo 1646, pero en la libreria real existen las rutinas hasta 1679.
Esto quiere decir que si un programa usa alguna de esas 33 rutinas IDA no
es capaz de decir su nombre.

Para resolverlo se usa primero el programa
AR2IDT euser.dll
para producir  euser.idt
y luego
ZIPIDS euser.idt
para generar correctamente   euser.ids

De todos modos, las instrucciones estan en el fichero  readme.txt

Obviamente el fichero de texto  euser.idt  se puede alterar si no te gustan 
los nombres de las funciones. En particular yo uso los nombres "de-mangleados"
que obtengo de los ficheros del SDK.
Sin extenderme mucho: el programa
dumpbin /ALL cone.lib
produce
..........
	Symbol name  : DaysInMonth__C5TTime
	(public: static int TTime::DaysInMonth(void))
	Ordinal      : 302
................

Un simple script en Perl permite incluir el nombre real en  euser.ids  para 
hacerlo mas entendible.

Esto se puede usar en cualquier programa. Por ejemplo si quieres desensamblar
un programa en Linux; aunque IDA conoce los nombres de algunas librerias, hay
demasiadas como para que la incluya todas, por lo que es posible generarlas 
a medida que las necesites.

---------------
Hay una tecnica bastante usada en programas de Windows que hace mas dificil
la vida del "analista de programas". En vez de llamar a una rutina externa, 
la incluyen dentro del propio programa.
Este proceso se llama in-lining.

Por ejemplo la rutina   strlen()  es bastante simple. Para invocarla hay que
incluir su libreria, usar una referencia al indice, definir un punto de 
entrada, e invocar a esta rutina.
Se ahorra algo de tiempo (e incluso de espacio) si incluyes su codigo 
directamente en tu programa.
Probablemente se puede hacer en menos de 10 bytes.
Pero claro, el que desensambla el programa se encuentra con una rutina que 
complica (aunque solo ligeramente) la interpretacion del desensamblado.

IDA es capaz de encontrar tales rutinas. Para ello usa algo llamado 
firma (signature), que no es mas que los primeros bytes de la rutina original.
Veamos el fichero   flair/startup/pe_vc6.pat
que contiene las firmas generadas por el compilador VisualC 6.0 
Una de las lineas dice:

558BEC6AFF68.....  __except_handler

lo cual significa que la rutina  __except_handler comienza por estos bytes.
Cuando IDA encuentra estos bytes, sugiere renombrar la rutina encontrada 
como "__except_handler_XXX"

Para automatizar el proceso se usa
plb
que a partir de una libreria, genera un fichero de muestras PAT
con este, genera un fichero de firmas SIG

---------------
Un segundo uso es agrupar secuencias de bytes.
Suponer que te das cuenta de que a menudo aparecen las instrucciones
LDR R0, [R3]
ADD R0, #1
STR R0, [R3]

que en ARM se escribe como

00 00 93 E5
01 00 80 E2
00 00 83 E5

Esta instruccion es lo mismo que la pseudo-instruccion

INC [R3]

Asi que creas un PAT con la linea

000093E5010080E2000083E5.... INC [R3]

?ves por donde van los tiros? Se puede hacer el programa mas breve, con lo 
cual es mas facil de entender.
Esto es una tecnica usada en re-compiladores que generan codigo C a partir 
del listado en ensamblador.
Para ver un desarrollo de esta idea recomiendo el excelente programa
http://desquirr.sourceforge.net
que incluye una explicacion bastante detallada.

Por supuesto, el documento de obligada lectura es el decompilador DCC de 
Cristina Cifuentes y su tesis doctoral, en
http://www.it.uq.edu.au

En general esto de las muestras y las firmas es util cuando quieres sacarle 
mas partido a IDA y conoces el compilador usado para construir el
programa que pretendes desensamblar.

---------------
Otra de las incomodidades de programas desensamblados es el uso de 
sentencias "switch"/"case".
En lenguaje C es comun usar algo asi:
switch(origen)
 {
 case 0: destino=8; break;
 case 1: destino=88; break;
 case 2: destino=888; break;
 case 3: destino=8888; break;
 }

El compilador traduce este codigo en:
LDR  R0, [origen]    // lee el valor   origen
LDR  R1, =tabla     // crea una tabla de 4 posibilidades
MOV  R0, R0*4      // cada valor de la tabla contiene un puntero a
ADD  R0, R1       // una subrutina.
BX   [R0]        // lee puntero[origen] , y salta a donde le dicen
tabla:
 DCD rutina0    // puntero a la subrutina de "case 0"
 DCD rutina1
 DCD rutina2
 DCD rutina3

rutina0:    // autentica rutina que ejecuta "case 0"
 MOV R0, 8
 B break
rutina1:
 MOV R0, 88
 B break
rutina2:
 MOV R0, 888
 B break
rutina3:
 MOV R0, 8888
 B break

break:
 STR R0, [destino]

Visto de otro modo: hace
jmp rutina[origen*4]

Desde el punto de vista del compilador esto tiene perfecto sentido. Lo malo
es que IDA lo unico que ve es una tabla con valores, y cree que estamos
en un bloque de datos.
Si es capaz de interpretar correctamente el codigo rutina0, ... rutina3 ,
pero desconoce desde donde se referencian.
Le podemos ayudar haciendo un script que a partir de una direccion
busque si hay una tabla de saltos en las siguientes 8 instrucciones:

for (pos = inicio; pos < inicio+8*4; pos = pos + 4) // instruccion de 4 bytes
{
 ins=GetManualInsn(pos);
 if(strstr(ins,"DCD")) // hay un puntero?
	{                   // veamos si apunta a una rutina
										 // la instruccion es   DCD xxxxxx
	valor_apuntado = Dword(substr(ins,5,-1)); // extraer  xxxxxx
	if( val>pos && val<(pos+80))  // si salta a alguna rutina cercana ...
	 {
	 result=MakeCode(valor_apuntado); // miro si es un trozo de codigo
	 if(result>0)                    // si se ha podido convertir en codigo ...
		{
		AddCodeXref(pos,val,fl_F); // entonces marco la referencia
		MakeName( pos, "salto_a_" + ltoa(val,16) ) ; // y le doy un nombre bonito
		MakeComm ( pos, "salto " + ltoa(val,16) );   // y un comentario
		}
	 }
	}
}


Por otro lado tambien podria usar la tecnica de las firmas. El bloque

LDR  R0, [origen]
LDR  R1, =tabla
MOV  R0, R0*4
ADD  R0, R1
BX   [R0]

es sintoma de que hay una aceso indexado, y aparece siempre relacionado
con una tabla de saltos.
Asi que hago un script que en cada puntero a rutina, lo comenta con:
DCD rutinaX ; case X
que me sirve para saber cual valor saltara a esta rutina.


Bueno, esto ayuda a IDA a entender mejor el listado, pero quizas podria
facilitarme la tarea A MI.
Para que esto sea posible, debo recuperar la estructura "switch"/"case"
inicial. Durante este proceso puedo tengo que transformar el codigo
desensamblado en algo parecido a lenguaje C, pero lo malo es que luego
no podria ensamblarlo de nuevo con un ensamblador: necesitaria un
compilador. El asunto es lo suficientemente complejo para explicarlo
aqui, por lo que os emplazo a un proximo numero de SET.

---------------
Un tema que he investigado poco pero que promete mucho es el de los 
reconocedores de archivos.
En vez de investigar un programa a veces necesitas analizar los datos que 
ha producido.
Uno de los scripts incluidos en IDA sirve para desmenuzar ficheros de 
tipo AIF que contienen los recursos (iconos, strings, menus) que usa una 
aplicacion Symbian.
Cuando IDA reconoce que el fichero es de este tipo, procesa toda la 
estructura y la presenta de manera comprensible.
La manera de programar nuevos reconocedores es en lenguaje C leyendo byte 
por byte en fichero, y definiendo estructuras conteniendo esos bytes.
En general el tema depende del tipo de fichero y debo decir que a mi me 
resulta mas facil hacerme un programa en C sin usar IDA en absoluto.

Quizas en un proximo articulo, aunque me parece que es un tema que 
interesara a pocos de vosotros (asumiendo que lo que yo cuento interesa 
a alguien, que a veces lo dudo)

Otros temas demasiados avanzados para contar en esta introduccion son:
-modulos, para definir otros procesadores y las instrucciones que usan.
 Aunque IDA soporta 35 familias de procesadores, quien sabe lo que los 
 usuarios necesitaran en el futuro.
-plugins, para compilar funcionalidad que le falta a IDA, por ejemplo para 
 relacionarlo con un debugger o un emulador y analizar el codigo sobre la
 marcha.
-wingraph, que es la aplicacion usada para mostrar las referencias entre
 rutinas en forma de arbol. Tiene algunos defectos que me gustaria
 modificar, por ejemplo poder colapsar algunas ramas inutiles. El fuente
 esta disponible y el formato usado (gdl-VCG) es facil de entender.
-sustitucion de grupos de instrucciones mediante macros
-regeneracion de codigo para posterior recompilacion

Lo que debe quedar claro es que el programa puede parecer caro, pero es 
porque lo vale.

Para aprender tecnicas de desensamblado pueden ser utiles los libros de 
la editorial "No Starch Press", en particular:
Hacking: The Art of Exploitation
Hacker Disassembling Uncovered, by Kris Kaspersky

Reversing: Secrets of Reverse Engineering, by Eldad Eilam
Reverse Compilation Techniques, by Cristina Cifuentes

Por ultimo me gustaria incluir un comentario que he leido en uno de estos 
libros de desensamblado:
"It will become more understandable after studying the disassembled listing."

Y mi propio comentario: me extranyaria mucho. En general el codigo 
desensamblado es el ultimo recurso yo que suelo usar.

*EOF*