Wiithon 1.1 publicado!

Actualizado: sábado, 21 de noviembre de 2009

Bueno por fin publicamos la nueva versión tras casi 5 meses desde el anuncio de la 1.0.
Para mi wiithon me ha aportado mucho en conocimientos, me he acostumbrado tras muchos años de SQL puro, el uso de bases de datos ORM. He aprendido la potencia del combo python + pygtk. He aprendido a crear paquetes deb que siguen las políticas de Debian. Crear manpages, hacerme un repositorio de paquetes, resolver conflictos de bazaar, subir paquetes, comprender los problemas de punteros en 32bits y 64 bits y por último, he aprendido a amar a los Makefiles y esa gran satisfacción de hacer cosas complejas de forma controlada y sencilla.

Sin más rollo os pongo un tutorial mucho más simplificado, si lo comparamos con el de la versión anterior:

  1. Novedades
  2. Características ya existentes
  3. Reporte de bugs
  4. Instalación
  5. Actualización
  6. Uso de Wiithon en Consola (CLI)
  7. Descargar código fuente
  8. Colaborar en Wiithon
  9. Estado de traducción de Wiithon.
  10. Team wiithon
  11. Pantallazos

Seguir leyendo

Obtener información de Binarios y librerías compartidas (nm/objdump)

nm – Listado de funciones de un objeto

Si queremos obtener un listado de funciones que tiene un código objeto o una librería compartida se utiliza «nm», que lo descubrí de casualidad.
Este comando lista todos los símbolos que contiene el código objeto o la librería dinámica.
Por ejemplo vamos a crear una librería dinámica con solo una función llamada «factorial».
Este es el código:

#include <stdio.h>

int factorial(int n)
{
    return n == 0 ? 1 : n * factorial(n-1);
}

Lo compilo así:

gcc factorial.c -o libfactorial.so -shared -fPIC

Ahora analizamos la librería con el comando «nm»:

nm -D libfactorial.so

Obtenemos esto:

         w _Jv_RegisterClasses
00002010 A __bss_start
         w __cxa_finalize
         w __gmon_start__
00002010 A _edata
00002018 A _end
000004c8 T _fini
00000314 T _init
0000044c T factorial

Vemos que nuestro función en código maquina esta en el offset del archivo 0x44c.
Si leemos el man, obtenemos el significado de los símbolos:

Symbol Type Description
A The symbol’s value is absolute, and will not be changed by further linking.
B Un-initialized data section
D Initialized data section
T Normal code section
U Undefined symbol used but not defined. Dependency on another library.
W Doubly defined symbol. If found, allow definition in another library to resolve dependency.

Las funciones T son las linkables, exceptuando «_fini» y «_init» que son funciones comunes a cualquier librería dinámica. (Esto es una suposición mía, aunque muy lógica por otra parte).

Un ejemplo de código de linkado típico:

#include <stdio.h>

int factorial(int n);

int main()
{
 printf("5! = %d\n", factorial(5));
 return 0;
}

Se compila así:

gcc link.c -o link -L. -lfactorial

Y como la librería no esta en una ruta estándar, se ejecutaría así:

export LD_LIBRARY_PATH="." && ./link
5! = 120

Vamos a probar un código que linke dinamicamente, pero en lugar de el fácil «-lname», lo haré con el dload, que nos sirve de ejercicio para entender como funcionan las librerías dinámicas. El código es el siguiente:

#include <stdio.h> // para fprintf
#include <stdlib.h> // para exit
#include <dlfcn.h>  // para dlopen, dlsym, dlerror, dlclose

int factorial(int n);

int main(int argc, char **argv)
{
 void *lib_handle;
 int (*factorial)(int);
 int x;
 char *error;

 lib_handle = dlopen("libfactorial.so", RTLD_LAZY);
 if (!lib_handle)
 {
 fprintf(stderr, "%s\n", dlerror());
 exit(1);
 }

 factorial = dlsym(lib_handle, "factorial");
 if ((error = dlerror()) != NULL)
 {
 fprintf(stderr, "%s\n", error);
 exit(1);
 }

 x = factorial(5);
 printf("5! = %d\n",x);

 dlclose(lib_handle);
 return 0;
}

El código hay que mirarlo detenidamente, especialmente el puntero a función, pero por lo demás, es sencillo y se autocomenta.
Se compila así:

gcc -rdynamic -o dlopen dlopen.c -ldl

Probamos el ejecutable:

export LD_LIBRARY_PATH="." && ./dlopen
5! = 120

objdump – Desensamblando de binarios

Con este comando podemos obtener el código en ensamblador a partir del código maquina. El comando es el siguiente:

objdump -d libfactorial.so

Si además lo compilamos introduciendo los símbolos de debugeo (parámetro -g), podemos ver el código en ensamblador combinado con el código fuente. Se añadiría el parametro -S:

objdump -d -S libfactorial.so

Ya sabíamos que nuestra función «factorial» estaba en el offset 0x44c, por tanto lo busco en la salida de objdump y pasteo la salida (en este caso, con símbolos de debugeo):

0000044c <factorial>:
#include <stdio.h>

int factorial(int n)
{
 44c:	55                   	push   %ebp
 44d:	89 e5                	mov    %esp,%ebp
 44f:	53                   	push   %ebx
 450:	83 ec 14             	sub    $0x14,%esp
 453:	e8 ef ff ff ff       	call   447 <__i686.get_pc_thunk.bx>
 458:	81 c3 9c 1b 00 00    	add    $0x1b9c,%ebx
    return n == 0 ? 1 : n * factorial(n-1);
 45e:	83 7d 08 00          	cmpl   $0x0,0x8(%ebp)
 462:	74 14                	je     478 <factorial+0x2c>
 464:	8b 45 08             	mov    0x8(%ebp),%eax
 467:	83 e8 01             	sub    $0x1,%eax
 46a:	89 04 24             	mov    %eax,(%esp)
 46d:	e8 f2 fe ff ff       	call   364 <factorial@plt>
 472:	0f af 45 08          	imul   0x8(%ebp),%eax
 476:	eb 05                	jmp    47d <factorial+0x31>
 478:	b8 01 00 00 00       	mov    $0x1,%eax
}
 47d:	83 c4 14             	add    $0x14,%esp
 480:	5b                   	pop    %ebx
 481:	5d                   	pop    %ebp
 482:	c3                   	ret

Con el poco ensamblador que me enseñan en la uni, puedo deducir los siguientes offsets:

45e: Es la comparación de n con 0
462: Si la igualdad anterior se cumple, salta a la línea 44c + 2c = 478
478: Es el interior del IF, iguala el parámetro que viene de la pila con 1. Definiendo 0! = 1
464: Se ejecutaría si la comparación de 45e no se da. Se asigna la vuelta de la recursión
467: Se resta 1 a n
46a: Se prepara e parámetro n-1 en eax, previo a una llamada.
46d: Se hace la llamada recursiva a si mismo.
472: Se multiplica por 8 la vuelta de la recursión.
476: Estamos en el else, por tanto esta jmp se salta el interior del if. 44c + 31 = 47d
47d: De aquí en adelante prepara el return, deja la pila como estaba antes de la llamada y se restaura el IP.

Vamos a hacer algo fácil «crackear»(si se le puede llamar crackeo a esto xD) el programa para cambiar la asignación de:
0!=1 por 0!=4

Por tanto el 5! en lugar de dar 120 va dar 4 veces más, 480.

Para hello abrimos con algún editor de hexadecimal:

ghex2 libfactorial.so

Vamos al OFFSET 479 (478 + 1) y cambiamos el 01 por 04.

Hacemos la prueba de fuego:

export LD_LIBRARY_PATH="." && ./dlopen

Y efectivamente:

5! = 480

OuYeah!


Bueno con esto acabo, este articulo es sobre todo didáctico por lo que si alguno puede completar más el articulo con sus comentarios, se le agradeceremos todos.

Fuentes:
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
http://unixhelp.ed.ac.uk/CGI/man-cgi?nm
http://node1.yo-linux.com/cgi-bin/man2html?cgi_command=ld
http://node1.yo-linux.com/cgi-bin/man2html?cgi_command=ldconfig

Significado pitidos de la placa base

Me apunto aquí una chuleta con los errores del POST de la BIOS. Como sabeis esto cambio dependiendo del desarrollador de la BIOS, pero más o menos esto es un consenso. No obstante iré actualizando cuando no se cumpla:

No hay pitidos No hay suministro electrico o el parlante de sistema esta desconectado o defectuoso
1 pitido corto Arranque normal.
Pitido constante ininterrumpido Falla en el suministro electrico
Pitidos cortos y constantes placa base defectuosa.
1 pitido largo Error de memoria RAM.
RAM Refresh Failure. Los diferentes componentes encargados del refresco de la memoria RAM fallan o no están presentes.
1 pitido largo, 1 corto Fallo general en la placa madre o ROM básica del sistema
1 pitido largo,2 cortos No se encuentra la tarjeta de video, puede estar mal instalada o bien defectuosa.
1 pitido largo, 3 cortos No se encuentra monitor conectado a la tarjeta gráfica.
1 pitido largo, varios cortos Falla relacionada con el video (depende del tipo de tarjeta de video y del la configuración de la bios)
2 pitidos largos y uno corto Falla en la sincronización de imágenes
2 pitidos cortos Error de paridad de memoria. La paridad no es soportada por la placa base.
3 pitidos cortos Fallo de memoria en los primeros 64 Kbytes de la RAM.
4 pitidos cortos El temporizador o contador de la placa base se encuentra defectuoso. El Timer 1 de la placa no funciona.
5 pitidos cortos La CPU ha generado un error porque el procesador o la memoria de vídeo está bloqueada.
6 pitidos cortos El controlador o procesador del teclado (8042) puede estar en mal estado. La bios no puede conmutar en modo protegido. Este error se suele dar cuando se conecta/desconecta el teclado con el ordenador encendido.
7 pitidos cortos La CPU ha generado una interrupción excepcional o el modo virtual del procesador está activo.
8 pitidos cortos El adaptador de vídeo ( tarjeta gráfica) del sistema no existe o su memoria de vídeo (RAM) está fallando. No es un error fatal. Es un fallo de escritura de la Video RAM.
9 pitidos cortos Error de conteo de la Video RAM. El valor del checksum (conteo de la memoria) de la RAM no coincide con el valor guardado en la bios.
10 pitidos cortos El registro de la CMOS RAM falla a la hora de la desconexión.
11 pitidos cortos La memoria caché externa está fallando. En la bios hay una opción llamada video memory cacheable, que lo que hace es volcar el contenido de la ram de la tarjeta en el disco duro. Ponla en enable, haber si soluciona tu problema.
2 pitidos cortos Se ha detectado un error al realizar uno de los tests de hardware.
Pitidos cortisimos, tenues y constantes Posiblemente el teclado provoca este error o bien una tecla presionada durante el arranque.