martes, 24 de junio de 2014

Programación dirigida por retorno. (II) - Un ejemplo práctico

Finalicé el post anterior con el compromiso de continuar con un ejemplo práctico de Programación dirigida por retorno.

Pongámonos en un caso extremadamente simple, un programa lee un fichero que contiene dos líneas, la primera es un identificador de sesión (numérico) y la siguiente es una contraseña válida para ese identificador de sesión.

Hay una matriz en la pila que se encarga de recibir ambos valores y coloca en el elemento apuntado por el identificador de sesión el valor la contraseña asociada.

El resto es demasiado sencillo se pregunta si el valor introducido es igual a la entrada que hay en una tabla de contraseñas. Si es igual el procedimiento sigue, si no lo es da un mensaje de error y finaliza.


{
FILE *fd;
int in1,in2;
int arr[20];
char var[20];

if (argc !=2){
printf(mensaje0,*argv);
return -1;
}
fd = fopen(argv[1],"r");
if(fd == NULL)
{
fprintf(stderr,mensaje1);
return -2;
}
memset(var,7,sizeof(var));
memset(arr,6,20*sizeof(int));
while(fgets(var,20,fd))
{
in1 = atoll(var);
fgets(var,20,fd);
in2 = atoll(var);
/* fill array */
arr[in1]=in2;
//printf("%d - %d\n", arr[in1], tabla[in1]);
if (arr[in1] != tabla[in1])
{
printf("La coordenada no es correcta\n");
return ;
}
printf("La coordenada es correcta\n");
printf(mensaje4);
return;
}
}



Esto está así por simplicidad. En un sistema más complejo la tabla de valores estaría fuera del programa y al menos procesada mediante un algoritmo de hashing. Pero todo este tema nos da un poco igual porque lo que a nosotros nos interesa simplemente dirigir el retorno.





He tomado algunas libertades para hacer más sencillo y comprensible el programa el programa:

Unos campos de memoria de relleno para simplificar los cálculos:



Unas inicializaciones de memoria raras. Lo correcto habría sido inicializarlas a 0x00 pero las he inicializado con los valores 6 y 7 para que nos sea más fácil de identificar en la pila.



Arrancamos Ollydbg y cargamos el programa compilado. Con la información que nos suministra este depurador podemos localizar en que punto está la verificación de la clave correcta: 

if (arr[in1] != tabla[in1])




Y colocamos un breakpoint en este punto.

Como los datos los tenemos en un fichero lo primero que tenemos que hacer es indicar a Ollydbg cuales el argumento de entrada. Lo realizamos desde el menú Debug -> Arguments

Ponemos el nombre del fichero que queramos  que previamente habremos creado con los siguientes valores:

2
93

Ejecutamos hasta que se pare y comprobamos los valores de los registros EAX y EDX. Al ser iguales el programa continúa en la direccion 0x004017F2 (la contraseña es correcta).



Si cargamos el fichero con otros valores:

2
95

Y ejecutamos, cuando se pare el programa podemos ver que los  valores de los registros EAX y EDX sin distintos. El programa da el mensaje de aviso y llega a la instrucción return.

El objetivo, que veremos en la próxima entrada es alterar el contenido de la pila para que nos lleve a la instrucción 0x004017F2 y poder continuar le ejecución del programa como si la contraseña hubiera sido correcta.







No hay comentarios:

Publicar un comentario