En varias competiciones de demoscene lo que importa es el tamaño: 1k, 4k, 64k por nombrar algunas.
Suponiendo que ya se tiene el binario, minimizado (ver linux_4k_intro_coding_asm06) es común comprimirlo.
Las dos formas más comunes que suelen encontrarse difieren en quien realiza la descompresión:
- La descompresión la realiza el ELF
- La descompresión se realiza mediante un script que se encuentra en el header
A continuación se verán las distintas alternativas mediante ejemplos encontrados en distintas demos, centrandose en las del caso 2.
Descompresión realizada por el archivo ELF
Mediante upx - About Time
En el archivo synth_src/bin/strip.sh
se encuentran los pasos para preparar el
archivo:
strip -s -R .comment -R .gnu.version demo
sstrip demo
upx-nrv --ultra-brute --overlay=strip --all-methods --all-filters --no-mode --no-owner --no-time --lzma demo
sstrip demo
Aparte de los programas strip y sstrip utilizados para reducir el tamaño del binario, se utiliza upx para realizar la descompresión a memoria en tiempo de ejecución.
Notar que el uso de strip
y sstrip
se realiza siempre, no solamente al
utilizar upx
.
Descompresión realizada mediante script en el header
Uso de sed - geelimanipulaatio
En la cabecera del archivo geelimanipulaatio_1920x1080
se encuentra:
cp $0 /tmp/M;(sed 1d $0|lzcat)>$_;$_;exit
Tamaño: 42 bytes.
Esta es la cabecera de menor tamaño entre las estudiadas.
Se utiliza sed
para borrar la primer linea del archivo y lzcat
para
descomprimirlo. Aquí $_
hace referencia al último argumento del comando anterior, con lo que se ahorran
4 bytes con cada uso.
Si bien el contenido de la copia (cp $0 /tmp/M
) es reemplazado con el
siguiente comando ((sed 1d $0|lzcat)>$_
), su motivo está relacionado con el
permiso de ejecución del archivo, el cual se mantiene del archivo original y
evita tener que utilizar el comando chmod +x
.
Uso de sed - lo jai rodybo’e nunco’e fai paki’orevo poi’i no’a kaike’a
En el directorio src/src/stub
se encuentran alternativas del header a
utilizar, por ejemplo, src/src/stub/stub2-outer-xz
:
sed 1d $0|xzcat>j;chmod +x j;./j;rm j;exit
Tamaño: 43 bytes.
Similar a la anterior, borra la primera linea del archivo en que se encuentra el header, descomprime el binario, le da permisos de ejecución, lo ejecuta y lo elimina.
Si no se eliminara el archivo sería la cabecera de menor tamaño entre las
estudiadas, pero es razonable que se borre el archivo si se descomprime en un
directorio que no sea /tmp
.
Uso de tail - bioterrorism
En el archivo bioterrorism/src/unpack.header
:
a=/tmp/a;tail -n+2 $0|zcat>$a;chmod +x $a;$a;exit
Tamaño: 50 bytes.
Otra alternativa, comparada con el uso de sed
, se pierden 2 bytes. La única
ventaja de utilizar tail
en lugar de sed
es la velocidad, pero para estos
casos no es apreciable.
Uso de dd - Yellow Rose of Texas
En el archivo src/unpack.header
se encuentra:
dd bs=1 skip=83<$0|gunzip>/tmp/T;cd /tmp;chmod +x T;__GL_FSAA_MODE=4 ./T;rm T;exit
En este caso el truco consiste en las opciones al comando dd
: bs=1 skip=83
copia el resto del archivo a partir del final del texto exit
, ya
que la linea ocupa exactamente 83 bytes (contando la nueva linea).
Si se omite la variable de entorno utilizada se obtiene:
dd bs=1 skip=66<$0|gunzip>/tmp/T;cd /tmp;chmod +x T;./T;rm T;exit
Tamaño: 66 bytes.
Conclusión
Como se indicó anteriormente nos centramos en el caso de descompresión basada en script en el header.
Para obtener una conclusión de que script conviene utilizar se normalizarán los scripts anteriores:
- Como nombre del programa extraído se utiliza
P
- Se utiliza como decompresor
zcat
Y se tendrán en cuenta las siguientes combinaciones:
- El archivo se extrae en el directorio actual y debe borrarse al terminar la ejecución.
- El archivo se extrae en el directorio
/tmp
y no debe borrarse al terminar la ejecución.
A continuación los scritps:
-
Se extrae en el directorio actual, se borra
cp $0 P;(sed 1d $0|zcat)>P;./P;rm P;exit sed 1d $0|zcat>P;chmod +x P;./P;rm P;exit tail -n+2 $0|zcat>P;chmod +x P;./P;rm P;exit dd bs=1 skip=46<$0|zcat>P;chmod +x P;./P;exit
-
Se extrae en
/tmp
, no se borracp $0 /tmp/P;(sed 1d $0|zcat)>$_;$_;exit sed 1d $0|zcat>/tmp/P;chmod +x $_;$_;exit tail -n+2 $0|zcat>/tmp/P;chmod +x $_;$_;rm $_;exit dd bs=1 skip=57<$0|zcat>/tmp/T;chmod +x $_;$_;rm $_;exit
En ambos casos el primer script es el ganador (por 1 byte) con un tamaño de 41 bytes totales, contando la nueva linea.
Nota: En los scripts que utilizan dd
se saltan la cantidad de carácteres de
la linea.
Por último, conviene recordar que no es posible calcular con antelación que método será el más efectivo para obtener un tamaño menor del ejecutable, por lo que conviene utilizar los dos anteriores (ELF, script) y ver con cual se obtiene un archivo de menor tamaño.