Para empezar en el desarrollo de malware es necesario tener una base sólida del lenguaje C. Muchos conceptos que aparecen constantemente en APIs de Windows, shellcode loaders, implantes o herramientas ofensivas están construidos sobre estructuras, enumeraciones, uniones, punteros y operaciones a nivel de bits.
Variables
Una variable es una reserva de espacio en la memoria del proceso. En C, el tipo de datos determina cuántos bytes ocupa dicha variable y cómo interpreta el compilador su contenido.
char(1 byte): Almacena un solo carácter o un valor entero pequeño.int(4 bytes): Almacena valores enteros (positivos o negativos).void: Representa la ausencia de tipo. Se utiliza para indicar que una función no devuelve datos o para declarar punteros genéricos (void*).
Modificadores de signo
signed: Permite valores positivos y negativos (opción por defecto).unsigned: Fuerza a que el tipo de dato solo almacene valores positivos, duplicando su capacidad máxima orientada a números enteros.
Punteros (Pointer) y direcciones de memoria
Un puntero es una variable cuyo contenido es una dirección de memoria en lugar de un valor directo. Es el concepto más crítico para entender la manipulación de procesos.
- Operador de dirección (
&): Obtiene la dirección de memoria de una variable. - Operador de desreferencia (
*): Accede al valor almacenado en la dirección de memoria que guarda el puntero.
int numero = 42; // Variable local en memoria
int* pNumero = № // 'pNumero' almacena la dirección de memoria de 'numero'
// Para modificar el valor de 'numero' a través del puntero:
*pNumero = 100; // Ahora 'numero' vale 100Arrays
Un array es una colección contigua de elementos del mismo tipo de datos almacenados en memoria. Se definen indicando el tamaño entre corchetes [].
// Declaración de un array de 4 bytes (caracteres)
char shellcode[4] = { 0x90, 0x90, 0x90, 0x90 };
// El acceso a los elementos es indexado (comienza en 0)
char primerByte = shellcode[0]; // Obtiene 0x90En C, el nombre de un array actúa internamente como un puntero que apunta a la dirección de memoria del primer elemento (&shellcode[0]).
Cadenas de caracteres (Strings)
En C no existe un tipo de datos nativo llamado "string". Las cadenas de texto son, fundamentalmente, arrays de caracteres (char) que terminan con un carácter nulo (\0 o 0x00) para indicar al sistema dónde finaliza la cadena.
// Declaración estándar de una cadena de caracteres
char* texto = "ntdll.dll";
// Lo que el compilador genera realmente en memoria es un array contiguo:
// ['n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', '\0']Estructuras (struct)
Una estructura es un tipo de dato personalizado que permite agrupar múltiples variables (pueden ser de diferentes tipos) bajo un mismo bloque de memoria contiguo.
// Definición de la estructura
struct ProcesoMini {
int pid;
int totalHilos;
};
// Instanciación y uso de la estructura
struct ProcesoMini miProceso;
miProceso.pid = 1432;
miProceso.totalHilos = 4;Cuando trabajamos con un puntero a una estructura, se utiliza el operador flecha (->) en lugar del punto (.) para acceder a sus miembros:
struct ProcesoMini* pProceso = &miProceso;
pProceso->pid = 2800; // Modifica el miembro 'pid' a través del punteroEn la entrada Offensive C (2) se habla con más profundidad sobre las estructuras y sus usos.
Funciones y prototipos
Una función es un bloque de código ejecutable diseñado para realizar una tarea específica. Consta de un tipo de retorno, un nombre y parámetros de entrada.
// Definición de una función básica
int SumarValores(int a, int b) {
return a + b;
}Calling conventions (__stdcall, __cdecl)
En el desarrollo en Windows y el uso de sus APIs, a menudo veremos palabras clave antes del nombre de la función, como WINAPI o NTAPI. Estas macros se traducen en directivas de compilación (como __stdcall) que le indican al procesador el orden exacto en el que deben cargarse los parámetros en los registros o en la pila antes de ejecutar la función.



