televia tag saldo recargas recargar recarga que puede paga oxxo movil donde ld glibc dynamic-linking fortify-source

ld - tag - televia



¿Puedo engañar a libc(GLIBC_2.13) para que cargue un símbolo que no tiene(de GLIBC_2.15)? (2)

En mi intento de hacer que "Steam for Linux" funcione en Debian, me he encontrado con un problema. libcef (Chromium Embedded Framework) funciona bien con GLIBC_2.13 (que puede proporcionar eglibc en Debian testing), pero requiere una función extra pequeña de GLIBC_2.15 (que eglibc no puede proporcionar):

$ readelf -s libcef.so | grep -E "@GLIBC_2/.1[4567]" 1037: 00000000 0 FUNC GLOBAL DEFAULT UND __fdelt_chk@GLIBC_2.15 (49) 2733: 00000000 0 FUNC GLOBAL DEFAULT UND __fdelt_chk@@GLIBC_2.15

Mi plan de ataque aquí fue para LD_PRELOAD una biblioteca shim que proporciona solo estas funciones. Esto no parece funcionar. Realmente quiero evitar la instalación de GLIBC_2.17 (ya que está en la GLIBC_2.17 experimental de Debian; incluso el sid de Debian todavía tiene GLIBC_2.13 ).

Esto es lo que he intentado.

fdelt_chk.c se roba básicamente de la biblioteca GNU C :

#include <sys/select.h> # define strong_alias(name, aliasname) _strong_alias(name, aliasname) # define _strong_alias(name, aliasname) / extern __typeof (name) aliasname __attribute__ ((alias (#name))); unsigned long int __fdelt_chk (unsigned long int d) { if (d >= FD_SETSIZE) __chk_fail (); return d / __NFDBITS; } strong_alias (__fdelt_chk, __fdelt_warn)

El script de mi Versions tiene el siguiente aspecto:

GLIBC_2.15 { __fdelt_chk; __fdelt_warn; };

Luego construyo la biblioteca de la siguiente manera:

$ gcc -m32 -c -fPIC fdelt_chk.c -o fdelt_chk.o $ gcc -m32 -shared -nostartfiles -Wl,-s -Wl,--version-script Versions -o fdelt_chk.so fdelt_chk.o

Sin embargo, si ejecuto Steam (con un montón de cosas adicionales para que funcione en primer lugar), el cargador aún se niega a encontrar el símbolo:

% LD_LIBRARY_PATH="/home/tinctorius/.local/share/Steam/ubuntu12_32" LD_PRELOAD=./fdelt_chk.so:./steamui.so ./steam ./steam: /lib/i386-linux-gnu/i686/cmov/libc.so.6: version `GLIBC_2.15'' not found (required by /home/tinctorius/.local/share/Steam/ubuntu12_32/libcef.so)

Sin embargo, el símbolo de versión también es proporcionado por el .so que acabo de construir:

% readelf -s fdelt_chk.so Symbol table ''.dynsym'' contains 8 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FUNC GLOBAL DEFAULT UND __chk_fail@GLIBC_2.3.4 (3) 2: 0000146c 0 NOTYPE GLOBAL DEFAULT ABS _edata 3: 0000146c 0 NOTYPE GLOBAL DEFAULT ABS _end 4: 00000310 44 FUNC GLOBAL DEFAULT 11 __fdelt_warn@@GLIBC_2.15 5: 00000310 44 FUNC GLOBAL DEFAULT 11 __fdelt_chk@@GLIBC_2.15 6: 00000000 0 OBJECT GLOBAL DEFAULT ABS GLIBC_2.15 7: 0000146c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start

En este punto, no sé qué puedo hacer para engañar al cargador (¿quién?) Para que elija mis símbolos. ¿Voy en la dirección correcta?


Me encontré con este mismo problema, aunque no con Steam. Lo que estaba intentando ejecutar quería 2.15 para fdelt_chk mientras que mi sistema tenía 2.14 . Encontré una solución para casos simples como el nuestro, donde podemos proporcionar fácilmente nuestra propia implementación para la funcionalidad que falta.

Comencé desde su intento de solución para implementar la funcionalidad y LD_PRELOAD ing. El uso de LD_DEBUG=all (según lo sugerido por osgx) mostró que el vinculador todavía estaba buscando 2.15 , por lo que simplemente tener el símbolo correcto no era suficiente y había algún otro mecanismo de versionado en algún lugar. Noté que tanto objdump -p como readelf -V mostraban referencias a 2.15 , así que busqué la documentación en ELF y encontré información sobre los requisitos de la versión .

Así que mi nuevo objetivo era transformar las referencias a 2.15 en referencias a otra cosa. Parecía razonable que solo pudiera sobrescribir las estructuras que se referían a 2.15 con las estructuras que se referían a alguna versión inferior, como 2.1 . Al final, después de algunas pruebas y errores, encontré que editar el Elfxx_Vernaux (es?) .gnu.version_r en .gnu.version_r era suficiente, pero supongo que un pirata informático.

La sección .gnu.version_r es una lista de Elfxx_Verneed s de 16 bytes y Elfxx_Vernaux 16 bytes. Cada entrada de Elfxx_Verneed es seguida por las Elfxx_Vernaux asociadas. Por lo que pude ver, vn_file es en realidad la cantidad de Elfxx_Vernaux asociados que hay, incluso aunque los documentos digan el number of associated verneed array entries . Sin embargo, podría ser solo un malentendido de mi parte.

Entonces, para comenzar a hacer las ediciones, veamos algo de la información de readelf -V . Recogí partes que no nos importan.

$ readelf -V mybinary <snip stuff before .gnu.version_r> Version needs section ''.gnu.version_r'' contains 5 entries: Addr: 0x00000000000021ac Offset: 0x0021ac Link: 4 (.dynstr) <snip libraries that don''t refer to GLIBC_2.15> 0x00c0: Version: 1 File: libc.so.6 Cnt: 10 0x00d0: Name: GLIBC_2.3 Flags: none Version: 19 0x00e0: Name: GLIBC_2.7 Flags: none Version: 16 0x00f0: Name: GLIBC_2.2 Flags: none Version: 15 0x0100: Name: GLIBC_2.2.4 Flags: none Version: 14 0x0110: Name: GLIBC_2.1.3 Flags: none Version: 13 0x0120: Name: GLIBC_2.15 Flags: none Version: 12 0x0130: Name: GLIBC_2.4 Flags: none Version: 10 0x0140: Name: GLIBC_2.1 Flags: none Version: 9 0x0150: Name: GLIBC_2.3.4 Flags: none Version: 4 0x0160: Name: GLIBC_2.0 Flags: none Version: 2

De esto vemos que la sección comienza en 0x21ac . Cada archivo listado tendrá un Elfxx_Verneed seguido de un Elfxx_Vernaux para cada una de las subentradas (como GLIBC_2.3 ). Supongo que el orden de la información en la salida siempre coincidirá con el orden en el archivo, ya que readelf solo está volcando las estructuras. Aquí está toda mi sección .gnu.version_r

000021A0 01 00 02 00 000021B0 A3 0C 00 00 10 00 00 00 30 00 00 00 11 69 69 0D 000021C0 00 00 11 00 32 0D 00 00 10 00 00 00 10 69 69 0D 000021D0 00 00 0B 00 3C 0D 00 00 00 00 00 00 01 00 02 00 000021E0 BE 0C 00 00 10 00 00 00 30 00 00 00 13 69 69 0D 000021F0 00 00 08 00 46 0D 00 00 10 00 00 00 10 69 69 0D 00002200 00 00 07 00 3C 0D 00 00 00 00 00 00 01 00 02 00 00002210 99 0C 00 00 10 00 00 00 30 00 00 00 11 69 69 0D 00002220 00 00 06 00 32 0D 00 00 10 00 00 00 10 69 69 0D 00002230 00 00 05 00 3C 0D 00 00 00 00 00 00 01 00 02 00 00002240 AE 0C 00 00 10 00 00 00 30 00 00 00 11 69 69 0D 00002250 00 00 12 00 32 0D 00 00 10 00 00 00 10 69 69 0D 00002260 00 00 03 00 3C 0D 00 00 00 00 00 00 01 00 0A 00 00002270 FF 0C 00 00 10 00 00 00 00 00 00 00 13 69 69 0D 00002280 00 00 13 00 46 0D 00 00 10 00 00 00 17 69 69 0D 00002290 00 00 10 00 50 0D 00 00 10 00 00 00 12 69 69 0D 000022A0 00 00 0F 00 5A 0D 00 00 10 00 00 00 74 1A 69 09 000022B0 00 00 0E 00 64 0D 00 00 10 00 00 00 73 1F 69 09 000022C0 00 00 0D 00 70 0D 00 00 10 00 00 00 95 91 96 06 000022D0 00 00 0C 00 7C 0D 00 00 10 00 00 00 14 69 69 0D 000022E0 00 00 0A 00 87 0D 00 00 10 00 00 00 11 69 69 0D 000022F0 00 00 09 00 32 0D 00 00 10 00 00 00 74 19 69 09 00002300 00 00 04 00 91 0D 00 00 10 00 00 00 10 69 69 0D 00002310 00 00 02 00 3C 0D 00 00 00 00 00 00

Para hablar brevemente sobre la estructura aquí, comienza con un Elfxx_Verneed . Según los documentos, podemos ver que habrá 2 Elfxx_Vernaux es, un desplazamiento de 16 bytes, y el siguiente Elfxx_Verneed es un desplazamiento de 48 bytes. Estas compensaciones son desde el inicio de la estructura actual. Parece que técnicamente las Elfxx_Vernaux asociadas Elfxx_Vernaux pueden no ser adyacentes después de la actual Elfxx_Verneed pero en realidad fue así en todos los archivos que revisé.

A partir de esto, podemos encontrar el archivo que queremos (libc.so.6) de diferentes maneras. Elfxx_Verneed una referencia cruzada de la cadena (en la que no Elfxx_Verneed ), encuentre el Elfxx_Verneed con un recuento de 0A 00 (10, que coincida con nuestra salida de readelf anterior), o encuentre el último Elfxx_Verneed ya que es la última salida de readelf . En cualquier caso, el correcto para mi archivo está en 0x226C . Su primer Elfxx_Vernaux comienza a las 0x227C .

Queremos encontrar el Elfxx_Vernaux con una versión de 0C 00 (12, otra vez coincidiendo con nuestra salida de readelf superior). Vemos el Elfxx_Vernaux que coincide en 0x22CC y toda la estructura es 95 91 96 06 00 00 0C 00 7C 0D 00 00 10 00 00 00 . Vamos a sobrescribir los primeros 12 bytes para dejar el desplazamiento solo. Solo estamos modificando los datos, no moviéndonos alrededor de las estructuras, después de todo.

Para seleccionar los datos con los que se sobrescribirá, simplemente lo Elfxx_Vernaux de un Elfxx_Vernaux diferente para una versión de glibc que podamos satisfacer. 0x22EC uno de 2.1 , que está en 0x22EC en mi archivo, con los datos 11 69 69 0D 00 00 09 00 32 0D 00 00 10 00 00 00 . Así que toma los primeros 12 bytes de este y sobrescribe los primeros 12 bytes de arriba, y eso es todo para la edición hexadecimal.

Por supuesto, usted podría tener múltiples referencias para tratar. Su programa puede tener varios binarios para editar.

En este punto, nuestro programa todavía no se ejecutará. Pero en lugar de que se le diga algo como GLIBC_2.15 not found que debería quejarse de la ausencia de __fdelt_chk . Ahora hacemos el shim y LD_PRELOAD ing descritos en la pregunta, excepto que en lugar de versionar nuestra implementación como 2.15 , usamos la versión que elegimos al editar en hexadecimal. En este punto el programa debería ejecutarse.

Este método depende de la capacidad de proporcionar una implementación para lo que falta. Nuestro __fdelt_chk es extremadamente simple, pero no dudo que en algunos casos, proporcionar una implementación podría ser más difícil que simplemente actualizar la libc del sistema.


Para lo que vale, la función __fdelt_chk está relacionada con la función FORTIFY_SOURCE que se agregó en glibc 2.15. Permite la verificación en tiempo de compilación y tiempo de ejecución para desbordamientos de búfer.

Si pudieras recompilar con el siguiente CFLAGS agregado, construiría un binario compatible con versiones anteriores sin la comprobación adicional:

-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0