lunes, 11 de junio de 2007

init e Introducción a los Niveles de Ejecución en Linux

Orestes Leal R. [orestesleal13022@cha.jovenclub.cu]

Análisis del Stage ejecutado cuando el Núcleo "finaliza" ejecutando el proceso init::

El proceso de arranque del núcleo Linux tiene básicamente la misma distribución jerárquica en cuanto al proceso que se ejecuta después del arranque e inicialización del núcleo que los UNIX convencionales, lo que será descrito a continuación es una descripción de los entresijos que ocurren durante esa etapa de inicialización.

Desde su primera versión, y al ser un OS tipo UNIX, cuando el kernel "termina" su ejecución (realmente no lo hace, sólo cede el control a un proceso padre init), aunque continuará ejecutándose, planificando procesos, etc. Hace una búsqueda de un programa llamado init. Más adelante veremos qué es y para qué sirve, pero con el fin de ir dando un seguimiento correcto, mostremos a continuación lo que ejecuta el kernel para encontrar el ejecutable init:

// Definiciones en C para buscar / encontrar init
762 if (execute_command) {
763 run_init_process(execute_command);
764 printk(KERN_WARNING "Failed to execute %s. Attempting "
765 "defaults...\n", execute_command);
766 }
767 run_init_process("/sbin/init");
768 run_init_process("/etc/init");
769 run_init_process("/bin/init");
770 run_init_process("/bin/sh");
771
772 panic("No init found. Try passing init= option to kernel.");
773 }

Donde run_init_process se encuentra definida de esta manera en el mismo fichero:

727 static void run_init_process(char *init_filename)
728 {
729 argv_init[0] = init_filename;
730 kernel_execve(init_filename, argv_init, envp_init);
731 }

Donde argv_init se encuentra definida en el mismo fichero y donde se define que el argumento debe ser init:

184 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };

Estos segmentos de código están definidos en $KERNELSOURCE/init/main.c ($KERNELSOURCE es el árbol de las fuentes). Las líneas a analizar en cuestión son desde 767 -> 770, estando todo esto basado en el núcleo 2.6.21.1. Esas definiciones en C quieren decir, básicamente, que en este momento el núcleo está haciendo una búsqueda de los posibles lugares donde el proceso init se aloja haciendo llamadas a varias funciones. Si la búsqueda es efectiva, ejecuta el proceso con permisos de super usuario (UID=0); de lo contrario, si el kernel no puede encontrar a init, el mensaje posterior en la línea 772 es bastante claro en ese sentido. A diferencia de algunas variantes de UNIX o BSD UNIX, en Linux, init se encuentra siempre en /sbin/init, definido así por el LFH, un estándar de la distribución de ejecutables, directorios, etc., en un sistema Linux.

Stage Post INIT::

Una vez que init es encontrado, Linux le cede el control de inicialización de procesos -los cuales serán descritos más adelante. Se puede visualizar el momento en el que init ha sido iniciado por el kernel, ya que cuando ésto ocurre se muestra un mensaje tipo "Startting Init 2.86", por poner un ejemplo. Nótese que el comando dmesg no muestra los mensajes pre-init, sino los posteriores.

A partir de ese momento, init toma control de la inicialización de TODOS los procesos post-kernel; es por eso que init es considerado el padre de todos los procesos. Podemos caer en cuenta de esto ejecutando el comando pstree y observar desde dónde viene cada proceso desde el árbol jerárquico superior. Un fragmento de salida podría ser el siguiente:

init-+-abiword
|-4*[agetty]
|-bash---startx---xinit-+-X
|       `-fluxbox-+-gkrellm
|             `-konsole-+-bash---mplayer
|                   |-bash---vim
|                   |-bash
|                   |-bash---man---less
|                   `-bash---pstree

Claramente se puede observar desde dónde provienen cada uno de los procesos, y los procesos ejecutados a través de otros procesos; por ejemplo en este caso la siguiente línea:

|-bash---startx---xinit-+-X

Quiere decir que desde el shell actual (bash) se ha ejecutado el proceso startx que a su vez inicia a xinit y finaliza ejecutando el proceso X -que actualmente se encuentra en ejecución-, y donde bash es un proceso directo de init, como se pudo observar.

Habiendo visto esto vamos a entrar en detalles del por qué y cómo init funciona, dando paso a todos estos procesos. Init crea los procesos leyendo un fichero de configuración que se puede decir que es global, ya que siempre se encuentra en la misma ruta. El fichero /etc/inittab es leído e interpretado por init para la inicialización de los procesos en los denominados run-levels o niveles de ejecución. En inittab, entre otras cosas, se definen varias entradas que causan que init expanda gettys, getty y agetty (comúnmente usados en Linux para abrir un puerto tty, pidiendo login e invoca al ejecutable /bin/login en cada línea para que los usuarios puedan loguearse).

Runlevels o Niveles de Ejecución::

Un runlevel es una configuración del sistema que permite sólo a un grupo de procesos existir. Los procesos que han sido expandidos por init para cada runlevel son definidos en /etc/inittab. Init puede estar en uno de 8 runlevels: 0 al 6 y S, s. El runlevel puede ser cambiado corriendo como usuario privilegiado y corriendo el comando telinit, el cual envía señales apropiadas a init, indicándole a qué runlevel cambiar.

Los runlevels 0, 1 y 6 están reservados. El nivel de ejecución 0 es usado para detener el sistema, el 6 para reiniciarlo, y el 1 para el modo monousuario. El runlevel S no debe ser usado directamente, sólo para los scripts que son ejecutados cuando se está accediendo al runlevel 1.

Despues de que init es ejecutado como el último paso de la secuencia de arranque del kernel, se realiza una búsqueda del inittab en /etc para ver si encuentra una línea del tipo initdefault, la cual establece cuál es el runlevel por defecto o inicial del sistema. Si no existe la entrada o no se encuentra el inittab, un runlevel debe ser establecido en la consola del sistema.

En algunas líneas del inittab debemos tener en cuenta la siguiente sintaxis:

id:runlevels:accion:proceso

Por ejemplo:

1:2345:respawn:/sbin/agetty tty1 9600

En resumen, el ID aquí es 1, el 2345 quiere decir que se inicializará en cualquiera de esos runlevels (recordar que init siempre inicia por defecto en algún runlevel); la palabra respawn quiere decir que el proceso será reiniciado en el momento que sea terminado; /sbin/agetty, en este caso, es el proceso a ejecutar donde se le pasan 2 parámetros requeridos, el ttyX, donde X = número de tty, y la velocidad (en baudios).

Conociendo ya básicamente cómo funciona init, damos paso a la descripción del fichero inittab. Un fichero de ejemplo de este file es el siguiente:

id:3:initdefault:

si::sysinit:/etc/rc.d/init.d/rc sysinit
l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

1:2345:respawn:/sbin/agetty tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600
7:2345:respawn:/sbin/agetty tty7 9600
8:2345:respawn:/sbin/agetty tty8 9600
9:2345:respawn:/sbin/agetty tty9 9600

id:3:initdefault:

Como se mencionaba anteriormente, la entrada initdefault establece el runlevel por defecto que init va a leer posteriormente en el inicio del sistema o con el comando telinit RUNLEVEL, donde RUNLEVEL es un número de 0 a 6 (ej: telinit 3). En este caso, si estuviésemos en las X pasaríamos automáticamente al modo en línea de comandos, ya que normalmente las X se ejecutan en el runlevel 5.

si::sysinit:/etc/rc.d/init.d/rc sysinit

Esta línea es de suma importancia (y varía de una distribución a otra con toda seguridad), es parte del mecanismo que se encarga de inicializar los scripts de arranque (S) y de apagado (K). Por ejemplo, unas líneas del script shell podrán ser las siguientes:

for i in $( ls -v ${rc_base}/rc${runlevel}.d/S* 2> /dev/null)
do
  if [ "${previous}" != "N" ]; then
    suffix=${i#$rc_base/rc$runlevel.d/S[0-9][0-9]}
    stop=$rc_base/rc$runlevel.d/K[0-9][0-9]$suffix
    prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix
    [ -f ${prev_start} ] && [ ! -f ${stop} ] && continue
    fi

Entre otras cosas, dichas líneas se encargan de inicializar lo antes mencionado, scripts de inicio y apagado en sus coincidencias S[números de 0 a 9] o K[lo mismo].

Un detalle a tener en cuenta es el parámetro del final, sysinit, que causara que se ejecute antes que cualquiera de las definiciones boot o bootwait durante el arranque del sistema.

Estas definiciones albergan el mismo significado, sólo que wait quiere decir que el proceso será iniciado cuando el runlevel especificado sea iniciado e init esperara por su finalización.

l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

La siguiente definición quiere decir que se hará cuando se presione la combinación mas conocida del planeta: CTRL + ALT + DEL. Cabe decir que los runlevels 0 y 6 no se incluyen, como es obvio, pues ya estos runlevels de por sí son apagado y reinicio, respectivamente.

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

Estas definiciones ya han sido explicadas, por lo cual no debe haber duda.

1:2345:respawn:/sbin/agetty tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600
7:2345:respawn:/sbin/agetty tty7 9600
8:2345:respawn:/sbin/agetty tty8 9600
9:2345:respawn:/sbin/agetty tty9 9600

Normalmente, los inittab convencionales son algo elaborados, aunque un inittab podría ser lo siguiente y funcionar adecuadamente:

id:1:initdefault:
rc::bootwait:/etc/rc
1:1:respawn:/etc/getty 9600 tty1
2:1:respawn:/etc/getty 9600 tty2
3:1:respawn:/etc/getty 9600 tty3
4:1:respawn:/etc/getty 9600 tty4

Donde bootwait define que será ejecutado al arranque del sistema, mientras que init espera a que termine. El campo de los runlevels será ignorado.

En la parte final de toda esta ejecución, init lee las entradas de aggety o getty y es cuando se nos presenta el prompt de login que todos conocemos (en línea de comandos) algo así como:

========================================
Webdeveloper2 Linux2.6.21.1 tty1 i686
login:
========================================

Funcionamiento y distribución de los scripts de arranque::

Con las bases de todo lo mencionado en el tema anterior veamos cómo, por qué y cuándo serán ejecutados scripts de arranque más comúnmente llamados shells init o scripts de runlevels.

Para comenzar, hay que mencionar el directorio que contiene "casi todos" los scripts de inicio, los cuales serán iniciados en el runlevel al que pertenezcan. Es el dir /etc/init.d, comúnmente usado en distribuciones como Debian, no siendo así en Red Hat, que usa el estilo BSD (muy parecido al estilo del Debian, pero con otra ubicación en los ficheros shell y alguna que otra diferencia, aunque en el fondo se logra básicamente el mismo objetivo).

Se mencionaba "casi todos", pues hay scripts que son "fijos". Esos shells son los que se encargan de montar el sistema de ficheros, chequearlo, iniciar Udev, Limpiar el FS, establecer la consola de Linux, activar la swap, entre otras. Por ejemplo, en una distribución GNU/Linux con estilo de arranque System V al estilo BSD, el directorio /etc/init.d no existe propiamente en ese lugar, sino que se encuentra en /etc/rc.d/init, por lo que los scripts fijos de arranque se encuentran normalmente en el directorio /etc/rc.d/init.d/rcsysinit y los leídos por init antes que ningún otro. Es necesario explicar esto para que se comprenda en caso de confusión al tener contacto con alguna de las dos variantes.

Volviendo a los scripts de runlevel normales, éstos se alojan en /etc/rc.d/init.d o en /etc/init.d, habiendo enlaces simbólicos desde cada directorio, que es identificado por el número del runlevel. La estructura de los dir es la siguiente: /etc/rc.d/rcX.d, donde X es un número de 0 a 6. En el estilo que usa Debian es igual, sólo que se encuentran en /etc/rcX.d. Quedando así más o menos la siguiente estructura en los directorios /etc/ o /etc/rc.d:

- rc0.d
- rc1.d
- rc2.d
- rc3.d
- rc4.d
- rc5.d
- rc6.d

Como se había mencionado antes, los scripts se encuentran en init.d. Ejemplificado, vamos a ver un script real alojando en init.d:

/etc/rc.d/init.d/bind

Donde bind es un shell script de runlevel.

De por sí, bind alojado en init.d no será ejecutado por defecto, sino que tiene que ser enlazado a algún runlevel existente (rc0.d, rc1.d, etc.). Para enlazarlo es necesario conocer qué prioridades y acción tienen los enlaces simbólicos. Digamos que vamos a enlazar a bind al runlevel 3; para esto hacemos:

// ejemplo de enlazar un script a un runlevel para que sea iniciado en el arranque del sistema
cd /etc/rc.d/rc3.d
ln -sv ../init.d/bind S92bind

Esto quiere decir que estamos creando el enlace simbólico S92bind, que apunta al script shell ../init.d/bind.

La norma o sintaxis es muy fácil de comprender: los enlaces que comienzen con S (de start) serán iniciados dependiendo del número que prosiga a la letra, donde los números más bajos tienen mayor prioridad en la ejecución. Todo esto quiere decir que cuando init entre en el runlevel 3 (en el arranque del sistema o poco después) y ejecute todos los enlaces que comienzen con S, llegará el punto en que ejecutará el script del ejemplo anterior.

Como es lógico, los servicios que son iniciados también deben ser detenidos de manera automática cuando el sistema se vaya a reiniciar o apagar. Para ello, en este ejemplo vamos a enlazar a bind en los runlevels 0 y 6 para que se detenga en un reinicio o apagado:

// ejemplo de enlazar un script a un runlevel para que sea detenido
cd /etc/rc.d/rc6.d
ln -sv ../init.d/bind K12bind
cd /etc/rc.d/rc0.d
ln -sv ../init.d/bind K12bind

Aquí la norma es la misma, aunque con una diferencia: los que comiencen con K (de kill) serán detenidos de igual manera que lo antes explicado (la prioridad la tiene el número menor). Habiendo hecho esto aseguramos que si reiniciamos o apagamos se detenga el servicio que se había iniciado en el arranque del sistema.

A continuación un ejemplo del script bind. Algunos detalles sobre qué sucede cuando es S y K y qué tiene que ver con el script.

#!/bin/sh
# script bind.
# dns Bind9 {named}

case "$1" in
  start)
    echo "Iniciando Servidor DNS..."
    /usr/sbin/named -u named -t /srv/named -c /etc/named.conf
    ;;
  stop)
    echo "Deteniendo el Servidor DNS..."
    killall /usr/sbin/named
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  reload)
    echo "Recargando el servidor DNS..."
    /usr/sbin/rndc -c /etc/rndc.conf reload
    ;;
  *)
    echo "Uso: $0 {start|stop|restart|reload}"
    exit 1
    ;;
esac

Esta es la parte interesante. Cuando un enlace comienza con K, init sabe que tiene que matar ese proceso, por lo cual envía al script bind un parámetro de la siguiente manera:

/etc/rc.d/init.d/bind stop

Por el contrario, si comenzara con S sería así:

/etc/rc.d/init.d/bind start

Esto da la medida de cómo funcionan al nivel más básico los scripts de runlevels sin ser el presente documento un manual de programación shell.

La línea case "$1 in" es propia del intérprete de comandos (bash, sh, tcsh, ksh, etc). Lo que quiere decir es "en caso de darse el primer parámetro y que sea igual a los admitidos".

Los parámetros admitidos en este script son start, stop, restart, reload, (los parámetros start y stop son obligatorios). Si deseamos tener un script que sea un auténtico shell de runlevel, el parámetro start es enviado al script al arranque del sistema, así como el stop al apagado o reinicio. Los otros dos son muy usados para recargar la configuración del servicio y reiniciar el servicio, lo cual no se aplica en el inicio, apagado o reinicio por cuestiones lógicas.

Para saber más...

Continuar leyendo

Buffer Overflow: hackeando la pila (II)

EliuX [aorozco@infomed.sld.cu]

El primer ejemplo::

Luego de la introducción previa a los asuntos del Stack, veamos ahora nuestro primer ejemplo en C, porque como dice el dicho: “Vista hace fe”.

Nota: El compilador de C que utilizo es el C++ Builder 6.

Example1.c

void function (int a, int b, int c)
{
  char buffer1[5];
  char buffer2[10];
}

void main()
{
  function(1,2,3);
}


Ahora deberemos coger un desensamblador y tratar de estudiar el código. Es posible que no elijan todos un mismo desensamblador, por lo que decidí explicar los pedazos más importantes en código usando la opción del Builder para ver la CPU, en tiempo de ejecución: View » Debug Windows » CPU.

;las siguientes líneas son fragmentos del código ensamblador del compilado anteriormente en C
;éste se describirá según el orden de ejecución
;cuando se llama a function (1,2,3)
push 0x03 ;meto los parámetros en orden inverso
push 0x02
push 0x01
call function(int, int, int)

;Llamamos al procedimiento function y pushea a la pila el ret
add esp,0x0c ;corro la pila 12 Bytes(3 words) para reservar espacio para los 3 parámetros
;el código en asm de void function (int a, int b, int c) sería
push ebp ;guardo BP (más conocido como el FP guardado)
mv ebp,esp ;muevo el Stack Pointer(SP) hacia el BP, para hacerlo el nuevo FP
;en la siguiente instrucción disminuimos sp en 20, para que la pila crezca (12 decimal = 0x14 hexadecimal) ;así se reservará espacio para las cadenas char buffer1 y char buffer2.
add esp,-0x14

Debemos recordar que la memoria en los procesadores Intel sólo puede ser direccionada en múltiplos de WORD (4 BYTE), por lo que nuestro buffer de 5 (char buffer1[5];) en verdad ocupará 8 BYTE y el de 10 (char buffer2[10];) 12 BYTE. Este es el motivo por el que a SP se le resta 20 BYTE (8+12) cuando se pasan los parámetros a la pila. Veamos cómo quedaría la pila cuando se llama a function:

Un Buffer Overflow es el resultado de poner más datos dentro del buffer de los que se pueden manejar. Como estos bugs de la programación los podemos usar para crear un efecto colateral (BOF) beneficioso a nuestra causa, veamos otro ejemplo:

Example2.c

void function (char *c)
{
  char buffer1[16];
// exactamente 4 WORD, porque cada char es un BYTE
  strcpy(buffer1,c); // copio el contenido del parámetro en el buffer
}
void main()
{
  char large_str[256];
// una línea de 256 caracteres
  int i;
  for( i=0; i< 255; i++)
  large_str[i] = ‘A’;
// la empiezo a llenar
  function(large_str); // cuando llamo a la función, introduzco las 256 “A” en la cadena de 16
}

Para que observe bien lo que pasa, póngale un breakpoint a la línea que dice large_str[i] = 'A'. Luego abra la ventana de CPU (Ctrl + Alt + C) y veamos qué es lo que pasa: Vaya presionando la tecla F8 (Ejecución paso a paso) y observe el cuadro inferior derecho y vea cómo la memoria se va llenando de la letra “A”. Luego quite este breakpoint y cree uno en la declaración de la función void function (char *c) y presione F9 para ir al inicio de la función. Presione F8 una vez para ir a la instrucción strcpy(buffer1,c);. Entonces en la ventana de CPU busquemos en el cuadro inferior izquierdo el buffer large_str que de seguro aparecerá como una columna llena de “A”. Si ejecutamos la siguiente instrucción con un F8, el procesador escribirá 256 elementos (char) a partir de la dirección en memoria de la variable c mediante la instrucción strcpy, la variable c almacenará un carácter “A” según su capacidad y los otros 255 se colocarán a continuación sobrescribiendo registros cómo el FP guardado, los valores de los parámetros (1,2,3) y el RET que almacenaba el valor de retorno de la función. En este momento la memoria quedaría así:

Si presionamos F8 para ver qué se ejecutaría cuando se sale de la función, veremos que el CPU nos lleva a una zona de memoria que no pertenece a nuestro programa (puede estar vacía o no), por lo que el procesador se da cuenta que se está efectuando una violación de segmentación y lanza el mensaje de error siguiente:

Si lo anterior se ha realizado sin problemas, entonces ¡felicidades! Ya has creado tu primer Buffer Overflow.

¿Entonces quiere decir que puedo cambiar el flujo de ejecución del programa? Sí, eso y mucho más ¿No se te ocurre nada que se pudiera hacer con solamente sobrecargar la pila? Pues a mí, infinidades de cosas, partiendo de que se puede machacar un código que se vaya a ejecutar y colocar el nuestro. Por eso vamos a tornarnos más agresivos y modificar nuestro primer código para que sobrescriba la dirección de retorno, y demuestre cómo podemos hacerlo ejecutar un código arbitrario ¡Vamos a ver cómo se crea la magia!

Cojamos como punto de referencia el primer ejemplo. Antes de buffer1 [] está el SP guardado y antes de él la dirección de retorno (RET). Eso es 1 WORD (4 BYTE) pasando la dirección de buffer1 [] que ocupa 2 WORD (8 BYTE) por lo que son 12 BYTE de offset (desplazamiento).

Nuestra misión será modificar el RET para saltarnos el segmento de código x=1;. Para hacer esto agregaremos 8 BYTE a la dirección de retorno. El código a ejecutar es el siguiente:

Ejemplo3.c

void function(int a, int b, int c)
{
  char buffer1[5];
  char buffer2[10];
  int *ret;
// variable apuntadora
  ret= buffer1 + 12;// RET ahora apunta al RET en la pila la dirección de buffer1 offset 12
  (*ret)+=8; // en la aritmética de apuntadores los # que se suman son BYTES, por lo
} // que se le aumenta la dirección a la que apunta RET en 8 BYTE
void main (){
  int x;
  x=’A’;
  function (1,2,3);
  x=’B’;
  printf(“%c\n”,x);
}

Veámoslo en la ventana del CPU ahora, por orden de ejecución, y las partes que se agregaron diferentes al ejemplo 1:

;cuando se ejecuta el código void main{
;main es la función que da inicio a nuestro programa y, como toda función, se realizan
;los mismos pasos iniciales
push ebp ;guardo el fp anterior (recuerda que se guarda en BP)
mov ebp,esp ;corro el bp hacia adelante donde esta el SP
push ecx ;guardo cx el registro contador (irrelevante)
;la instrucción x=0 se codifica
move byte ptr [ebp-0x01],0x00
;fíjense cómo usa el ebp como puntero pase y luego accede a la variable x mediante el offset 0x01
;el signo negativo significa que la variable se encuentra después de ebp, o sea, una una zona de memoria inferior (recuerda que la pila crece hacia zonas inferiores de memoria)
;luego llama a function(1,2,3) y se ejecuta
push ebp ;lo mismo que en todas las funciones
mov ebp,esp ;creo un nuevo FP para apuntar a los variables
add esp,-0x18 ;1word del puntero RET, 2 word de buffer1 y 3 word de buffer2
;la instrucción ret= buffer1 + 12 se codifica
lea eax,[ebp+0x04]
; pongo buffer1 +12 en ax= +0x04 de offset del BP (apunta al RET de function); se hace así porque el CPU interpreta buffer1 como ebp+-0x08 y si le sumamos 12 sería ebp+0x04
mov [ebp-0x18],eax ;muevo el contenido la dirección de buffer1+12 a *ret (el apuntador)
mov edx,[ebp-0x18] ;copio lo que está en *ret a dx (registro usado para direccionar como BP)
add dword ptr [edx],0x08 ;le sumo 8 al contenido que está en la dirección que apunta *ret en dx
mov esp,ebp ;corrijo el SP
pop ebp ;rescato el ebp anterior (FP guardado)
ret ;salgo de la función

;cuando regresa de la función se salta la siguiente instrucción
add esp,0x0c
;para corregir el offset de SP con respecto a los parámetros de la función, pero como no se ejecuta, abra ;después un error de segmentación de pila.
;La instrucción x+=1 se codifica
inc dword ptr [ebp-0x04];el offset de x es el primero (-0x04 de esta función)
;pero como las dos anteriores se saltan se ejecuta la siguiente
printf(“%c\n”,x);
El resultado que se obtendría al final del programa sería la salida en pantalla del 0, puesto que no se ejecutó la línea x=1 y se mantuvo su último valor asignado, que fue el impreso.
¿Ahora sí se les ocurren más cosas para hacer, no? Pues esto no es todo... ¡todavía hay más!

Para saber más...

Continuar leyendo

¡ Infomed !

Alien [blackhat4all@gmail.com]

Antes que nada quisiera pedir disculpas si ven algo de informalidad en este artículo, pero fue escrito en una de esas madrugadas en que mi cuerpo y mi mente, más que a mí, pertenecían a la nicotina y al café.

Sucede que estando yo en lo que considero “red de redes” de Cuba, se me ocurrió entrar a una página a la cual, por supuesto, no debería haber entrado. Era una página de esas de las que requiere una contraseña para poder tener acceso a la misma. Sin otra cosa que hacer que perder el tiempo, me dediqué a estudiar ese tipo de páginas, ver como era su funcionamiento por dentro, su estructura, etc. Desde ese momento me conecté a la página de Infomed que permite ver los correos que nos han enviado, ya que de ese servicio yo sí tengo autenticación y me sería más fácil hacer comparaciones. Una vez que estuve con los típicos letreros de Usuario y Contraseña delante, lo primero que hice fue guardar la página en mi Escritorio (donde pongo las cosas que borraré en menos de tres días) y luego procedí a editarla.

Gran parte del código estaba compuesto por simbologías propias de lenguajes script, pero, aun así, fui capaz de entender algunos fragmentos. Para sorpresa mía no había en ningún trozo de código (de los que logré descifrar), algo que hablara algo sobre password, o contraseña, o alguna palabra clave de esa de la que sabemos se usan. La única instrucción clave que logré entender fue una que decía algo como:

submit_login()

De esta frase, se puede concluir por los paréntesis que es una función, y después de buscar un poco más con los ojos, y menos con los buscadores que traen implementados los editores de texto, encontré dicha función:

function submit_login()
{
  if (document.implogin.imapuser.value == "")
  {
    alert('Provea su nombre de usuario y contraseña');
    document.implogin.imapuser.focus();
    return false;
  }
  else if (document.implogin.pass.value == "")
  {
    alert('Provea su nombre de usuario y contraseña');
    document.implogin.pass.focus();
    return false;
  }
  else
    {return true;}
  }
}

Repito que mi fuerte no son los lenguajes script, pero claramente se ve que lo único que se hace con ella, es retornar false en caso de que los campos de usuario o de contraseña estén vacíos y mostrar un mensaje.

El resto del código era para mí igual de desechable, así que toda la búsqueda había sido en vano. Sin embargo, no se por qué me dio en ese momento por revisar mi correo (siempre hay locos que me escriben de madrugada) y, como casualmente en ese momento estaba conectado, me limité a hacer doble clic en la página que había descargado, con la idea de luego, presionando sobre el botón que valida mis datos, obtener la lista de todos mis mensajes. Sorpresa fue la mía al ver que abriendo dicha página, había perdido todos los colores, el formato, y las palabras Usuario y Contraseña... difícilmente eran legibles para quien nunca había entrado a esta sección.

¿Qué sucedió?
¿Por qué veo las cosas de esta manera?

Fueron las primeras preguntas que me hice. Pude pensar que había modificado algo del código, pero realmente estaba seguro de que lo único que hice fue leer, ya que al cerrarla no me pidió ni siquiera si quería guardar los cambios.

¿Qué podría haber pasado?

En estos líos de edición de la revista he aprendido con ZorphDark algo sobre programación script y cosas por el estilo. Él es una persona realmente "obsesiva" con la limpieza del código y las facilidades que nos brindan las hojas de estilo CSS, así que de forma casi obligatoria he tenido que aprender algo sobre ellas.

El problema de las hojas de estilo, es que para que la página se pueda visualizar correctamente, debe tener a la hoja CSS en su misma dirección o, de lo contrario, especificar desde dónde va a ser cargarda (casi todo el mundo la pone en la misma dirección de la página). Quizás el problema de la pérdida de belleza radicaba en ese aspecto, que el código hacía referencia a una hoja de estilo que estaba en el servidor y a la cual yo, desde mi condición de cliente, no tenía acceso.

¿Cómo hacer referencia a la hoja de estilo?

Al utilizar Firefox como navegador, éste me permite (no sé si Internet Explorer también), entre otras opciones, ver una información bastante detallada de la página en cuestión. Usando esta función pude tener acceso a la dirección en el servidor donde se guarda la hoja de estilo, a la dirección donde es enviado el nombre de usuario y la contraseña que se introduce, el puerto y dominio utilizado, etc. (¡y pensar que todavía hay quienes trabajan con Internet Explorer!). Una vez que tengo los datos necesarios, solo tengo que ir reemplazando por todo el documento las direcciones, y donde dice algo similar a:

<link href="/css.php?app=imp" rel="stylesheet" type="text/css">

Poner:
<link href="http://webmail.sld.cu/css.php?app=imp" rel="stylesheet" type="text/css">

Además de eso yo decidí completar de paso todas aquellas direcciones que iba encontrando entre el código.

Hasta aquí las cosas estaban bien, pero como ya era tan tarde -que podía confundirse con súper temprano- se me antojó seguir... quizás tenía la musa inspirada, y eso no se da todos los días. Quise seguir buscando por todo el código para ver en qué parte podría encontrar lo de la contraseña, pero esta vez busqué con más énfasis, y encontré algo como:

<tr>
  <td class="light" align="right"><b>Usuario</b></td>

  <!-- nótese que no se revela el campo que almacena el nombre del usuario -->
  <td align="left"><input tabindex="1" name="imapuser" value="USUARIO" type="text"></td>
</tr>
<tr>
  <td class="light" align="right"><b>Contraseña</b></td>
  <td align="left"><input tabindex="2" name="pass" type="password"></td>
</tr>

En estas líneas se puede apreciar fácilmente que, según el estilo que tiene la página del correo de Infomed, tiene dos cuadros de texto. Al primero se le pasa el nombre de usuario, y del segundo la única información que se nos da es el tabindex, el name y el type, pero en ningún momento se revela la contraseña (por supuesto), esto es algo que está almacenado en el servidor, pero sólo con reemplazar la línea:

<td align="left"><input tabindex="2" name="pass" type="password"></td>

Con:
<td align="left"><input tabindex="2" name="pass" value=”CONTRASEÑA” type="password"></td>

...al abrir la página sólo tendríamos que hacerle un clic al botón Enviar.

Nota: Ya este archivo no está en el escritorio, desde que vi esto lo pasé inmediatamente para mi otra partición.

Repito, yo no conozco mucho sobre lenguajes script, digamos que no es mi fuerte, pero me pregunto: ¿qué pasaría si una persona con algún diccionario amplio de palabras fuese capaz de generar de forma automática una página con todas estas condiciones y decirle que desde que se cargue envíe la información al servidor? Por supuesto, debería tener además una función que se encargue de verificar si la respuesta es verdadera y, en caso contrario, que cierre página y genere otra seleccionando una palabra distinta entre los posibles passwords. No se asegura que se pueda entrar a todas las cuentas, puesto que hay muchas personas que saben de estos aspectos de seguridad y tienen contraseñas combinadas con números, pero también los hay que siguen poniendo como password “qwerty” (por sólo citar un ejemplo).

Antes de terminar, quisiera dejar bien claro que “NO SÉ DE PROGRAMACIÓN SCRIPT”, lo que hace de este artículo un texto completamente inofensivo. Si existen otras mentes perversas que con los conocimientos adecuados son capaces de hacer cosas detestables luego de leerse esto, ése es su problema.

Para saber más...

Continuar leyendo

Espacio de intercambio

charlie_mtp

En informática, el espacio de intercambio es una zona del disco (un fichero o partición) que se usa para guardar las imágenes de los procesos que no han de mantenerse en memoria física. A este espacio se le suele llamar swap, del inglés "intercambiar".

Descripción::

La mayoría de los sistemas operativos modernos poseen un mecanismo llamado memoria virtual, que permite hacer creer a los programas que tienen más memoria que la disponible realmente (por ejemplo, 4 Gb en un ordenador de 32 bits). Como en realidad no se tiene físicamente toda esa memoria, algunos procesos no podrán ser ubicados en la memoria RAM.

En este caso es cuando es útil el espacio de intercambio: el sistema operativo puede buscar un proceso poco activo, y moverlo al área de intercambio (el disco duro) y de esa forma liberar la memoria principal para cargar otros procesos. Mientras no haga falta, el proceso extraído de memoria puede quedarse en el disco, ya que ahí no gasta memoria física. Cuando sea necesario, el sistema vuelve a hacer un intercambio, pasándolo del disco a memoria RAM. Es un proceso lento (comparado con usar sólo la memoria RAM), pero permite dar la impresión de que hay más memoria disponible.

Implementación::

En realidad, puede ser que no toda la imagen del proceso se lleve al disco. De esta forma, se mantienen algunas partes en memoria principal, mientras que otras permanecen en el almacenamiento secundario.

Si los algoritmos utilizados en el intercambio de páginas están mal diseñados o hay poca memoria disponible, se puede dar un problema conocido como "hiperpaginación" o, en inglés, thrashing. Los síntomas son un atasco y sobrecarga en el sistema; esto se debe a que los procesos continuamente están siendo pasados de memoria física a área de intercambio (porque hace falta memoria para correr otro proceso) y luego otra vez a memoria (porque han de ejecutarse). Aquí vamos a hacer un alto y añadir una observación donde espero que los seguidores de Microsoft no se molesten. Tenemos que dejar claro que en Windows esto no está todo lo bien implementado que pudiera, y el resultado de ésto lo podemos ver cuando en ocasiones estamos sin hacer nada en el ordenador y vemos el bombillo del disco duro encendido (o sea, que está trabajando) y pensamos que está loco o nos preguntamos que estará haciendo. Pues bien, el problema está que Windows es algo nervioso (hiperactivo) y pagina en ocasiones sin necesitarlo. La razón es que cuando el sistema tiene menos de 200 Mb de memoria física libre necesita paginar, y he aquí la explicación de por qué pagina tan seguido.

Posibles ubicaciones::

En los sistemas operativos se puede usar como área de intercambio un fichero o una partición (los dos son en realidad parte de un disco duro o almacenamiento secundario).

Fichero de intercambio:
Un fichero en blanco puede prepararse para ser usado como área de intercambio. Esto tiene una gran ventaja: es fácil de crear, borrar, ampliar o reducir, según se crea necesario (a diferencia de una partición). Pero tiene una desventaja: le afecta la fragmentación, ya que se encuentra dentro de un sistema de ficheros. El problema de la fragmentación no es grave, ya que el espacio de intercambio no siempre es accedido de forma secuencial, sino directa (en oposición a la secuencial).

Partición de intercambio:
También se puede dedicar una partición entera del disco duro (o el disco completo) como área de intercambio. Ventajas: se puede conseguir mejor rendimiento si se coloca la partición en la zona más rápida del disco, que es al principio (los cilindros exteriores del disco, por donde pasan más datos a cada vuelta). No hay problemas de fragmentación y no hay que usar ningún sistema de ficheros en concreto.
Tiene pocas desventajas: crear una partición es un proceso algo difícil; de todas formas, si se elige bien el tamaño de la partición, no hará falta ningún cambio en el futuro la partición siempre ocupará el mismo espacio, aunque no se esté usando al 100%.

Otros dispositivos::

Las tarjetas de video incluyen una memoria, que en los modelos actuales puede llegar a cientos de megabytes; además, son muy rápidas, y no se están usando siempre. Por eso no es extraño que ya se haya intentado usar esta memoria como dispositivo de intercambio (y como almacenamiento genérico). En Linux se puede hacer esto mediante MTD. También ésto se ha hecho con la memoria de una tarjeta de sonido, usando un controlador específico que la convierte en un dispositivo de bloque.

Uso en sistemas operativos::

Cada sistema operativo gestiona la memoria virtual de forma distinta, por tanto, el intercambio depende de la implementación de los algoritmos de intercambio.

En Windows:
Microsoft Windows usa un fichero de intercambio desde su versión 3.1 (1992), la primera en usar memoria virtual. Lo implementa mediante un fichero situado en el directorio raíz (C:\) o en el de sistema ( C:\WINDOWS\), y tiene por nombre: 386SPART.PAR en Windows 3.1; WIN386.SWP en Windows 3.11, 95 y 98; pagefile.sys en Windows NT y sucesores. Este fichero tiene un tamaño variable (depende de la configuración) y no debe ser movido o borrado. Aquí haremos otro alto para añadir que si quiere ver cómo aumenta este archivo, sólo obsérvelo recién iniciada la máquina y más adelante, después de tener varios procesos pesados abiertos. Entonces verá cómo su tamaño aumenta.

Hay una opción para establecer un tamaño fijo para el fichero, pero no es recomendable, porque a veces (cuando se acaba la memoria física y un programa necesita más) hace falta aumentar el tamaño del fichero de intercambio, y si no se puede, no habrá memoria extra para los programas. Si los programas (o el propio Windows) no pueden conseguir la memoria que necesitan, probablemente den fallos extraños. Se puede controlar el tamaño mínimo y el máximo para el fichero. Mientras que aumentar mucho el máximo no hará que funcione mejor, aumentar el mínimo sí que puede ayudar en sistemas que tengan poca memoria RAM.

En Linux:
Linux se suele usar con una partición de intercambio, aunque también permite usar ficheros de intercambio.
Se pueden asignar varios dispositivos de intercambio, incluso de diferentes tipos, y asignar a cada uno una prioridad. Si la prioridad es la misma en varios, las páginas de memoria se distribuirán como en un RAID de nivel 0. Esto permite que los dispositivos de swap se usen en paralelo, cosa que puede aumentar la eficacia, sobre todo si están en discos independientes.

Para crear un área de intercambio en Linux se usa la orden mkswap nombre, donde nombre puede ser un fichero o la ruta a un dispositivo de disco (por ejemplo /dev/hda1). Esto prepara el dispositivo y le pone la cabecera apropiada. Si lo que se está usando es un fichero swap, el contenido puede ser cualquiera (se destruirá), y lo que importa es el tamaño. Pero además, mkswap tiene un requisito especial: el fichero no ha de tener agujeros. Quiere decir que los bytes del fichero han de estar realmente en el disco. Esto no pasa siempre: si se usa cp /dev/zero nuevo, el sistema de ficheros probablemente vea que se trata de un fichero disperso (tiene regiones muy grandes todas con nulos), y no lo grabará realmente en el disco. Al usar algo como dd if=/dev/zero of=nuevo bs=1024 count=65536 se le fuerza a que escriba todos los bloques, sin agujeros. El dispositivo de intercambio se activa con la orden swapon nombre y se desactiva con swapoff nombre. En el fichero /proc/swaps se muestra una lista de los dispositivos de intercambio activos, y en /etc/fstab se suelen añadir las particiones swap que se activan al inicio del sistema. Con el programa free se puede ver, además de cuánta RAM queda libre, el tamaño total de las áreas de intercambio, cuán de llenas están, y cuánta memoria (RAM) se está usando como caché.

¿Hace falta swap?

La memoria de intercambio sirve como RAM adicional. Entonces, en un ordenador que ya tenga mucha memoria RAM, ¿hace falta swap?

Aunque puede funcionar bien sin tener ningún área de intercambio, es muy recomendable crearla. La razón es que siempre es bueno quitar de la memoria los procesos poco usados, ya que eso permite usar la RAM para otras tareas, como por ejemplo, la memoria caché de las operaciones de entrada/salida o el acceso al disco.

Un ejemplo: supongamos que un usuario abre en un programa una imagen muy grande, que le consume el 80% de la memoria RAM, y después, sin cerrarla, se pone a hacer varias búsquedas de ficheros por su disco duro. Si no se puede llevar a disco ese proceso grande, quiere decir que ha de mantenerse en memoria física; por tanto, las búsquedas sólo tendrán menos del 20% de la memoria RAM para hacer de caché, y por eso serán poco eficientes. Con swap, se podría llevar a disco el proceso grande (o al menos una parte), hacer esas búsquedas usando toda la RAM como caché, y luego restaurar el proceso, si hace falta.
Hay algunos procesos que, debido a la función que realizan, están poco activos, y puede ser recomendable que estén en el área de intercambio para liberar un poco la memoria RAM. Por ejemplo, un servidor SSH (mecanismo de control remoto del ordenador) tiene que estar siempre activo para atender las posibles peticiones, pero sólo empezará a trabajar de verdad cuando un usuario se conecte.

Tamaño del espacio de intercambio::

Ésta es una discusión típica entre los administradores de sistemas, y una duda común que aparece durante la instalación de un sistema Linux (o cualquier UNIX). Hay una regla muy conocida que dice que "la swap ha de ser el doble de la memoria RAM instalada", pero esto ya no es válido hoy en día. Esta regla funcionaba bien antes, cuando siempre se compraba menos RAM de la que realmente se necesitaba, porque era muy cara. Tener tres veces más memoria que la física iba bien para la mayoría de usuarios. Pero en un ordenador nuevo que tenga 1 Gb de RAM, no será necesario gastar 2 Gb en una partición de swap, porque probablemente no se usará.

La regla habitual usada para decidir el tamaño del área de intercambio es "pensar en cuánto querrías tener y en cuánto tienes, y poner como swap la diferencia". Por ejemplo, si un usuario necesita abrir ficheros de hasta 700 Mb, pero sólo tiene 256 Mb de RAM, entonces lo que le falta (aproximadamente 500 Mb) se ha de poner como swap, como mínimo. Más swap puede ir bien, pero no será muy usada. Si el ordenador ha de soportar mucha carga, la partición ha de ser mínimamente grande; se recomienda algo más de 128 Mb.

Seguridad::

El espacio de intercambio sirve para guardar, aproximadamente, las mismas cosas que la memoria RAM. Esto incluye información privada, contraseñas, documentos abiertos (aunque no se hayan grabado), etc. Pero con una diferencia: la memoria RAM se pierde al apagar el ordenador; en cambio, la swap no (porque está dentro del disco duro).

Esto hace que sea necesaria una política de borrado de swaps en algunos sistemas donde la privacidad sea importante. Borrar una partición de swap en Linux es muy fácil (sólo hay que escribirla con ceros mediante dd), pero hacerlo manualmente puede ser tedioso, sobre todo porque antes hay que desmontarla y luego volverla a montar.

Otra opción es escribir un código que se ejecute al apagar el ordenador para que haga esto cada vez, cosa que puede ser algo lenta. Existen programas que automatizan estas tareas en varios sistemas operativos.

De todas formas, borrar la swap al apagar no asegura los datos mientras el ordenador está encendido, ya que en el disco habrá información que supuestamente sólo debía estar en memoria RAM. Por eso, en algunos casos se usa un dispositivo de intercambio cifrado, que ofrece más protección, pero, como contrapartida, es mucho más lento. Eso afecta al rendimiento general del sistema, y hace que esta solución sea prohibitiva en el caso general. Naturalmente, también es necesario controlar los permisos de los dispositivos de intercambio, para evitar que usuarios no autorizados puedan leer un fichero de swap, y por tanto la memoria.

Para saber más...

Continuar leyendo

¿Está protegida mi PC?

ZorphDark [blackhat4all@gmail.com]

Actualizaciones semanales -e incluso diarias- del programa antivirus instalado en el sistema, la efectiva configuración de un potente cortafuegos (firewall) que bloquea la entrada y salida de datos por puertos no seguros, la adopción de largas y complejas contraseñas alfanuméricas para el aseguramiento de recursos, la encriptación PGP, el manejo de diversas políticas de seguridad y cualquier otra eficaz medida de control a nivel de software, por más novedosa que sea, no constituye el punto final para lograr la invulnerabilidad de un sistema de cómputo.

Por lo general, al referirse a la seguridad informática, siempre se lleva a un segundo plano las reglas de protección física. Dejando a un lado el hecho de que casi siempre el hardware suele ser más costoso que la información almacenada en su parte lógica, se debe mencionar que el desgaste, la rotura o el robo de cualquier dispositivo central o periférico de una computadora puede arruinar fácilmente cualquier norma de seguridad de datos basada en softwares de protección digital.

Por esa razón, es necesario incluir la custodia y la protección física dentro de los planes de seguridad informática, tanto a nivel institucional o empresarial como en un simple hogar.

Protegiendo el hardware::

La mejor forma de proteger un sistema informático es mediante la prevención. Si se toma en cuenta una serie de medidas que eviten el deterioro, el daño intencional o el hurto de algún dispositivo del hardware instalado, obviamente el nivel de riesgos disminuirá de forma considerable.

Todo informático, administrador de red o persona que esté a cargo de la integridad de una o varias computadoras, debe realizar un estudio general acerca de los peligros físicos existentes relacionados con la geografía y las condiciones del local donde estén instaladas. Las determinaciones que se hayan tomado deben incluirse en el plan de seguridad informática y, consiguientemente, deben ser transmitidas a todas las personas que utilicen esos equipos. Al igual que el hardware, los demás componentes electrónicos que intervienen en el correcto funcionamiento de las computadoras, como los suministros de potencia (UPS), los aires acondicionados y los dispositivos de transmisión de datos (routers, switchs, gateways), deben ser protegidos con cautela.

Peligros y amenazas::

Existen miles de factores que pueden atentar físicamente contra un sistema de equipos de cómputo. Para contribuir a la formación de un riguroso plan de seguridad y control, es necesario destacar un conjunto de propuestas mínimas para la prevención y detección de las amenazas más comunes.

Catástrofes naturales:
El número de medidas que se deben tomar frente a catástrofes de este tipo deben de estar acordes con el nivel de frecuencia y probabilidad de que estas ocurran. En nuestro país los huracanes y ciclones tropicales representan la mayor amenaza, ya que traen consigo poderosas ráfagas de vientos y grandes inundaciones que pueden afectar la integridad del local donde se encuentren ubicados componentes electrónicos e informáticos. Para evitar graves perjuicios, se deben colocar los equipos a una determinada altura. En caso de alerta ciclónica las medidas deben extremarse, alejándolos de ventanas y puertas y, dentro de las posibilidades, ubicándolos en pisos superiores o alejándolos de zonas peligrosas, como presas, ríos, playas, con el objetivo de evitar el riesgo de contacto con el agua por una inundación.

Tormentas eléctricas:
Si el campo electromagnético de un sistema de cómputo se ve afectado por las colosales descargas de este fenómeno, los daños del hardware podrían ocasionar una rotura parcial o total. Aunque los pararrayos pueden evitar la caída de un rayo sobre la estructura metálica del edificio donde se encuentren instalados equipos electrónicos e informáticos, los responsables de su integridad deben apagarlos y desconectarlos de la corriente eléctrica para prevenir cualquier situación irremediable. Uno de los dispositivos más afectados es el módem, por lo que se recomienda desconectarlo de la línea telefónica cuando se termine de utilizar y no transferir información cuando hayan descargas eléctricas.

Incendios:
Todo laboratorio de computación debe contar con un sistema de detección y extinción de incendios, para evitar que algún desastre de este tipo pueda ocasionar más daños. Es necesario que se pongan en práctica medidas que impidan que ocurra un accidente que conlleve a un incendio, como prohibir el fumar, la correcta instalación y la revisión sistemática de la red eléctrica del local.

Fallos eléctricos:
Las afectaciones provocadas por las caídas de tensión, los picos, cortes, entre otros fallos eléctricos, pueden ser evitadas por el uso de sistemas de alimentación eléctrica ininterrumpida (UPS). Además de que el usuario tiene la posibilidad de guardar los documentos abiertos y apagar la computadora correctamente ante cualquier fallo de suministro eléctrico, el hardware queda bien protegido con la ayuda de esos equipos. Una alternativa son los protectores de equipos electrónicos fabricados por GEDEME Electrónica, que se comercializan a costos mucho menores que un back-up en las tiendas del país.

Temperaturas extremas:
El calor excesivo, el aumento de la humedad relativa o el frío intenso pueden dañar con el tiempo los componentes físicos de un equipo informático. Para evitarlo, se deben instalar reguladores y detectores climáticos en los laboratorios de computación. El uso de aires acondicionados es una excelente opción para mantener la temperatura ideal en estos locales, pero un buen ventilador refrescando el monitor y la torre puede utilizarse también para dicha tarea.

Hurtos y atentados:
Un factor que se debe tener muy en cuenta por su alto nivel de riesgo es el aseguramiento del sistema de protección contra robos y otras acciones ilícitas. El cuidado de las computadoras portátiles, de bolsillo y los dispositivos de hardware más pequeños, representan el mayor problema debido a su alto nivel de portabilidad. Para prevenir este tipo de amenaza existen diversos métodos que, con un mayor o menor costo económico, por lo general evitan tener que sufrir pérdidas superiores. Con el objetivo de limitar el acceso a personas no autorizadas al área donde se encuentren instalados los equipos informáticos, es recomendable disponer de un sistema de control. La instalación de un circuito de cámaras y la restricción mediante permisos, llaves o técnicas biométricas (identificación de características físicas o sensoriales de un individuo) son varios ejemplos que se pueden aplicar.

PROTECCIÓN DE LA INFORMACIÓN::

Velar por el mantenimiento en buen estado de los soportes de almacenamiento de información digital es una necesidad y a la vez una obligación de cualquier persona que trabaje con computadoras. A diferencia de los medios tradicionales como el papel, las cintas de audio y de video, los datos acumulados en dispositivos informáticos no pueden ser recuperados cuando hay graves daños físicos en su estructura. Aunque existen eficaces métodos de recuperación de la información ubicada en sectores defectuosos de discos rígidos y extraíbles, cuando ocurre un fallo eléctrico, desgaste o un grave incidente sobre su superficie magnética, es casi seguro que se afecte su integridad, reflejándose en la pérdida total del sistema de archivos.

Puede darse la situación de que las líneas de comunicación que utilicemos para transferir datos sean interferidas por algún motivo. En caso de no poder enfrentarse a tal amenaza a nuestra privacidad, es necesario instalar algún sistema de encriptación de información, ya sea binario (los más seguros) o en modo texto (como el ROT-13).

Por último, es necesario enfatizar que todo individuo que se responsabilice por una o varias computadoras, debe poner a prueba su sistema de seguridad informática, simulando, en la medida de las posibilidades, cualquiera de las situaciones antes expuestas. Una de las vías para estar seguro de uno mismo es siendo capaces de defendernos de ataques provocados por nuestra voluntad. Es preferible ganar una batalla anticipada contra uno mismo que perderla contra quien quiera atacarnos por sorpresa...

Para saber más...

Continuar leyendo

Desfragmentación

charlie_mtp

Seguro muchos de nosotros alguna vez hemos liado con la desfragmentación del disco duro, memoria RAM o simplemente hemos oído hablar de ello. Pues bien, esa fue la idea al escribir este documento: informarnos más acerca de cómo funciona, y espero que sea el primero de una serie de artículos relacionados con el manejo de archivos (principalmente Windows) en disco duro y memoria.

La fragmentación es un problema que surge debido al ordenamiento interno de los datos en algunos sistemas de archivos. Ocurre a menudo en el sistema operativo Windows, aunque también afecta a otras plataformas en una escala mucho menor. También se produce fragmentación dentro de la memoria de la computadora (memoria RAM) cuando se asignan los procesos a los diferentes bloques de memoria. Existen dos tipos de fragmentación:

Fragmentación interna::

Los discos duros tienen un tamaño mínimo de bloque, que es llamado clúster. Este tamaño varía según el sistema de archivos y el tamaño total de la partición. Por eso se sugiere no disponer de un gran tamaño de partición en los discos nuevos donde la capacidad es muy importante (el tamaño será tocado en otro artículo más adelante). Por ejemplo, si nuestro clúster es de 16 Kb (16 384 bytes), por más que un archivo ocupe menos, en nuestro disco ocupará 16 Kb. Esto sugiere una pérdida de ese espacio que dice utilizar, pero no utiliza. Por eso, en nuestro ejemplo, un archivo de 3 Kb ocupará en nuestro disco lo mismo que uno de 10 Kb, o sea, 16 Kb. Esa pérdida de espacio se denomina fragmentación interna y no se corrige con el desfragmentador, sino disminuyendo el tamaño de la partición.

Fragmentación EXTERNA::

Este tipo de fragmentación aparece como consecuencia de las distintas políticas de ajuste de bloques que tiene un sistema de ficheros, o al utilizar asignaciones dinámicas de bloques en el caso de la memoria. En el sistema de ficheros, la sucesiva creación y eliminación de ficheros de distintos tamaños puede conducir al aislamiento de los bloques libres de un disco y, dependiendo de la política de ajuste, su no elección para futuros ficheros. En la memoria del sistema, la fragmentación se produce cuando los procesos asignados han ocupado posiciones no contiguas de memoria dejando demasiados bloques libres de pequeño tamaño, en los que no "caben" nuevos procesos.

En sistemas de ficheros la desfragmentación trata de resolver este problema, alineando los bloques de datos contiguos y juntando los bloques libres, produciendo así fragmentos mayores que sí serán elegidos para futuros ficheros. En la memoria principal se soluciona compactando los procesos para que éstos ocupen posiciones contiguas y dejar los bloques libres juntos, o también se soluciona con la paginación de memoria (este es otro tema que pienso tomar más adelante).

Desfragmentación::

Este proceso consta de ordenar los trozos de información distribuida a través de todo el disco, para mejorar la velocidad de acceso y distribuir de mejor forma el espacio libre del dispositivo. Como este proceso reorganiza partes de archivos, requiere de suficiente memoria para realizar los movimientos de dichos trozos de información. Al mover en forma física la información, la estructura lógica no sufre alteraciones.

Aspectos de la desfragmentación::

En Windows, la presencia de archivos inmovibles del sistema o que el desfragmentador no moverá para simplificar su tarea (sobre todo con el archivo de intercambio o swap file), puede impedir un buen porcentaje de desfragmentación en el disco.

Ciertos sistemas de archivos son más susceptibles a cambios por desfragmentación que otros. Por ejemplo, una partición del tipo FAT se fragmenta más rápido que una de partición del tipo NTFS, ambos propios del sistema Windows. Todo lo contrario ocurre en muchos sistemas de archivos del tipo Unix que no requieren desfragmentaciones en general, debido a que buscan que la fragmentación se mantenga en un punto donde no sea necesario desfragmentar, mediante el uso de nodos de posición.

Utilidades::

Los programas de desfragmentación, por lo general, vienen incorporados al sistema operativo (excepto en Windows NT 4). También existen aplicaciones externas, los cuales poseen opciones más avanzadas que los propuestos por los fabricantes del sistema operativo.
El desfragmentador más conocido es el DEFRAG, que es usado en MS-DOS y en las plataformas de Windows. Puede ser encontrado en las versiones de Windows en Inicio » Programas » Accesorios » Herramientas de Sistema.

Continuar leyendo

lunes, 4 de junio de 2007

e-volución: ¿un futuro superior?

ZorphDark [blackhat4all@gmail.com]

En la década de 1980, tras un largo período de investigaciones, se logró exponer en las pantallas de rayos catódicos imágenes realistas que representaban nuestro mundo. La creación de potentes tarjetas gráficas, la reproducción de sonido digital de alta calidad y el desarrollo de la velocidad de los procesamientos digitales, permitieron la introducción y el progreso de la multimedia en todas las computadoras personales. Esto conllevó a impresionantes mejoras en la concepción y el diseño de sistemas operativos y programas dotados de una interfaz gráfica, además del perfeccionamiento de los videojuegos y aplicaciones que requerían del uso de imágenes y sonido.

El acceso a la computación por parte de un creciente grupo de personas no especializadas en la materia fue posible gracias a esa “explosión” gráfica. Este incremento de usuarios se hizo notar aún más con la aparición de la Web en 1989 y la desenfrenada expansión de Internet en los años 90. El objetivo del desarrollo de la informática y las nuevas tecnologías cambiaba repentinamente su rumbo. Con su corta edad y su escasa madurez, éstas comenzaban a intervenir en todas las esferas de la economía y en gran parte de las sociedades desarrolladas de una forma acelerada.

El nuevo mundo

Mucho antes de haber sido discutida seriamente por los políticos, psicólogos, sociólogos y filósofos, la “nueva era” de la información y las comunicaciones se adentraba con gran fuerza en el quehacer y en el pensar de muchas personas. La nueva generación y una parte importante de los adultos, comenzó a ver el ciberespacio como algo interesante, eficaz, e incluso, como una vía de escape a los problemas cotidianos.

Tras un caudal de estudios e investigaciones a lo largo de muchos siglos por tratar de esclarecer materialmente el mundo que nos rodea, muchos hombres de ciencia, precursores de las tecnologías actuales, nos han dejado el problemático legado de asimilar un nuevo mundo, muy diferente a las concepciones físicas con que se ha interpretado el nuestro. Nos encontramos ahora ante un universo colmado de sorpresas e interrogantes. Con el paso del tiempo, la ciencia ha adquirido nuevas dimensiones: a los científicos que intentan interpretar el mundo real, se le suman aquellos que se convierten en creadores y programadores de nuevos espacios dentro de un vasto territorio poco explotado en relación con sus dimensiones y sus riquezas tecnológicas y filosóficas.

La otra cara…

El problema está en que las nuevas tecnologías se desarrollan mucho más rápido que la conciencia humana. La informática y las redes han permitido un considerable desarrollo de la economía, la educación, la medicina y las comunicaciones, pero ¿hasta dónde? Esta revolución de finales del siglo XX ha sido tan silenciosa como apresurada. Muchos futuristas fanatizan con la idea de que estamos ante una nueva civilización, llena de esplendor y de maravillas, y otros muestran el pesimismo de terminar con una guerra devastadora contra máquinas dotadas de gran inteligencia artificial. La respuesta no está en profetizar, sino en el uso que se le dé a ese potencial tecnológico. Nuestro futuro depende del abandono de los pensamientos con fines bélicos y económicos, que ponen en juego nuestro destino y el fruto de los brillantes logros y descubrimientos a lo largo de la historia de la humanidad.

También es una realidad de que hay que conllevar este desarrollo con el de los países subdesarrollados, que carecen incluso de una energía eléctrica y telefonía que satisfaga las demandas. Se debería pensar seriamente en gastar menos recursos en robots militares y asignar más en ayuda de los que no tienen con qué alimentarse. Pero aún así, en medio de esa desigualdad, hay centenares de logros científicos que ocurren a diario que no se pueden obviar. La puesta en práctica de muchos de ellos puede ser tan dañina como una guerra, por estar financiados por entidades y gobiernos con intereses contrarios al desarrollo de la humanidad. Hay que tener muy en cuenta el uso que se le dé a la inteligencia artificial, a la química y a la genética. Vivimos una etapa muy interesante, donde el hombre ha pasado del modo de interpretación al de creación, y cualquiera de esos novedosos inventos puede acarrear un desastre global. El hombre actual se orienta mucho a lo nuevo, lo desconocido… ¿podrán la ciencia y las tecnologías ayudarnos a corregir el mundo en que nos encontramos? Depende de nosotros, de nuestras ideas y de nuestro esfuerzo.

Creando nuevas entidades

A la par de los biólogos en su afán de creación de organismos genéticamente modificados en el mundo real, los programadores se encuentran inmersos en el desarrollo de otro tipo de entidades, que se diferencian principalmente por no existir físicamente. Se pone en juego nuestra visión material del mundo y nuestro papel como “simples humanos” y no como “dioses”. El esfuerzo de los genetistas y de los cibernéticos continúa siendo un dilema, no sólo por su eficacia, sino, por su lugar en la evolución del hombre y en su futuro inmediato. Concebir clones y organismos al gusto propio de uno es tan interesante y riesgoso como la implementación de inteligencia en entidades mecánicas o virtuales.

Nos alejamos de los tiempos en que los dibujos de paisajes, el cine, las imágenes digitales realistas y las animaciones con efectos especiales eran un arte asombroso. Estamos ahora frente a creaciones artísticas de mayor magnitud. Dejamos de ser espectadores de una obra para convertirnos en creadores de un mundo inimaginable en la actualidad. Con el desarrollo científico-técnico, nuestro espíritu creativo se ha desarrollado aún más, al punto de concebir un ser mitológico y hacerlo realidad en pantallas catódicas, de plasma o en un holograma.

La interactividad de la multimedia ha abierto un portal que nos acerca cada día más a la dimensión de lo “no real” de los bits. El hecho de poder conversar con softwares inteligentes y poder resolver complicados problemas lógico-matemáticos ha brindado un gran impulso a nuestra imaginación, hasta el punto de hacer realidad nuestros pensamientos. La ciencia-ficción es incapaz de predecir hasta donde podrá llegar nuestro ingenio. Este es nuestro presente. ¿Qué será del futuro? ¿Qué sucederá cuando seamos capaces de crear una realidad virtual en la cual podamos adentrarnos y programar nuestro entorno? ¿Qué ocurrirá cuando la ciencia y la biología permitan la incorporación de “mejoras” en nuestro organismo? ¿Qué pasará cuando podamos intervenir en nuestro destino? ¿Nos convertiremos en nuestros propios dioses? Quizás esto no sea un sueño.

Inteligencia artificial ¿hasta qué punto?

Es difícil imaginar que el hombre, que aún no conoce los misterios de su cerebro y la metodología de sus pensamientos, pueda concebir una máquina que iguale su potencial. Algunos creen que para el 2020 podamos tanto viajar a Marte como conversar con una computadora “humanizada”. ¿Qué hay de fantasía o realidad en esto último? Si bien mucho esfuerzo y recursos económicos y financieros podrían poner los pies de un astronauta sobre las arenas de nuestro planeta cercano, la “inteligencia definitiva” del software de un cyborg está un poco distante de cumplirse. El sistema binario no brinda capacidades de cálculo suficientes como para interpretar la lógica de los sentimientos, las decisiones personales y el comportamiento propio de un ser humano. Sería muy difícil e incluso imposible representar nuestro mundo y las más variadas ideas con fórmulas matemáticas.

A pesar de ello, el cómputo con ADN en cuatro estados, la mecánica cuántica, el procesamiento holográfico y los híbridos neurodigitales -que combinan neuronas vivas con chips-, nos alejan de nuestras fronteras y muestras nuevos horizontes dignos de explorar. La velocidad de procesamiento y la capacidad de almacenamiento de las computadoras actuales con la ayuda de la lógica de un cerebro humano sería suficiente para superarnos en todo sentido. ¿Será posible esto? ¿Hasta qué punto?

e-volución: Evolución Electrónica

La instauración de un procesamiento no lineal y multifuncional podría acercarnos un poco al sueño de compartir nuestro mundo con máquinas realmente útiles y autónomas, que tracen metas y tomen decisiones por sí mismas. De este modo nos acercamos a otro problema bien descrito en los libros de ciencia-ficción. Es necesario enfatizar en que nuestra evolución debe ir por encima de la evolución electrónica. De hecho, es hora de que se elabore un esquema de análisis crítico capaz de tener en cuenta los nuevos desafíos que nos impone la ciencia y la técnica, para poder darles un sentido, y de esa forma, ayudarnos a nosotros mismos a trazar un camino seguro por el cual transitar.

La solución no está en frenar o luchar contra la evolución de la ciencia y la tecnología, la creación de robots inteligentes y de organismos genéticamente modificados. Esa no es la vía. Hay que desarrollar libremente el fenómeno Internet, la creación de softwares libres y el intercambio científico sin intereses de otro tipo que no sean el perfeccionamiento del hombre dentro de la sociedad y la naturaleza en que se desenvuelve. Cualquier intento de censura cerrará puertas que no se volverán a abrir o se abrirán del modo incorrecto. Hay que cultivar en todas las personas en las que recaiga el peso de la creación del nuevo mundo (ya sean programadores, políticos, filósofos, económicos, artistas, etc.) una concepción humanista de sus pensamientos.

El ciberespacio, en vez de globalizar el mundo en una idea monopolizadora, entrará a medida que su desarrollo lo permita, en cada una de las culturas e ideologías del planeta, para que la interpretación de la vida y la historia humana tenga lugar en sus más variadas concepciones. La llamada brecha digital es un factor que debe eliminarse para la diversificación de las culturas en Internet. El libre acceso a la información fomentará el desarrollo del “nuevo” y el “viejo” mundo, enriquecerá las mentes más enajenadas y contribuirá en gran medida a la evolución del intelecto humano. Tanto como nadie debe perder en este proceso de cambios el “instinto de lo real”, nadie se debe quedar atrás en la revolución de las tecnologías e información. Debemos estar dispuestos a entrar en este universo de información y conocimientos inagotables con mucha precaución, preparación y deseos de lograr para la especie humana un futuro superior.

Para saber más...

Continuar leyendo