Ayuda con este codigo.

Iniciado por 0xDani, 6 Agosto 2012, 14:54 PM

0 Miembros y 1 Visitante están viendo este tema.

0xDani

Bueno estoy leyendo un codigo que un usuario posteo hace poco y que decia que era un jailbreak de la ps3 o algo asi. Bueno el caso es que hay algunas partes del codigo que no llego a entender. Las dejo aqui por si alguien me puede ayudar.

Antes de poner codigo, aclaro que u8 es un typedef de char, u16 de unsigned short, u32 de unsigned int y u64 de unsigned long long.

La primera:
Aqui aparece la estuctura elf_hdr, no la pongo para no ocupar mas espacio.
int elf_read_hdr(u8 *hdr, struct elf_hdr *h)
{
int arch64;
memcpy(h->e_ident, hdr, 16);
hdr += 16;

arch64 = h->e_ident[4] == 2;

h->e_type = be16(hdr);
hdr += 2;
h->e_machine = be16(hdr);
hdr += 2;
h->e_version = be32(hdr);
hdr += 4;

if (arch64) {
h->e_entry = be64(hdr);
h->e_phoff = be64(hdr + 8);
h->e_shoff = be64(hdr + 16);
hdr += 24;
} else {
h->e_entry = be32(hdr);
h->e_phoff = be32(hdr + 4);
h->e_shoff = be32(hdr + 8);
hdr += 12;
}

h->e_flags = be32(hdr);
hdr += 4;

h->e_ehsize = be16(hdr);
hdr += 2;
h->e_phentsize = be16(hdr);
hdr += 2;
h->e_phnum = be16(hdr);
hdr += 2;
h->e_shentsize = be16(hdr);
hdr += 2;
h->e_shnum = be16(hdr);
hdr += 2;
h->e_shtrndx = be16(hdr);

return arch64;
}


Las funciones be16, be32 y be64 estan aqui:
static inline u16 be16(u8 *p)
{
u16 a;

a  = p[0] << 8;
a |= p[1];

return a;
}

static inline u32 be32(u8 *p)
{
u32 a;

a  = p[0] << 24;
a |= p[1] << 16;
a |= p[2] <<  8;
a |= p[3] <<  0;

return a;
}

static inline u64 be64(u8 *p)
{
u32 a, b;

a = be32(p);
b = be32(p + 4);

return ((u64)a<<32) | b;
}


En realidad lo que menos entiendo son las funciones be16, be32 y be64. Y por si alguien va a decirme que no espere que me hagan la tarea, tambien aclaro que esto solo es una parte de un codigo mucho mas grande(foro.elhacker.net/dudas_generales/iquestalguien_me_podria_hacer_el_gran_favor_de_pasar_esto_a_exe-
t368531.0.html).

Saludos.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM

Foxy Rider

A ver .... vamos por partes, por que el código no tiene comentarios, lo que requiere leerlo más detenidamente.

1) elf_read_hdr()
Es una función que lee el encabezado de un fichero en formato binario ELF (el análogo en Windows es .exe o mejor dicho: PE), el código es medio feito por que tiene funciones helpers que no están descritas y con nombres "feos".
Pero básicamente esas funciones convierten de diversas notaciones (como un array de unsigned chars a un unsigned de 32 bits ... misma cantidad de bits y mismos bits per sé, diferente forma de almacenar en memoria .. por ejemplo)

Por lo que tendrías que leer, es algo sobre el formato ELF ( acá tenés una ayuda con eso ... pero nótese que es una lectura BÁSICA y que tenés que sumar otras)

2) be16(), be32(), be64()

2.A) Vamos a la declaración:

static inline u16 be16(u8 *p)

voy a ignorar static e inline, y vamos a lo que importa.
la función toma un puntero a u8 (u8 está definido como unsigned char ... lógico, u8 significa unsigned 8 bits, bits es justamente lo que pesa un char en memoria) y retorna un unsigned de 16 bits (un "short", 2 bytes, el doble de un char).

Así que, para juntar los 16 bits para retornarlos en u16, desde el vamos sabemos que necesitamos 2 u8 ... 2 elementos de 8 bits suman 16.
Ahora, ¿por qué unsigned pensarás? bien, acá quiero hacer un stop y primero hacemos una clase básica sobre los tipos de datos y el signo:

2.B) Hagamos un inciso sobre tipos y signos
Las variables que tienen signo (todas lo tienen, el compilador lo asume salvo que las marques unsigned), en memoria, se le "roba" un bit mara marcar el signo (ese bit si está como 1, o true, es negativo, sino no). Por ejemplo, un byte son 8 bits, y si tuviese o no signo, nos deja con esta situación:

0 0 0 0 0 0 0 0 = 8 bits para usar (2^8 es nuestro rango de números ... lógico, 256 !) ... y ni un bit usado para el signo

0 0 0 0 0 0 0 0 = 7 bits para usar y uno reservado para el signo (2^7 es nuestro "rango" de números ... con 7 bits representamos un rango de 128, sin importar el signo, que eso lo marca el bit restante )

Ese "bit reservado" para el signo puede estar de un lado y otro, depende del "endianess", y es algo que no pienso cubrir acá, pero te lo nombro para que lo busques.

2.C) Retomemos

Sabiendo que u8 representa 8 bits precisos (por eso el unsigned, no "robamos" un bit para el signo) y u16 representa 16. ahora pasemos a analizar el código:

1) u8 es un puntero, como ves más abajo, en realidad se espera que este puntero albergue dos elementos (algo equivalente a "u8 dato[2]"), bien ... 2 unsigned de 8 bits (son 16)

2) Operaciones con bits (lo resaltado)

Código (c,3,4) [Seleccionar]
u16 a;

a  = p[0] << 8;
a |= p[1];

return a;


La primer línea resaltada lo que usa es el operador de bit shift, básicamente tenemos dos operadores de bit shift :


  • <<
  • >>

Básicamente, lo que hacen es "correr" los bits para un lado u otro (¿las flechitas te sugirieron algo?), y todo lo que "quede afuera" (por que podés correr hasta donde aguante el tipo de dato sin perder nada), se trunca, veamoslo de manera gráfica con este pseudocódigo con una variable de 8 bits:


X = 0 1 1 0 0 0 0 1
X << 3


Tenemos que "corremos" los bits de X tres lugares a la izquierda, el nuevo X vale esto:

0 0 0 0 1 0 0 0

Todos los otros 1, se corrieron "de más" a la izquierda, y se perdieron ... se entiende el concepto? Otro ejemplo menos radical con el destino de los bits:

X = 0 1 1 0 0 0 0 1
X << 1


X queda :

X = 1 1 0 0 0 0 1 0

Ok, avanzamos ... Como no podemos hacer  "a = p", tenemos que meter los dos 8 bits en la variable de 16 bits.
por lo que tenemos que "correr" bits para encajarlos en la parte izquierda y derecha de "a".
básicamente metemos los primeros 8 bits, los enviamos a la izquierda, y metemos los otros 8 bits, veamoslo:

A = 0 1 1 0 1 0 1 0 (8bits)
B = 0 0 0 0 0 1 0 1 (8bits)
C = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 (16 bits)

C = A (C vale A, y todos los bits de A pensa que estan a la derecha)
C << 8 (los corremos a la izquierda, ahora A quedo en el lado izquierdo de C, el resto es 0, obvio)

C |= B // Esto nos interesa



Lo que marqué ahí es un operador con bits, y es un operador de suma (or), básicamente esto significa C es igual a C, más los bits ( | ) de B, que pensá que irían a la derecha ... vuelan los 8 bits de la derecha (que no tenían nada importante), y los 8 de la izquierda que dejamos desde el shift, quedan ... se entiende?
C quedaría compuesto de A y B ... A llendo a la izquierda y B a la derecha.

Un sumario de los operadores de bit y bit shift → http://www.cprogramming.com/tutorial/bitwise_operators.html
Y con eso podrías entender las otras funciones.

Saludos.

0xDani

Absolutamente genial tu explicacion!! Lo he entedido mucho mejor que antes. El mayor problema que tenia es que no he encontrado nada de informacion sobre el operador |=. Tambien decir que los nombres de esas 3 funciones no eran muy descriptivos, y eso termino de confundirme. Bueno, voy a leer el articulo sobre el formato ELF, y a ver si me entero yo solo de lo que es el "endianess".
Y sobre la explicacion te agradezco mucho el esfuerzo de hacerla tan completa(y digerible :xD).

Saludos.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM

Foxy Rider

CitarEl mayor problema que tenia es que no he encontrado nada de informacion sobre el operador |=

Acá tenés un machete de los operadores y su precedencia → http://en.cppreference.com/w/c/language/operator_precedence
|= es como+=, pero es usando el "or" en vez que "+".

CitarBueno, voy a leer el articulo sobre el formato ELF, y a ver si me entero yo solo de lo que es el "endianess".

A medida de que vayas leyendo lo que linkee, lo que te mencioné, y el Google vaya fluyendo ... todo se vá a ir conectando, de todas formas, ante cualquier duda, postee nomás.

Saludos ♥