Grunt's personal blog

this is my personal blog for my hacking stuff, my degree stuff, etc

View on GitHub

I/O - E/S

Entrada y Salida (I/O)

El lenguaje de programación C proporciona varias formas de realizar tareas de entrada y salida (I/O). La entrada y salida son conceptos fundamentales en la informática, ya que permiten que los usuarios y aplicaciones externas interactúen con un programa para completar alguna acción.

De manera simple, la entrada se refiere a cualquier dato que se puede proporcionar a un programa en ejecución. Por otro lado, la salida es la información que el programa puede mostrar en la terminal o escribir en un archivo.


Entrada y Salida de Bajo Nivel

En C, las funciones de bajo nivel como read() y write() permiten realizar operaciones de entrada y salida directamente con descriptores de archivo (file descriptors). Estas funciones son útiles para leer datos desde archivos o desde la entrada estándar (stdin) y escribir datos en la salida estándar (stdout).

Por ejemplo, la función read() lee datos arbitrarios hasta un número especificado de bytes y los almacena en un búfer. De manera similar, write() se utiliza para enviar datos desde el programa hacia un destino, como la terminal o un archivo.


Entrada y Salida de Alto Nivel

Las funciones de alto nivel como fgets() y printf() son más comunes en aplicaciones C. Estas funciones proporcionan una interfaz más sencilla para trabajar con datos de entrada y salida.

Estas funciones son ideales para trabajar con datos estructurados y para interactuar con los usuarios de manera más intuitiva.

Entrada y Salida de Bajo Nivel con Ejemplo

En C, las funciones de bajo nivel como read() y write() trabajan directamente con descriptores de archivo y manejan datos en forma de bytes crudos. Esto significa que no procesan los datos ni aplican formatos, simplemente leen o escriben los bytes tal como están.

Ejemplo de Uso

El siguiente ejemplo muestra cómo se pueden usar read() y write() para interactuar con el usuario a través de la entrada y salida estándar:

#include <unistd.h>
#include <string.h>

void demo_data() 
{
    // Mensaje inicial para el usuario
    const char *prompt = "Enter data: ";
    write(STDOUT_FILENO, prompt, strlen(prompt));

    // Búfer para almacenar la entrada del usuario
    char buffer[32] = {};

    // Leer datos desde la entrada estándar
    int n = read(STDIN_FILENO, buffer, sizeof(buffer));

    // Mostrar los datos leídos al usuario
    const char *output = "The program read in:\n";
    write(STDOUT_FILENO, output, strlen(output));
    write(STDOUT_FILENO, buffer, n);
}

Explicación del Código

  1. write(STDOUT_FILENO, prompt, strlen(prompt));
    Escribe un mensaje en la salida estándar (la terminal) para solicitar datos al usuario.

  2. read(STDIN_FILENO, buffer, sizeof(buffer));
    Lee hasta 32 bytes de datos desde la entrada estándar (teclado) y los almacena en el búfer.

  3. write(STDOUT_FILENO, buffer, n);
    Escribe los datos ingresados por el usuario de vuelta a la salida estándar.

Este enfoque es útil cuando se necesita un control preciso sobre los datos sin aplicar ningún procesamiento adicional, como el manejo de caracteres de nueva línea o el formateo de cadenas.


Python script para el challenge

import interact
import struct

p = interact.Process()

# Menú principal
p.readuntil('Enter Choice')
p.sendline('1')  # Low Level IO

# Payload correcto (sin '!')
p.readuntil('Enter data:')
p.sendline(b'Hello\nWorld!\n\xC0\xDE\xF0\x0D')

# Entramos al quiz
p.readuntil('Press enter to start quiz...')
p.sendline('')

# Enviamos string literal exacto
p.readuntil('Enter Answer:')
p.sendline(b'Hello\nWorld!\n\xC0\xDE\xF0\x0D')

# Entramos en modo interactivo
p.interactive()