Ciertos usuarios habran notado que algunos drivers provistos por NVIDIA vienen enpaquetados en archivos .bin los cuales al abrirse no son mas que shells scripts con una caracteristica: el script contiene el codigo ejecutable del programa que se encarga de instalar compilar e instalar el driver.
Lo cierto es que pocos han documentado como se puede realizar esto y tecnicamente como es posible que un programa ejecutable pueda ser integrado dentro de un script siendo se espera que un script sea unicamente archivo ascii.
Bueno en realidad no hay mucho misterio: el interprete ( en este caso bash ) unicamente ejecuta la parte ascii y uno de los comandos dentro del script abre el mismo script, saca el codigo ejecutable a un archivo y ejecuta el programa.
Aunque hay varios detalles involucrados lo anterior es mayormente todo lo que hay que hacer, sin embargo varios tecnisismos se entrometen los cuales veremos a continuacion:
Vamos a crear 2 programas, el primero es un shell script y el segundo un "hola mundo" escrito en lenguaje C y compilado posteriormente:
Creamos el programa en C y lo compilamos: cat > hola.c #includeint main(){ printf("hola mundo desde C\n"); return 0; } $gcc hola.c -o hola --------------------------------------------- Creamos el script : $cat > shell.sh #!/bin/bash echo "hola desde un script!!!" $ chmod +x shell.sh
Ahora vamos a ver cuantos byes ocupa mi script y el programa compilado:
$ ls -al hola
-rwxr-xr-x 1 kb kb 6449 2008-05-12 22:24 hola //el programa compilado: hola consta de 6449 bytes
$ wc -c hola
6449 hola //aqui lo confirmo
$ hexdump -C shell.sh
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 65 63 68 6f |#!/bin/bash.echo|
00000010 20 22 68 6f 6c 61 20 64 65 73 64 65 20 75 6e 20 | "hola desde un |
00000020 73 63 72 69 70 74 21 21 21 22 0a |script!!!".|
0000002b
$wc -c shell.sh
43 shell.sh
Como vemos el script shell.sh termina en el byte 2b es decir 43 en decimal, ahora con esta informacion podriamos copiar el codigo ejecutable del programa hola al final del script, veamos que pasara.
Usamos el comando dd para copiar el archivo ejecutable hola dentro del script:
cp shell.sh shell2.sh
$ dd if=hola seek=43 bs=1 of=shell2.sh < ---salta los primeros 43 bytes( bs=1 es un byte) de shell2.sh
6449+0 records in
6449+0 records out
6449 bytes (6.4 kB) copied, 0.099458 seconds, 64.8 kB/s
hexdump shell2.sh -C|head
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 65 63 68 6f |#!/bin/bash.echo|
00000010 20 22 68 6f 6c 61 20 64 65 73 64 65 20 75 6e 20 | "hola desde un |
00000020 73 63 72 69 70 74 21 21 21 22 0a 7f 45 4c 46 01 |script!!!"..ELF.|
00000030 01 01 00 00 00 00 00 00 00 00 00 02 00 03 00 01 |................|
00000040 00 00 00 f0 82 04 08 34 00 00 00 ec 0c 00 00 00 |.......4........|
00000050 00 00 00 34 00 20 00 07 00 28 00 24 00 21 00 06 |...4. ...(.$.!..|
00000060 00 00 00 34 00 00 00 34 80 04 08 34 80 04 08 e0 |...4...4...4....|
00000070 00 00 00 e0 00 00 00 05 00 00 00 04 00 00 00 03 |................|
00000080 00 00 00 14 01 00 00 14 81 04 08 14 81 04 08 13 |................|
00000090 00 00 00 13 00 00 00 04 00 00 00 01 00 00 00 01 |................|
$
hexdump shell.sh -C|head
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 65 63 68 6f |#!/bin/bash.echo|
00000010 20 22 68 6f 6c 61 20 64 65 73 64 65 20 75 6e 20 | "hola desde un |
00000020 73 63 72 69 70 74 21 21 21 22 0a |script!!!".|
0000002b
Veamos que pasa si tratamos de ejecutar el script ahora:
./shell2.sh
hola desde un script!!!
./shell2.sh: line 3: syntax error near unexpected token `('
./shell2.sh: line 3: `ELF��4�
4 ($!44�4�������tttt�t�
�������((�(� Q�td/lib/ld-linux.so.2GNU@X�h�l�p�U��S���[�����������t����pX[���5`��%d��%h�h������%l�������%p�h�����1�^�����PTRh��h��QVht���������������������U����=��t
����|��ҡ|����u�����ÐU��������t���t �$�����Ð�L$����q�U��Q���$\��C������Y]�a�ÐU��]Ít&��'U��WVS�O�á��
���������������)�����t$1��E�D�E
�D$��$��������9�uރ�
[^_]Ë$Ð�U��S�t����t����t
���Ћ���u���[]�U��S���[�������Y[��hola mundo desde C��������
8�H����op�����' t�
El script ejecuto sin embargo el interprete del shell como era de esperar no pudo ejecutar el codigo binario del programa hola, por tanto lo que debemos hacer es introducir al script las instrucciones necesarias para sacar ese codigo a un archivo y ejecutar el archivo de modo que el interprete nunca intente ejecutar el codigo binario de manera directa.
La forma en que haremos esto sera usando el comando dd para leer el mismo script desde donde corre y despues daremos permisos de ejecucion, todavia hay algunos detalles :
El truco para tener idea exacta de cuantos bytes nos vamos a gastar en el script y apartir de que byte podemos empezar escribir el contenido de nuestro programa ejecutable es escribir primero lo siguiente en el comando dd que desempaqueta el archivo; el script quedara asi:
$cat shell.sh
#!/bin/bash
echo "hola desde un script!!!"
dd if=shell.sh bs=1 skip=000000 of=program
chmod +x program
exec program
$ hexdump -C shell.sh
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 65 63 68 6f |#!/bin/bash.echo|
00000010 20 22 68 6f 6c 61 20 64 65 73 64 65 20 75 6e 20 | "hola desde un |
00000020 73 63 72 69 70 74 21 21 21 22 0a 64 64 20 69 66 |script!!!".dd if|
00000030 3d 73 68 65 6c 6c 2e 73 68 20 62 73 3d 31 20 73 |=shell.sh bs=1 s|
00000040 6b 69 70 3d 30 30 30 30 30 30 20 20 6f 66 3d 70 |kip=000000 of=p|
00000050 72 6f 67 72 61 6d 0a 63 68 6d 6f 64 20 2b 78 20 |rogram.chmod +x |
00000060 70 72 6f 67 72 61 6d 0a 65 78 65 63 20 70 72 6f |program.exec pro|
00000070 67 72 61 6d 0a |gram.|
00000075
$ wc -c shell.sh
117 shell.sh <-contamos cuantos caracteres hay
$ printf " %d \n" 0x75 <-hacemos una conversion de hexadecimal a decimal
117
Abora sabemos en que desplazamiento en bytes podemos empezar a copiar el archivo ejecutable "ho;a" y desde donde lo vamos a desempacar; ahora solo nos quedan 2 pasos, el primero modificar el parametro 000000 ( pueden ser tantos ceros como requieran) y luego empezar a copiar el codigo usando el dd pero desde la linea de comandos:
cat shell.sh
#!/bin/bash
echo "hola desde un script!!!"
dd if=shell.sh bs=1 skip=000117 of=program <---modificamos el parametro skip
chmod +x program
exec program
$ hexdump -C shell.sh
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 65 63 68 6f |#!/bin/bash.echo|
00000010 20 22 68 6f 6c 61 20 64 65 73 64 65 20 75 6e 20 | "hola desde un |
00000020 73 63 72 69 70 74 21 21 21 22 0a 64 64 20 69 66 |script!!!".dd if|
00000030 3d 73 68 65 6c 6c 2e 73 68 20 62 73 3d 31 20 73 |=shell.sh bs=1 s|
00000040 6b 69 70 3d 30 30 30 31 31 37 20 20 6f 66 3d 70 |kip=000117 of=p|
00000050 72 6f 67 72 61 6d 0a 63 68 6d 6f 64 20 2b 78 20 |rogram.chmod +x |
00000060 70 72 6f 67 72 61 6d 0a 65 78 65 63 20 70 72 6f |program.exec pro|
00000070 67 72 61 6d 0a |gram.|
00000075
Ahora copiamos el archivo a nuestro shell en el desplazamiento adecuado:
ls -al *.sh hola*
-rwxr-xr-x 1 kb kb 6449 2008-05-12 22:24 hola
-rw-r--r-- 1 kb kb 79 2008-05-12 22:23 hola.c
-rwxr-xr-x 1 kb kb 6492 2008-05-13 07:08 shell2.sh
-rwxr-xr-x 1 kb kb 117 2008-05-15 20:08 shell.sh
$ dd if=hola bs=1 seek=117 of=shell.sh
6449+0 records in
6449+0 records out
6449 bytes (6.4 kB) copied, 0.103083 seconds, 62.6 kB/s
$ wc -c shell.sh
6566 shell.sh
hexdump -C shell.sh |head
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 65 63 68 6f |#!/bin/bash.echo|
00000010 20 22 68 6f 6c 61 20 64 65 73 64 65 20 75 6e 20 | "hola desde un |
00000020 73 63 72 69 70 74 21 21 21 22 0a 64 64 20 69 66 |script!!!".dd if|
00000030 3d 73 68 65 6c 6c 2e 73 68 20 62 73 3d 31 20 73 |=shell.sh bs=1 s|
00000040 6b 69 70 3d 30 30 30 31 31 37 20 20 6f 66 3d 70 |kip=000117 of=p|
00000050 72 6f 67 72 61 6d 0a 63 68 6d 6f 64 20 2b 78 20 |rogram.chmod +x |
00000060 70 72 6f 67 72 61 6d 0a 65 78 65 63 20 70 72 6f |program.exec pro|
00000070 67 72 61 6d 0a 7f 45 4c 46 01 01 01 00 00 00 00 |gram..ELF.......|
00000080 00 00
Asi se ve ahora el script por medio del edir vi
$vi
#!/bin/bash
echo "hola desde un script!!!"
dd if=shell.sh bs=1 skip=000117 of=program
chmod +x program
exec program
^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@ð<82>^D^H4^@^@^@ì^L^@^@^@^@^@^@4^@ ^@^G^@(^@$^@!^@^F^@^@^@4^@^@^@4<80>^D^H4<80>^D^Hà^@^@^@à^@^@^@^E^@^@^@^D^@^@^@^C^@^@^@^T^A^@^@^T<81>^D^H^T<81>^D^H^S^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A^@^@^@^@^@^@^@^@<80>^D^H^@<80>^D^Ht^D^@^@t^D^@^@^E^@^@^@^@^P^@^@^A^@^@^@t^D^@^@t<94>^D^Ht<94>^D^H^L^A^@^@^P^A^@^@^F^@^@^@^@^P^@^@^B^@^@^@<88>^D^@^@<88><94>^D^H<88><94>^D^HÐ^@^@^@Ð^@^@^@^F^ 00 00 00 02 00 03 00 01 00 00 00 f0 82 04 |................|
00000090 08 34 00 00 00 ec 0c 00 00 00 00 00 00 34 00 20 |.4...........4.
El anterior programa tiene un problema y es que el exec no encuentra "program" asi que modificamos un poco el script :
#!/bin/bash
echo "hola desde un script!!!"
dd if=shell.sh bs=1 skip=000119 of=program <-esta linea se modifico
chmod +x program
exec ./program <-- esta linea se modifico
^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@ð<82>^D^H4^@^@^@ì^L^@^@^@^@^@^@4^@ ^@^G^@(^@$^@!^@^F^@^@^@4^@^@^@4<80>^D^H4<80>^D^Hà^@^@^@à^@^@^@^E^@^@^@^D^@^@^@^C^@^@^@^T^A^@^@^T<81>^D^H^T<81>^D^H^S^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A^@^@^@^@^@^@^@^@<80>^D^H^@<80>^D^Ht^D^@^@t^D^@^@^E^@^@^@^@^P^@^@^A^@^@^@t^D^@^@t<94>^D^Ht<94>^D^H^L^A^@^@^P^A^@^@^F^@^@^@^@^P^@^@^B^@^@^@<88>^D^@^@<88><94>^D^H<88><94>^D^HÐ^@^@^@Ð^@^@^@^F^@^@^@^D^@^@^@^D^@^@^@(^A^@^@(<81>^D^H(<81>^D^H ^@^@^@ ^@^@^@^D^@^@^@^D^@^@^@Qåtd^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^F^@^@^@^D^@^@^@/lib/ld-linux.so.2^@^@^D^@^@^@^P^@^@^@^A^@^@^@GNU^@^@^@^@^@^B^@^@^@^F^@^@^@^H^@^@^@^C^@^@^@^E^@^@^@^A^@^@^@^C^@^@^@^D^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^B^@^@^@^@^@^@^@^B^@^@^@^D^@^@^@^A^@^@^@^E^@^@^@^@ ^@ ^@^@^@^@^D^@^@^@KãÀ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@ ^@
.......
.....
Con eso tenemos el punto final de nuestro experimento, ahora ya podemos ejecutar nuestro script que autosempaqueta un programa ejecutable:
./shell.sh
hola desde un script!!!
6450+0 records in
6450+0 records out
6450 bytes (6.4 kB) copied, 0.100495 seconds, 64.2 kB/s
hola mundo desde C <---------- bingo !!!
Con eso ponemos punto final a este problema.