-[ 0x0C ]--------------------------------------------------------------------
-[ CRACKING BAJO LINUX - IV ]------------------------------------------------
-[ by SiuL+Hacky ]----------------------------------------------------SET-20-


1. PROTECCIONES COMERCIALES -------------------------------------------

Vamos a tener en esta entrega una mezcla de teoria y practica, donde por
un  lado  conoceremos  detalles  de  una  proteccion  comercial bastante
extendida  en  el mundo  linux/unix;  y por  otro  aplicaremos conceptos
generales  que si observais con cuidado se suelen repetir con frecuencia
en este tipo de protecciones.

Afortunada  o  desafortunadamente linux  esta  todavia bastante  libre de
aplicaciones  comerciales,  o  al  menos  de  aquellas  que  no permiten
mediante  una licencia especial  su uso gratuito (tal  como al final han
hecho  WordPerfect, StarDivision y  otra gente). Por  ello tampoco es de
esperar  un  desarrollo de  soluciones de  tipo comercial  para proteger
programas.  Incluso en Windows donde  la explosion de software comercial
es  tremenda, el hecho de licenciar  un sistema de proteccion/gestion de
licencias  es minoritario y  predominan sistemas mas  o menos caseros (y
mas o menos eficaces) de proteccion).

Un  ejemplo  claro  de  protecciones comerciales  en  Windows  serian la
populares  mochilas  o  llaves  hardware. Haciendo  un  inciso,  hay que
sealar  que  un uso  adecuado de  una mochila,  debe hacer  un programa
practicamente  seguro, a no ser de que se  disponga de una de ellas y se
pueda  hacer un estudio para su emulacion.  Bueno, pues a pesar de esto,
una gran parte de ellos son crackeables de forma sencilla.

Uno  de los problemas fundamentales en el uso de soluciones comerciales:
la desatencion hacia la proteccion es tal, que no solo no se invierte el
menor medio humano (que no economico) en desarrollar la proteccion, sino
que la forma de "empalmar" la proteccion al resto del programa, lo suele
hacer  altamente vulnerable.  De alguna forma  es de esperar  que si uno
paga  por un sistema  de proteccion, no  tenga que perder  un segundo en
adaptar el programa.

Es   aqui  donde  llegamos  a  esos  chicos  tan  raros  que  programan
aplicaciones  en  unix,  generalmente sobre  cosas  tan  esotericas como
simulaciones  quimicas, estudio  geofisicos, etc  ... El  panorama hasta
ahora es muy poco ingenioso. Este tipo de aplicaciones cuestan muchisimo
dinero,  y como generalmente  su ambito de uso  es muy reducido, tampoco
les  debe importar demasiado que no se  proteja. Eso no significa que lo
dejen  en  plan  "copien  y  disfruten";  por  el  contrario  compran un
programa/conjunto  de utilidades  que venden los  chicos de Globetrotter
Software, y que casi todo el mundo que trabaja con estaciones de trabajo
habra  oido alguna vez: Flexlm. Si, flexlm (Flex License Manager) parece
ser  la forma mas generica  de proteger, bien sea  un compilador de Sun,
una  aplicacion para  SGI, u otras  aplicaciones que  ultimamente se han
dignado  a  portar a  linux. Por  cierto,  me cuentan  por ahi,  que hay
aplicaciones de NT (New Testament) que tambien lo usan.

Para  el que  no lo conozca,  estos chicos de  Globetrotter Software han
hecho  un autentico  negocio. Su lista  de clientes es  importante, y la
cantidad   de  bazofia  comercial   que  podeis  encontrar   en  su  web
(www.globetrotter.com)  es tremenda. Vamos que saben vender bien la moto
esta  gente. Esto  en web,  por lo que  supongo que  una presentacion en
directo  de sus productos debe ser como  para perder el control. Si esto
lo  mezclais con licencias, patentes y todo  eso, da la impresion de que
lo  que estas comprando es algo asi como el Gate-keeper que salia en "La
Red". Ya juzgareis vosotros mismos, pero a mi me parece que, en general,
es  el timo  de la estampita  aun sin conocer  lo que cuesta.  Y digo en
general,  porque puede ser un buen esquema, siempre que no se implemente
por  cuenta propia algunas funciones que permite FlexLM.  Pero entonces,
estamos  pagando por  algo que  no protege, lo  que protege  es la parte
generada por el comprador.



2 . FlexLM. Cuestiones generales  -------------------------------------

Ya  esta bien de  hablar vaguedades.   que es y  como funciona FlexLM ?
Hay dos modos principales de funcionamiento:

1)  En el primero de ellos  hay una especie de esquema cliente/servidor.
El  cliente  estaria  integrado dentro  del  programa a  proteger,  y el
servidor  seria un  programilla o demonio  generado via  flexlm (y donde
cada empresa puede introducir variantes y mejoras). En este modo aparece
la  utilidad "lmgrd" que hace las veces  de inetd y se encarga de lanzar
diversos  demonios. Cada  demonio perteneceria a  una empresa/producto y
obviamente  se  encargarian  independientemente  de  dar  acceso  a  los
clientes.  Cada demonio lee la informacion de un fichero de licencia con
un  formato  estandard  que  genericamente  (hay  peque~as  variaciones)
incluye:  nombre del programa a proteger,  numero de licencias, fecha de
caducidad y un hash que verifica los contenidos anteriores.

2) En el otro, el cliente lee directamente el fichero de licencia.

Si  nos ponemos la camiseta de Globetrotter, diriamos que con la primera
de  las  opciones,  es posible  tener  licencias flotantes,  es  decir n
licencias  a usar por n ordenadores, pero sin fijar cuales. Bueno, blah,
blah.  La  cuestion  es   como  de  seguro  es FlexLM  ?  Lo  que opina
Globetrotter de la la vulnerabilidad de su producto es (traducido):

*** ATAQUE SENCILLO ***
Ejecutando la aplicacion sobre un depurador si esta conserva informacion de
depurado (unstripped para ser tecnicos).

=> es cierto. Es una ataque sencillisimo, y es el gran problema de todo el
producto: al final todo se reduce a:

llamar funcion_check_supercomplicada
es correcta la licencia ?

y  esta decision suele  ser sencilla de  localizar (vistosos mensajes de
error)  y mas facil todavia de parchear.  Otro inciso, no hace falta que
haya  informacion de  simbolos para crackear  un programa  asi. Si esta
informacion  existe, lo  que facilita  es que  se reviente completamente
(como veremos) el sistema FlexLM.

*** ATAQUE DIFICIL, DEPENDIENTE DE LA CONFIGURACION ***
"Matando  los  demonios. Si,  a  pesar de  todo, no  se  usa uno  de los
temporizadores  incorporados, y  no se  llama a  la funcion HEARTBEAT(),
entonces la proteccion software puede ser puenteada por alguien que mate
los  demonios, ya que las aplicaciones  nunca detectarian que el demonio
esta caido."

=> de dificil nada. Debe estar en el grupo de los faciles, ya que la funcion
heartbeat puede ser parcheada y se acabo el invento. O mejor se parchea todo
;)


*** ATAQUE MUY DIFICIL ***  (...suena bien eh ?)
"Adivinando  los hash  que pertenecen  al fichero  de licencia.[...] The
algorithm  used is a proprietary  one-way block chaining encypherment of
all the input data".

=> me niego a traducir esta obra de arte. Por lo demas, el hash tiene 48
bits. sigamos

"Escribiendo  un nuevo demonio que emule el original. FlexLM encripta el
trafico  entre el cliente y el demonio  para hacer mas dificil este tipo
de ataques".

=> en cuanto a ingenieria inversa me parece con diferencia el tema mas
interesante, aunque las debilidades anteriores ya desacreditan el sistema.

"Ejecutando  el depurador en un ejectuble sin simbolos de depurado. Esto
requiere   que   alguien   encuentre  la   llamadas-FlexLM   sin  ningun
conocimiento en la tabla de simbolos".

=>  guau, o  sea que vamos  a utilizar  el ataque muy  dificil. Pero que
buenos que somos.



3 . Funcionamiento interno de FlexLM  ---------------------------------

Bueno hasta aqui mucho de blah, blah, blah, propaganda, marketing y esas
cosas. Ahora bien, las bases sobres la que se asienta son solidas ?

Para  ello, lo mejor es irse al web de Globetrotter (www.flexlm.com creo
que  tambien valia)  y pillar  el kit  de desarrolladores.  Hace ya unos
cuantos  meses pille el de  la version 6.1, que  es el que incorporan la
mayoria  de los programas (si,  flexlm se actualiza, ya  se sabe hay que
sacar  nuevas versiones cueste lo que cueste). Este kit es una autentica
mina  de  oro,  ya  que facilita  aparte  de  una  documentacion bastante
completa  (hay, logicamente funciones interesantes no documentadas), los
siguientes elementos:

1. Gestor de licencias (lmgrd)
2. Codigo fuente de un ejemplo demonio-cliente
3. Utilidades para generacion de licencias
4. Tres librerias que contienen todo el API de FlexLM

Dentro  del 3er punto esta incluida  una utilidad llamada lmcrypt. Esto,
lo  creais  o  no, es  una  generador  de licencias.  Esto  es  un nuevo
concepto,  resulta que  la empresa que  vende la  proteccion facilita un
generador  de licencias. Ya  no es necesario  crearte tu propia programa
que  destripe las  entraas del algoritmo  de generacion, no,  te lo dan
ellos.

Hombre,  hay que matizarlo, pero es  asi como vereis. Bueno nos habiamos
bajado el kit de desarrollo. Este viene pseudoencriptado, con lo cual es
preciso  perder unos segundos (pocos eso si) en sacar la clave. No voy a
entrar  en mucho detalle, ya que creo que es justo que si alguien quiere
acceder  a este material se lo trabaje  un poco. De todas formas, es muy
sencillo y utilizando ltrace se consiguen las pistas para sacar la clave
facilmente.

Aun  asi  si  alguien  no es  lo  suficientemente  capaz,  siempre puede
arrastrarse  a los chicos de Globetrotter y  que te manden la clave (que
es lo que supuestamente todo el mundo deberia hacer).

Es  facil al principio perderse entre  la documentacion, por lo cual, os
voy a resumir en que se basa el sistema. Hay 7 elementos clave para cada
demonio comercial (entendiendo por demonio comercial, todo el sistema de
gestion  de licencias utilizado para un programa determinado ... que hay
mucho mal pensado):

* 2 semillas de encriptacion exclusivas.
* 5 claves de 32 bits.

Para  la  generacion de  los hash  que  autentifican las  licencias, son
fundamentales  estas  dos  semillas,  ya  que  conociendolas  es posible
autentificar  tantas  licencias como  uno quiera.  Las cinco  claves son
utiles  para  poder instalar  el kit  y para  generar un  demonio. Estos
datos,  son logicamente utilizados por las funciones del API, por lo que
se empaquetan en la siguiente estructura de datos:

typedef struct  {
                            short tipo;   
                            unsigned long semillas[2];
                            unsigned long claves[4]; 
                            short flexlm_version;
                            short flexlm_revision;
                            char flexlm_patch[2];
                            char behavior_ver[LM_MAX_BEH_VER + 1];
                          } codigos;

Supongamos  que  hemos comprado  la cosa  esta  y nos  han pasado  las 2
semillas  y las 5  claves. El programa  de instalacion del  kit nos pide
todos  estos datos, y  nos genera un  cliente, un demonio  y otras cosas
(ya,  ya se que no teneis ninguno  de estos datos, pero estamos hablando
en  un caso generico). Hay una utilidad llamada lmcrypt, que recibe como
entrada  una licencia en la  que el hash esta a  cero, y nos devuelve el
fichero  de licencia  con el  hash adecuado. La  forma en  que genera el
hash, es mediante esta funcion:

int lc_cryptstr(job, STR, STR_RETURN, *CODIGOS, flag, filename, errors) 

Esta  funcion  esta  documentada en  los  manuales,  y os  he  puesto en
mayusculas los parametros importantes:

STR: recibe la cadena de texto donde se especifica sobre que programa se
aplica  la  licencia,  si caduca  y  cuando,  y el  numero  de licencias
permitidas.   Uno de los  campos es el  hash de autenticacion,  y que en
este caso se pone a cero. Por ejemplo:

      "FEATURE word MSOffice 1.0 permanent 4 0"

CODIGOS: es una estructura como la de arriba, con las semillas y las claves,
que puestamente se usaran para crear el hash

STR_RETURN: devuelve una cadena de texto equivalente a STR, pero donde el
hash ya no es cero, sino son los 48 bits correspondientes.

Vale,  la licencia  esta generada.  Porque  no la  genera cualquiera ?
Hombre,  pues porque hacen  falta esos 7 datos  ? 7  datos ? bueno, en
realidad  solo son 6,  ya que en  la estructura CODIGOS  solo aparecen 4
claves (ya veremos que pasa con la quinta).



4 . Debilidades del sistema  ------------------------------------------

Ahora resulta que el usuario Pepito se ha comprado su programa carisimo, y
le han dado un fichero de licencia que podria ser asi:

SERVER localhost.localdomain ANY 
VENDOR khoral /usr/local/flexlm/v6.0/i86_l1/khoral 
FEATURE xprismpro khoral 1.0 permanent 4 XXXXXXXXXXXX 

las  XXX son el hash eh !!  Arrancara el gestor de licencias (lmgrd) que
ira  a buscar  ese fichero  y tendra  que comprobar  el hash.  Bien, por
sentido  comun, y aunque uno  no sepa nada de  cracking, o el sistema es
muy  bueno o de alguna forma para comprobarlo hay que generarlo otra vez
y comparar.

  Como comprueba el hash el demonio ? Tomando el demonio de ejemplo que
viene  en  el kit  (y  al igual  que hacen  la  mayoria de  los demonios
comerciales  que circulan) primero se incializa el sistema llamando a la
funcion lc_init:

lc_init(--, --, CODIGOS*, --)

Je, je, luego efectivamente en el demonio hay una copia de la estructura
CODIGOS, con la semillas y las 4 claves. QUE FRAUDE ! pensareis. Aqui es
donde  FlexLM dice:  Ah, pero la  seguridad esta garantizada  ya que las
semillas  estan encriptadas (xoreadas) con la clave numero 5 que no esta
incluida  en  el  demonio  (y asi  es  efectivamente).  Esta  funcion de
inicializacion  recibe las 4  claves y las dos  semillas xoreadas con la
clave numero 5.

Recapacitemos,  nos dicen que NO estan  en el demonio todos lo elementos
que  nos permitirian  generar licencias.  Yo, desde  luego, no  crei que
comprobaran  el hash sin recurrir a los  datos originales con el que fue
generado,  luego la clave  numero 5 debian generarla  de alguna forma al
vuelo  (o  bien estaba  "escondida" en  el  demonio). Si  analizamos mas
detenidamente   el  codigo  del   demonio  de  ejemplo,   vemos  que  la
comprobacion del hash se hace con una llamada a la funcion lc_crypt, que
obviamente no esta documentada

lc_crypt (--, --, --, CODIGOS*)

pero  en la que la estructura  codigos recibe ya las semillas originales
(desxoreadas). Je, je, luego han generado la clave numero 5.

En  definitiva y ahorrandonos listados en ensamblador (ya llegaran) , la
clave  numero 5  se genera  mediante una  llamada a  la funcion, tambien
indocumentada l_svk (secret vendor key ?)

int l_svk(char*,CODIGOS*)

el  parametro de entrada (y co-responsable de su generacion) es nada mas
y  nada menos  que el nombre  del demonio :D.  Ciertamente curioso. Esta
funcion  l_svk esta disponible  en las librerias  del kit de desarrollo,
luego  podemos hacernos  un programita  en el  que rellenando  los datos
correspondientes a las semillas xoreadas y las 4 claves, nos facilite la
clave  numero 5, y lo que es  mas importante las semillas originales con
las que generar licencias en serie.

Resumiendo,  en el codigo del  demonio (y en su  nombre) estan los datos
para  generar  todas  las  licencias del  mundo.  El  unico  problema es
identificar  la llamada a la funcion lc_init,  por ejemplo, en la que se
pasa  como parametro una estructura  de tipo CODIGOS. Pero  eso no es un
gran  problema una  vez que sabemos  como es  (en el demonio  del kit de
desarrollo,  si que  hay tabla de  simbolos y es  inmediato localizar la
funcion en el listado en ensamblador).

Mi  opinion es  que si  se dispone de  un fichero  de licencia operativo
(sabiendo asi las sintaxis de cada campo), es bastante sencillo generear
licencias  adicionales o  modificar las existentes.  En el  resto de los
casos se complica algo.



5 . Ficheros de licencias. Ejemplo practico ---------------------------

Despues de esta introduccion general a lo que es FlexLM, que no pretende
ser  demasiado exhaustiva por  cuestiones de espacio  (si acaso en otras
entregas,  trataremos un caso  concreto de FlexLM  que sea especialmente
didactico),  vamos a  ver un  ejemplo practico  que si  bien esta flexlm
metido por medio, no es exactamente flexlm.

El programa se llama IDL 5.2, y significa algo asi como Interactive Data
Language.  Es una especie de lenguaje de programacion muy orientado a la
presentacion/visualizacion grafica de datos, y que segun cuenta la gente
es bastante potente. Lo podeis encontrar en el web de rsi:

www.rsinc.com

Tienen una demo muy curiosa. Supuestamente es completamente funcional si
exceptuamos  salvar datos  e imprimir.  Eso si  solo durante  7 minutos,
transcurridos  los cuales  te echa sin  el menor  miramiento. Vereis que
cada  vez afinan mas. Existe  la posibilidad de que  te den una licencia
temporal  para evaluarlo (gratuita), y luego  si lo compras, la licencia
va por FlexLM.

Curiosamente la forma de obtener una licencia temporal de evaluacion, no
es con FlexLM. No se muy bien, si es que no se fian del sistema (en cuyo
caso  parece  deberian cambiarlo),  o bien  no quieren  pagar mas  a los
chicos  de Globetrotter. Se han hecho su propio programita que genera un
fichero de licencia que desde luego no esta en modo texto.

Este  programa, llamado  genver, genera  un numero  aleatorio que  tu le
comentas  al  comercial de  turno por  telefono, y  este te  genera otro
numero que introduces al programa para que genere la licencia.

Hay claramente tres opciones:

1) Evitar que caduque a los 7 minutos (hay una bonita ventana que nos
comunica que el tiempo se ha acabo).

2) Generar una licencia temporal.

3) Generar un licencia Flex.

Vamos  a descartar  la primera  y tercera  opcion. La  primera porque el
programa  esta hecho en Motif, y no  conocemos nada sobre ello, ni sobre
Toolkits,  mensajes,  widgets  ni nada  de  eso. Ademas  el  programa es
gigantesco  y los listado en ensamblador son  enormes (de mas de 60 Mb).
Hasta  ahora no hemos tocado  nada sobre Motif, ya  que algo me dice que
esta  cayendo en deshuso y es en general bastante farragoso (esta basado
en objetos, es decir, codigo gigantesco). La tercera es por una cuestion
preventiva,  ya que ya me ha ocurrido varias veces de estar mucho tiempo
forzando funcionalidades que luego no estaban disponibles en el cliente,
con  lo  cual manipular  licencias sin  tener una  referencia de  que el
cliente  las va  a saber  manejar, puede  ser una  perdida de  tiempo. En
cualquier  caso, con lo  expuesto aqui podreis  obtener facilmente tanto
las  semillas como la  5 claves (el que  lo consiga que  me las mande, y
tendra soporte on-line de flexlm. A ver si os animais).

Manos a la obra, ejecutamos el programa genver (que se encuentra en el
directorio idl/bin/bin.linux/genver) y nos dice:

	Your number for today is: 6239

	Enter length of trial period in days :

si le ponemos que 1 millon, nos echara rapidamente, pero si ponemos algo
razonable como 100, nos respodera:

	Enter RSI supplied installation key:

esta  es la que supuestamente nos  dan por telefono. Respondiendo lo que
sea,  nos dice que es invalida. Ejectando el maravilloso programa ltrace
que  hemos descrito  ampliamente en entregas  anteriores, obtenemos este
interesante listado:

[080490e2] fopen("./idl.genver", "w")             = 0x0804b028
[08049122] chmod("./idl.genver", 0666)            = 0
[080493ca] ftime(0xbfffe5dc, 0, 0x40005ff0, 0x08048940, 0xbfffe5dc) = 0
[0804946b] printf("\nYour number for today is: %lu\n"..., 14098) = 34
[08048e24] fileno(0x0804afc8)                     = 0
[08048e2f] isatty(0)                              = 1
[08048e4a] printf("Enter %s: ", "length of trial period in days ") = 39
[08048e68] fgets("100\n", 1024, 0x0804afc8)       = 0xbfffe164
[08048f1c] sscanf("100\n", "%ld", -1073749672, -1073749672) = 1
[08048f54] sscanf("100\n", "%ld", -1073749672, -1073749672) = 1
[08048e24] fileno(0x0804afc8)                     = 0
[08048e2f] isatty(0)                              = 1
[08048e4a] printf("Enter %s: ", "RSI supplied installation key") = 37
[08048e68] fgets("235253453536346"..., 1024, 0x0804afc8) =0xbfffe164
[08048f1c] sscanf("235253453536346"..., "%ld", -1073749672,-1073749672) = 1
[08048f54] sscanf("235253453536346"..., "%ld", -1073749672,-1073749672) = 1
[08048db1] fprintf(0x0804af70, "genver: %s\n\n", "invalid key") = 21
[08048dde] exit(1)                                = <void>

hay  dos secuencias muy parecidas,  una la que lee  el numero de dias, y
otra  la que lee la llave. La secuencia  es printf -> fgets -> sscanf ->
sscanf. Si os fijais en el puntero de programa, la localizacion de estas
funciones es la misma, es decir, hay una especie de funcion que hace las
labores  de "imprime cartel, lee caracteres, pasalo a numero". No parece
muy  sensato que la funcion sscanf (que es similar a scanf) se llame dos
veces con los mismos argumentos, pero ...

Generemos  un listado  en ensamblador (con  el script  dasm, cuya ultima
actualizacion  acompa~o al final. Por  cierto disculpad que los mensajes
esten  en ingles) del programa genver,  y examinemos las proximidades de
la secuecia fgets -> sscanf:

Reference to function : fgets

0x08048e63 call   0x08048798
0x08048e68 addl   $0xc,%esp
0x08048e6b movl   %eax,%eax
0x08048e6d movl   %eax,0xfffffbf8(%ebp)
0x08048e73 cmpl   $0x0,0xfffffbf8(%ebp)
0x08048e7a jne    0x08048e90

fgets  devuelve  en  eax  el  puntero  a  la  cadena  leida,  luego esta
comprobando  que se  ha leido algo.  Posteriormente comprueba  que no es
ningun  caracter exotico (CR,  tabulador, ...), y  hace una llamada (dos
veces, solo os pongo la segunda) a sscanf:

int sscanf( const char *cadena, const char *formato, &numero)


0x08048f38 leal   0xfffffbf0(%ebp),%eax
0x08048f3e pushl  %eax; 	<----  salva el puntero al numero
0x08048f3f leal   0xffffeb17(%ebx),%edx
0x08048f45 movl   %edx,%eax
0x08048f47 pushl  %eax		<----  salva el punt. a la cadena de formato
0x08048f48 movl   0xfffffbf8(%ebp),%eax
0x08048f4e pushl  %eax		<----  salva la cadena origen

Reference to function : sscanf
				<---- sscanf devuelve en eax la cantidad
				<---- de caracteres convertidos

0x08048f4f call   0x08048848
0x08048f54 addl   $0xc,%esp
0x08048f57 movl   %eax,%eax
0x08048f59 cmpl   $0x1,%eax	<---- comprueba que se ha convertido un car.
0x08048f5c je     0x08048f92	<---- salta si es cierto
0x08048f5e leal   0xfffffbfc(%ebp),%eax
0x08048f64 pushl  %eax

[...]

0x08048f8a call   0x08048d80
0x08048f8f addl   $0x8,%esp

Referenced from jump at 08048f5c ; 

0x08048f92 movl   0xfffffbf0(%ebp),%eax <--- mueve el numero devuelto por
					<--- sscanf a eax
0x08048f98 jmp    0x08048fa0
0x08048f9a leal   0x0(%esi),%esi

Referenced from jump at 08048e7e ; 08048f98 ; 


0x08048fa0 movl   0xfffffbec(%ebp),%ebx
0x08048fa6 movl   %ebp,%esp
0x08048fa8 popl   %ebp
0x08048fa9 ret   

luego  toda  esta funcion,  lo  que hace  es  devolver en  eax  la llave
introducida por el usuario. Para averiguar a donde retorna esta funcion,
lo  mejor es ejecutar el  programa en el depurador  y al encontrarnos en
este  punto del programa (tras introducir la llave, ya que esta parte de
codigo  tambien  se  ejecuta  cuando introducimos  el  numero  de dias),
ejecutar  el  comando  gdb  llamado "back",  que  devuelve  el  arbol de
llamadas en ese punto:

#0  0x8048f1c in strlen ()
#1  0xbfffe38c in ?? ()
#2  0x80495a6 in strlen ()
#3  0x804899b in strlen ()

luego venimos del codigo con direccion 0x80495a6. Examinemoslo:

0x080495a1 call   0x08048e00 	<--- esta es la funcion que hemos visto
				<--- y que devuelve la llave leida
0x080495a6 addl   $0x4,%esp
0x080495a9 movl   %eax,0xffffeaf4(%ebp)
0x080495af movl   0xffffeaf4(%ebp),%edi
0x080495b5 movl   %edi,0xffffeb4c(%ebp)
0x080495bb movl   0xffffeb4c(%ebp),%eax
0x080495c1 movl   %eax,0xffffeaf4(%ebp)
0x080495c7 movl   0xffffeaf4(%ebp),%edi
0x080495cd cmpl   %edi,0xffffeb48(%ebp)

nunca habia visto algo tan ineficiente, estas lineas solo valen para que
finalmente  se  compare  el  numero  introducido  con  el  contenido  en
ebp+0xffffeb48, que es un numero que cambia cada vez, y que para vuestra
informacion es la clave correcta. Pongo el resto del codigo.

0x080495d5 pushl  $0x1   	<--- esto se ejecuta si la clave es erronea
0x080495d7 leal   0xffffeee2(%ebx),%edx
0x080495dd movl   %edx,0xffffeaf4(%ebp)
0x080495e3 movl   0xffffeaf4(%ebp),%eax
0x080495e9 pushl  %eax
0x080495ea call   0x08048d80	<--- aqui se llamara al printf con el
				<--- mensaje de llave invalida

Ya  sabemos donde esta la llave buena,  ahora os voy a ense~ar una forma
sencilla  de que nos aparezca mientras se ejecuta el programa. Para ello
sabemos  que cuando nos solicita la clave, el programa ya la ha generado
internamente,  y la idea  es usar el  printf donde nos  la solicita para
mostrar ese numero en claro. Vuelvo a poner la forma del printf donde se
solicita introducir la llave:

printf("Enter %s: ", "RSI supplied installation key")

que os parece si lo cambiamos a:

printf ("Enter %x: ", puntero_a_la_llave_que_el_ha_calculado);

Para  cambiar la  cadena de  formato, no hay  mas que  editar el fichero
binario (sigo sugiriendo dosemu+hiew) y cambiar la "s" por la "x". Y por
ultimo  habra que  cambiar el puntero  a "RSI  ..." por un  puntero a la
llave.  Para  esto  ultimo  si ejecutamos  genver  bajo  un  depurador y
detenemos  el  programa en  la  instruccion 0x080495a9  (ver  listado de
arriba),  podemos averiguar la direccion absoluta  de la llave, es decir
cuanto   vale  ebp+0xffffeb48  en  ese   punto.  Se  apunta,  llamemosla
direccion_llave.

Volviendo al printf que vamos a modificar, esta es su estructura:

0x08048e38 movl   0x8(%ebp),%eax
0x08048e3b pushl  %eax  	<--- salvar "RSI ..."
0x08048e3c leal   0xffffeb0c(%ebx),%edx
0x08048e42 movl   %edx,%eax
0x08048e44 pushl  %eax		<--- salvar "Enter %s"

Reference to function : printf

0x08048e45 call   0x08048778

si en este punto vemos el valor de ebp, veremos que solo se diferencia en
0x6c unidades de la direccion_llave, es decir modificando:

0x08048e38 movl   0x8(%ebp),%eax
     por
0x08048e38 movl   0x6c(%ebp),%eax

apuntara a la llave correcta, que nos aparecera claramente, es decir, en vez
de preguntar:

	Enter RSI supplied installation key:

preguntara

	Enter llave_correcta:

elegante no ;-) ? Como dao colateral, en vez de solicitarnos el numero de
dias tambien aparecera un numero, pero bueno, creo merece la pena el cambio.

Hasta la proxima entrega,

SiuL+Hacky
si_ha@iname.com

------------------------------ listado de dasm ------------------------

#!/usr/bin/perl
;############ MODIFY THIS LINE WITH YOUR PERL LOCATION ############
push(@INC,"/usr/lib/perl5");
require("flush.pl");


;##################################################################
;######## LINUX DISASSEMBLER 2.0799
;######## (C) SiuL+Hacky Jul 1999
;######## You may copy, modify, distribute this program and
;######## is up you to keep this header here
;######## Usage: dasm exe_file dasm_file
;##################################################################


$f_input=$ARGV[0];
$f_output=$ARGV[1];
&printflush(STDOUT, "\nCreating disassembled file ...");
$return=system("objdump -d -T -x --prefix-addresses ".$f_input.">".$f_output."2");
if ($return!=0){
  print "\nERROR OPENING OBJDUMP $return";
  print "\nUsage: dasm exe_file dasm_file";
  print "\nBe sure to get objdump in your path. Check also file permissions\n";
  exit(1);
 }

open(INPUT, "<".$f_output."2");

&printflush(STDOUT, "\nReading strings ...");
$_=<INPUT>;
while (!/.rodata/){
  $_=<INPUT>;
}
($rubbish, $rest)=split(/.rodata/,$_,2);
($rubbish, $rest)=split(/0/,$rest,2);
@numbers=split(/  /,$rest,5);
$size=hex($numbers[0]);
$starting_address=hex($numbers[1]);
$end_address=$starting_address+$size;
$offset=hex($numbers[3]);
open(CODIGO, "<".$f_input);
seek(CODIGO,$offset,0);
read(CODIGO,$cadena,$size);
close(CODIGO);


SEARCH: while (<INPUT>){
  last SEARCH if (/SYMBOL TABLE/);
}
if (/SYMBOL TABLE/){ 
  &printflush(STDOUT, "\nProcessing symbol table ...");
  $_=<INPUT>;
  while (!/^\n/){
   @st_element=split(/ /, $_);
   $_=$st_element[$#st_element];
   chop;
   $symbol_table{$st_element[0]}=$_;
   $_=<INPUT>;
  }
}
else {
  seek(INPUT,0,0);
}

while (!/\.text/){
  $_=<INPUT>;
}
&printflush(STDOUT,  "\nProcessing jmps and calls ...");

######### the regex gets rid of possible line information #############


while (<INPUT>){
  $_=~ s/0x//g;
  $_=~ s/<.*?>//g;
  $_=~s/  / /g;
  if (/j/){
    ($direccion,$inst,$destino)=split(/ /,$_,3);
    $destino=~s/ //g;
    chomp($destino);
    $salto{$destino}.=($direccion." \; ");
  }
  elsif (/call/){
    ($direccion,$inst,$destino)=split(/ /,$_,3);
    $destino=~s/ //g;
    chomp($destino);
    $call{$destino}.=($direccion." \; ");
  }
}

seek(INPUT,0,0);
&printflush(STDOUT, "\nWritting references ...\n");
open(OUTPUT, ">".$f_output) || die print "\nError opening write file\n";
print OUTPUT "FILE REFERENCED\n\n";

while (!/Disassembly of section .text:/){
 $_=<INPUT>;
 print OUTPUT;
}
$char=".";
$counter=0;
while(<INPUT>){
 $counter++;
 if ( ($counter % 400)==0){
   printflush(STDOUT,$char);
   if ( ($counter % 4000)==0){
     printflush(STDOUT,"\r");
     if ($char eq "."){ $char=" ";}
     else { $char=".";}
   }  
 }
 $copia=$_;
 $_=~s/0x//g;
 $_=~s/<.*?>//ge;
 $_=~s/  / /g;
 ($direccion, $inst, $destino)=split(/ /,$_,3);
 if ( defined( $symbol_table{$direccion} )){
   print OUTPUT "\n";
   print OUTPUT "---- Function : ".$symbol_table{$direccion}." ----\n";
 }
 if (/call/){
   $destino=~s/ //g;
   chomp($destino);
   if ( defined( $symbol_table{$destino} )){
     print OUTPUT "\n";
     print OUTPUT "Reference to function : ".$symbol_table{$destino}."\n\n";
   }
 }  
 if ( defined( $salto{$direccion} )){
   print OUTPUT "\n";
   print OUTPUT "Referenced from jump at ".$salto{$direccion}."\n\n";
 }
 if ( defined( $call{$direccion} )){
   print OUTPUT "\n";
   print OUTPUT "Referenced from call at ".$call{$direccion}."\n\n";
 }
 if (/\$/){
        ($instruccion, $operand)=split(/\$/,$_,2);
        if (!/push/){
          ($operand, $rest)=split(/\,/,$operand,2);
        }
        chomp($operand);
        $offset=hex($operand);
        if ( ($offset <= $end_address) && ($offset >= $starting_address ) ){
          $auxiliar=substr($cadena, $offset-$starting_address);
          $length=index($auxiliar, pack("x") );
          $auxiliar=substr($auxiliar, 0, $length);       
          $auxiliar=~s/\n//g;
          print OUTPUT "\n";
          print OUTPUT "Possible reference to string:";
          print OUTPUT "\n\"$auxiliar\"\n\n"
        }       
  }
 print OUTPUT $copia;
}
close(INPUT);
close(OUTPUT);
print "\n";
system("rm ".$f_output."2");



