Pokemon Real

Llevo sin jugar al pokemon, desde que tenía la game boy gorda, la que venía con el tetris xD. Ya entonces me envicio exagerado, solo me falto el mewtwo de los cojones xDD y el mew que decian que no se podía capturar.

A mi novia le han regalado la ds con 2 juegos de pokemon, hemos empezado a jugar al diamante y joder, es buenisimo xD Tambien es verdad que no tenemos la ds pirateada -_- ….

En relación, os dejo con un video buenisimo y subtitulado:

Sony = pWn3d!

Ayer me llama mi novia diciendo, que ha visto en las noticias un bug en la playstation 3 y ha provado su consola (la gorda), y esta afectada. OMG!

El bug consiste en que en el algún momento entre el 28 de febrero y 1 de marzo todas las ps3 del mundo petaron. Es curioso que no importe la región, esto indica que es un bug del reloj interno que va con GMT +0.

Ayer sobre las 23:00 ya salimos del 29 bisiesto virtual en el que estaban todos los relojes internos del mundo y era muy posible que se arreglara el solo, sin parchear nada. Y así ha sido, las consolas han vuelto a funcionar hoy, simplemente corrigiendo el día.

El reloj interno es una marca de tiempo que se utiliza para cuando por ejemplo compras contenido DRM, como peliculas durante 24 horas. Se graba la marca de tiempo del reloj interno y se suma un offset de 24 horas, independientemente de la región. Sino se hiciera asi, podríamos quedarnos la película más de 24 de horas si estuvieramos retrasando el reloj continuamente.

Yo pienso que precisamente por eso, no se ha permitido conectar a PSN, además de por todas las incoherencias en logros, principalmente por evitar comprar contenido DRM en sistemas bugeados.

Le dejo a Sony una mini práctica que hice en primero para mostrar el calendario de cualquier año (>=1) o para para mostrar el mes actual:

program Actividad3;
{
Actividad 3
por Ricardo Marmolejo García
1º Ingienería Técnica Informática de Gestión
}

uses crt,dos;

const
   ANCHO_COL = 4;

var
   eleccion:integer;
   que_ano:integer;
   eleccion_str:string;
   que_ano_str:string;
   error:integer;

{
Funciones utilizadas en actividades anteriores:
pintar_marco()
mostrar_texto_centrado()
pintar_creditos()
}

procedure pintar_marco(x1,y1,ancho,alto:byte);
var
   x,y:byte;
   x2,y2:byte;
const
   DOBLE_BARRA_VERTICAL=186;
   DOBLE_BARRA_HORIZONTAL=205;
   ESQUINA_SUPERIOR_IZQUIERDA=201;
   ESQUINA_SUPERIOR_DERECHA=187;
   ESQUINA_INFERIOR_IZQUIERDA=200;
   ESQUINA_INFERIOR_DERECHA=188;

begin
   x2 := x1 + ancho;
   y2 := y1 + alto;

   for x := (x1+1) to (x2-1) do
   begin
      gotoxy(x,y1);
      write(chr(DOBLE_BARRA_HORIZONTAL));
      gotoxy(x,y2);
      write(chr(DOBLE_BARRA_HORIZONTAL));
   end;

   for y := (y1+1) to (y2-1) do
   begin
      gotoxy(x1,y);
      write(chr(DOBLE_BARRA_VERTICAL));
      gotoxy(x2,y);
      write(chr(DOBLE_BARRA_VERTICAL));
   end;

   gotoxy(x1,y1);
   write(chr(ESQUINA_SUPERIOR_IZQUIERDA));
   gotoxy(x2,y1);
   write(chr(ESQUINA_SUPERIOR_DERECHA));
   gotoxy(x1,y2);
   write(chr(ESQUINA_INFERIOR_IZQUIERDA));
   gotoxy(x2,y2);
   write(chr(ESQUINA_INFERIOR_DERECHA));
end;

procedure mostrar_texto_centrado(texto:string;altura:byte);
var
   centro_pantalla,centro_texto:byte;
const
   ANCHO_PANTALLA = 80;
begin
   centro_pantalla := ANCHO_PANTALLA DIV 2;
   centro_texto := length(texto) DIV 2;

   gotoxy(centro_pantalla - centro_texto , altura);
   write(texto);
end;

procedure pintar_creditos();
begin
   textcolor(8);
   mostrar_texto_centrado('ACTIVIDAD 3',23);
   mostrar_texto_centrado(CONCAT('por Ricardo Marmolejo Garc',chr(161),'a - 2006'),24);
   textcolor(15);
end;

////////////////////////////////////////////////////////////////////////////////

function esBisiesto(ano:integer):boolean;
{
ENTRADA: año que queremos evaluar
SALIDA: booleana
OBJETIVO: Nos dice si un año es bisiesto o no
}
begin
   esBisiesto := (ano MOD 4 = 0) AND ((ano MOD 100 <> 0) OR (ano MOD 400 = 0));
end;

function getLimiteDeEsteMes(mes:byte;ano:integer):byte;
{
ENTRADA: mes y ano
SALIDA: Nos devuelve el número del último dia del mes
OBJETIVO: Nos permite obtener el límite de cada mes
}
begin
   case mes of
      1:getLimiteDeEsteMes := 31;
      2:if(esBisiesto(ano)) then
          getLimiteDeEsteMes := 29
        else
          getLimiteDeEsteMes := 28;
      3:getLimiteDeEsteMes := 31;
      4:getLimiteDeEsteMes := 30;
      5:getLimiteDeEsteMes := 31;
      6:getLimiteDeEsteMes := 30;
      7:getLimiteDeEsteMes := 31;
      8:getLimiteDeEsteMes := 31;
      9:getLimiteDeEsteMes := 30;
      10:getLimiteDeEsteMes := 31;
      11:getLimiteDeEsteMes := 30;
      12:getLimiteDeEsteMes := 31;
   end;
end;

procedure parchear_diasemana(VAR diasemana:WORD);
{
ENTRADA: dia de la semana
OBJETIVO: si es domingo cambia el 0 a 7 quedando definido de 1-7
}
begin
   if(diasemana = 0) then
     diasemana := 7;
end;

function imprimir_un_mes(INICIO,FIN,diasemana,mes:byte):byte;
{
ENTRADA:
INICIO -----> inicio por el que comienza el mes , lo lógico es que sea 1 o el dia actual
FIN --------> fin para el mes , suele venir dado por getLimiteDeEsteMes()
diasemana --> dia de la semana del 1-7 en que comienza el mes
mes --------> del 1-12 mes que se va a imprimir
SALIDA:       dia de la semana del siguiente mes , con esto si llamamos reiteradas veces a esta función
              encadenamos los meses y lo que hacemos es imprimir un calendario
OBJETIVO: imprimir un mes
}
var
     i:byte;
     nombre_mes:string;
     ano_actual,mes_actual,dia_actual,diasemana_actual:word;

   function getNombreMes(mes:byte):string;
   {
   ENTRADA: mes del 1 al 12
   SALIDA: Nombre en String del mes
   OBJETIVO: Crea una relación del número del mes con su nombre
   }
   begin
      case mes of
         1:getNombreMes := 'Enero';
         2:getNombreMes := 'Febrero';
         3:getNombreMes := 'Marzo';
         4:getNombreMes := 'Abril';
         5:getNombreMes := 'Mayo';
         6:getNombreMes := 'Junio';
         7:getNombreMes := 'Julio';
         8:getNombreMes := 'Agosto';
         9:getNombreMes := 'Septiembre';
         10:getNombreMes := 'Octubre';
         11:getNombreMes := 'Noviembre';
         12:getNombreMes := 'Diciembre';
      end;
   end;

   procedure mostrar_cabezera_de_un_mes(titulo_del_mes:string);
   {
   ENTRADA: Entregamos el String del mes
   OBJETIVO: Nos muestra una cabezera del mes
   }
   begin
      writeln;
      writeln;
      textcolor(14);
      writeln(UPCASE(titulo_del_mes):ANCHO_COL*5);
      textcolor(7);
      writeln;
      write('   L   M   X   J   V   S');
      textcolor(12);
      writeln('   D');
      textcolor(15);
      writeln;
   end;

   procedure tabular_en_funcion_del_dia_de_la_semana(diasemana:byte);
   {
   ENTRADA: dia de la semana
   OBJETIVO: Nos tabula los meses para que cuadren los dias de la semana
            si empezamos en 1 (lunes) hay 0 tabulaciones
            si empezamos en 2 (martes) hay 1 tabulaciones
            si empezamos en 3 (miercoles) hay 2 tabulaciones
            si empezamos en 4 (jueves) hay 3 tabulaciones
            ...
            si empezamos en n hay (n-1) tabulaciones
   }
   var
      i:byte;
   begin
      for i:=1 to diasemana-1 do
          write('':ANCHO_COL);
   end;
begin
   GetDate(ano_actual,mes_actual,dia_actual,diasemana_actual);
   parchear_diasemana(diasemana_actual);
   nombre_mes := getNombreMes(mes);
   mostrar_cabezera_de_un_mes(nombre_mes);
   tabular_en_funcion_del_dia_de_la_semana(diasemana);
   for i:=INICIO to FIN do
   begin
      textcolor(15);
      // aqui no miro año , asi que puede ocurrir que coloree el dia de un año que tenga el mismo dia de la semana
      if(i = dia_actual) AND (mes = mes_actual) AND (diasemana = diasemana_actual) then
          textcolor(10)
      else if(diasemana = 7) then
          textcolor(12);

      write(i:ANCHO_COL);

      if(diasemana = 7) then
      begin
           writeln;
           diasemana := 1;
      end
      else
          diasemana := succ(diasemana);
   end;
   imprimir_un_mes := diasemana;
end;

procedure imprimir_calendario(que_ano:integer);
{
ENTRADA: Año del calendario que quieres ver
OBJETIVO: Mostrar el calendario
}
var
   i:byte;
   diasemana:byte;

  function CalcularPrimerDiaDeLaSemanaDeUnAno(ano:integer):byte;
  {
Esta función me ha costado pensarlo y no se si esta bien , he supuesto lo siguiente :
He observado que el 1 de enero del 2005 es Sabado(6) , el 1 de enero del 2006 es domingo (7),
el 1 de enero del 2007 es lunes (1) , el 1 de enero del 2008(bisiesto) es miercoles(3) (se ha saltado el martes)
de aqui deduzco una función recursiva. Supongo que el año 1 empieze en lunes ,(realmente empeze con 2006)
El año 2 se define:
   si el año anterior a 2 es bisiesto entonces
      El año 2 sera el año anterior a 2 + 2
   sino (no es bisiesto)
      El año sera el año anterior + 1
Para reiniciar al llegar a domindo uso MOD 7
Con esto consigo esta sucesión : 1 , 2 , 3 , 4  , 6 , 7 , 1 , 2 , 4  , 5 , 6 , 7 , 2 , 3 ...
Consigo definir todos los dias de la semana de los unos de eneros del año 1 en adelante
  ENTRADA: año
  SALIDA: dia de la semana del año introducido
  OBJETIVO: Al imprimir el calendario de un año , para definir este año solo necesito saber el dia de la semana del 1 de enero
  }
  begin
     if (ano <= 1) then         CalcularPrimerDiaDeLaSemanaDeUnAno := 1      else         if(esBisiesto(ano-1)) then           CalcularPrimerDiaDeLaSemanaDeUnAno := CalcularPrimerDiaDeLaSemanaDeUnAno(ano-1) + 2         else           CalcularPrimerDiaDeLaSemanaDeUnAno := CalcularPrimerDiaDeLaSemanaDeUnAno(ano-1) + 1;       if CalcularPrimerDiaDeLaSemanaDeUnAno > 7 then
          CalcularPrimerDiaDeLaSemanaDeUnAno := CalcularPrimerDiaDeLaSemanaDeUnAno MOD 7;
  end;

   procedure imprimir_cabezera_calendario();
   {
   OBJETIVO : Imprime un Titulo en color , indicando el AÑO
   }
   begin
      writeln;
      textcolor(10);
      writeln('               A',chr(164),'o ',que_ano);
      textcolor(15);
   end;

begin
   diasemana := CalcularPrimerDiaDeLaSemanaDeUnAno(que_ano);
   imprimir_cabezera_calendario();
   for i:= 1 to 12 do
     diasemana := imprimir_un_mes(1,getLimiteDeEsteMes(i,que_ano),diasemana,i);
end;

procedure imprimir_desde_HOY_hasta_el_proximo_mes();
{
OBJETIVO: Imprime un periodo aproximado de un mes , exactamente desde el dia X del mes actual
hasta el dia X del siguiente mes
}
var
   ano,mes,dia,diasemana:word;

   function getProximoMes(mes:integer):byte;
   {
   ENTRADA : Mes de referencia
   SALIDA : Siguiente mes respecto al mes de referencia
   OBJETIVO : Saber el proximo mes
   }
   begin
      if(mes = 12) then getProximoMes := 1
      else if(mes > 12) then getProximoMes := mes MOD 12
      else getProximoMes := mes+1;
   end;
begin
   GetDate(ano,mes,dia,diasemana);
   parchear_diasemana(diasemana);

   // imprimo el actual mes
   diasemana := imprimir_un_mes(dia, getLimiteDeEsteMes(mes,ano) , diasemana , mes               );
   // imprimo el proximo mes , sabiendo el dia de la semana que me devolvio la anterior
                imprimir_un_mes(1  , dia                         , diasemana , getProximoMes(mes));
end;

begin
   repeat
      clrscr;
      textcolor(15);
      pintar_marco(10,5,60,15);
      gotoxy(15,8);   writeln('1 . Imprimir un MES desde hoy hasta el proximo mes');
      gotoxy(15,10);  writeln('2 . Imprimir un calendario');
      gotoxy(15,12);  writeln('3 . Salir');
      pintar_creditos();
      gotoxy(15,16);
      write('Elije una opcion [1-3] : ');
      readln(eleccion_str);
      val(eleccion_str,eleccion,error);
      clrscr;
         case eleccion of
            1:
            begin
                 imprimir_desde_HOY_hasta_el_proximo_mes();
                 readkey;
            end;
            2:
            begin
                 writeln('Calendario del a',chr(164),'o ? (mayor o igual que a',chr(164),'o 1) : ');
                 readln(que_ano_str);
                 val(que_ano_str,que_ano,error);
                 if(error = 1) OR (que_ano < 1) then que_ano := 1;
                 clrscr;
                 imprimir_calendario(que_ano);
                 writeln;writeln;
                 readkey;
            end;
            3://salir
            else
            begin
                 mostrar_texto_centrado('Opcion incorrecta',10);
                 readkey;
            end;
         end;
   until(eleccion = 3);
end.

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

Espacios en for i in $(ls)

#!/bin/sh

IFS=$'\x0A'$'\x0D' ;
for i in $(find -iname "*.avi"); do
mv -v "$i" . ;
done;

Chuleta:  Para que el for no considere el espacio un separador, y una tarea como la del ejemplo lo realize bien. El script de ejemplo mueve todos los videos de subcarpetas al directorio actual.

31 Personajes de videojuegos «reales»

Peligro: Este post tiene alto contenido geek
He encontrado un post por halloween con 31 imagenes(dia 31 y tal) de gente que se disfraza de protagonistas de juegazos :P. Os pongo 3 de ejemplo, dejo el link al final.

Fuente:
http://www.slobsofgaming.com/article/104754/31-amazing-video-game-costumes/