Aprender C hoy en día es un must-have para aquellos que quieran dedicarse al exploiting o al análisis de malware. Como antesala al ensamblador, vamos a empezar con un ejercicio simple.

Enunciado
Compila un programa que muestre en pantalla "Bienvenido, exploiter <name>!!" siendo <name> un parámetro que le tenemos que pasar al programa. Además, el programa no debe ejecutarse sin que le pasemos dicho parámetro al igual que no debe ejecutarse si le pasamos más parámetros de los indicados.
Divide y Vencerás
Crear una función que muestre en pantalla un mensaje y el parámetro que le pasemos
Que devuelva error si se ejecuta con un número de parámetros diferentes a 2
Entrando al Barro
#include <stdio.h>
int main(int argc, char *argv[]) {
if(argc == 2) {
printf("Bienvenido, exploiter %s!", argv[1]);
return 0;
} else {
fprintf(stderr, "Usage: %s + <name>", argv[0]);
return 1;
}
}
Explicación
Lo primero que hacemos es importar el header <stdio.h> <= (click para más info)
#include <stdio.h>
C es un lenguaje que se compone de headers (o cabeceras).
¿Qué es un Header? Es un archivo que tiene la extensión ".h" y puede contener:
Declaración de funciones
Macros
Definiciones de tipos de datos
En este caso concreto, el header que usaremos nos permite operar con el input y el output. Algo básico cuando necesitamos sobre todo operar con mensajes en la terminal.
Después declaramos la función main.
int main(int argc, char *argv[])
No es viable compilar un programa en C sin que esté presente la función main. Además, debemos indicarle los argumentos argc y argv.
Argc (con "c" de counter) es el argumento de tipo entero que contiene el número de parámetros que vamos a pasarle a nuestro programa (de ahí que sea de tipo int).
Argv es una array que va a contener los parámetros que le pasemos al programa. Pero debe ser un puntero.
¿Por qué un puntero?
Porque las arrays como tal no existen "por definición" en C. La manera más elegante de llamarlo es mediante el puntero.
/* Esto... */
char *argv[]
/* ...Es lo mismo qué esto */
char **argv
Una vez declarada la función main correctamente, nos disponemos a completar el programa mediante 1 condicional sencillo.
Por una parte resolvemos el problema de que el programa se ejecute con más, o menos de 2 argumentos. Así que asignamos la funcionalidad principal del programa si se ejecuta solo con 2 argumentos.
if(argc == 2) {/* ... */}
Y aquí implementamos el mensaje que debe mostrarse. La función printf se encarga de mostrar información en la terminal. %s indica dónde debe ir un tipo de dato, concretamente de tipo char, y argv[1] indica que queremos que se muestre el segundo parámetro pasado al programa en el placeholder %s.
Por último, añadimos return 0, ya que es la manera limpia de terminar el programa de manera exitosa.
printf("Bienvenido, exploiter %s!", argv[1]);
return 0;
El primer argumento es SIEMPRE el propio ejecutable, y el segundo parámetro es el primero que introduce el usuario.
Por último añadimos la ejecución que se dará si el condicional previo no se cumple. Usamos esta vez la función fprintf porque podemos especificar dónde queremos enviar el mensaje. En este caso, queremos enviarlo a stderr, que es la salida del sistema que se encarga de los output de error.
Una vez hecho eso, pasamos el parámetro como en el caso anterior, esta vez con argv[0] ya que especificamos ahí el nombre del binario.
Cerramos el proceso en la condición con return 1 para especificar que el programa no ha terminado como debería, de manera controlada.
else {
fprintf(stderr, "Usage: %s + <name>", argv[0]);
return 1;