Binary Exploitation - Gecko Academy - Modulo 2¶
C / C++ Reversing (fundamentos)¶
Objetivo del modulo¶
Pasar de "leer codigo fuente" a "reconocer patrones en binario". Este modulo cubre piezas base de C/C++ que despues aparecen en reversing:
- entrada/salida y flujo en
main - funciones y paso de parametros
- tipos de datos y comparaciones signed/unsigned
- arrays, matrices y punteros
struct,uniony layout de memoria- clases basicas en C++
Preparacion del laboratorio¶
Compilar cada ejemplo en dos modos:
- Debug (
/Od /Zi) para ver logica casi 1:1. - Release (
/O2) para ver optimizaciones y codigo plegado.
Herramientas:
- IDA Pro para analisis estatico
- x64dbg / WinDbg para analisis dinamico
Slide 2 - Primer programa C/C++¶
I/O basico y stack buffer¶
#include <iostream>
#include <windows.h>
int main()
{
char name[20];
memset(name, 0, sizeof(name));
printf("Enter your name: ");
gets_s(name, sizeof(name));
printf("Hello %s !\n", name);
getchar();
return 0;
}
Que mirar en reversing¶
- reserva de stack (
sub rsp, ...) - direccion de buffer local (
lea rcx, [rbp-...]) - llamadas a CRT (
printf,gets_s) - limpieza y retorno de
main
Riesgo tecnico¶
gets_s es mas seguro que gets, pero igual es entrada de usuario.
Siempre revisar limites y como se usa el buffer luego.
Slide 3 - Funciones¶
Concepto: bloque reutilizable con parametros y retorno.
#include <iostream>
void to_print(char* name, char* age) {
printf("Hello %s, you are %s years old", name, age);
}
int main(int argc, char* argv[])
{
if (argc != 3) {
printf("[+] Usage: name, age. \nExample: funciones.exe John 25");
exit(1);
}
to_print(argv[1], argv[2]);
getchar();
return 0;
}
Que mirar en asm (Win64)¶
RCX,RDX,R8,R9para los 4 primeros parametros- prologo/epilogo de funcion
- valor de retorno en
RAX - llamadas con
cally manejo de argumentosargc/argv
Slide 4 - Tipos de datos¶
#include <iostream>
#include <windows.h>
int main()
{
unsigned int un_num = 0x81828384;
unsigned short un_two_bytes = 0x8182;
int s_num = 0x81828384;
short s_two_bytes = 0x8182;
char character = 0x41;
bool condition = false;
bool condition2 = true;
printf("[+] Data type: UNSIGNED INTEGER, len: 4 bytes: 0x%x\n", un_num);
printf("[+] Data type: UNSIGNED SHORT, len: 2 bytes: 0x%x\n", un_two_bytes);
printf("[+] Data type: INTEGER, len: 4 bytes: 0x%x\n", s_num);
printf("[+] Data type: INTEGER, len: 2 bytes: 0x%x\n", s_two_bytes);
printf("[+] Data type: INTEGER, len: 1 bytes: 0x%x\n", character);
printf("[+] Data type: INTEGER, len: 1 bytes: 0x%x\n", condition);
printf("[+] Data type: INTEGER, len: 1 bytes: 0x%x\n\n", condition2);
printf("[+] Checking unsigned data type\n");
if (un_num > 0) {
printf("[!] Positive value\n\n");
}
else {
printf("[!] Negative value or zero\n");
}
printf("[+] Checking signed data type\n");
if (s_num > 0) {
printf("[!] Positive value\n");
}
else {
printf("[!] Negative value or zero\n");
}
getchar();
return 0;
}
Punto clave para reversing¶
No alcanza con ver cmp:
- signed suele usar saltos
jl/jg/jle/jge - unsigned suele usar
jb/ja/jbe/jae
Esto impacta directamente en la logica de validacion.
Slide 5 - Arrays y matrices¶
// (Global Scope)
const char* array1[] = { "A", "B", "C", "D" };
int main() {
const int rows = 3;
const int cols = 4;
const char* array2[] = { "E", "F", "G" };
char** array3 = (char**)malloc(2 * sizeof(char*));
array3[0] = (char*)"I";
array3[1] = (char*)"J";
printf("Array 1:\n");
for (int i = 0; i < sizeof(array1) / sizeof(array1[0]); ++i) {
printf("%s\t", array1[i]);
}
printf("\nArray 2:\n");
for (int i = 0; i < sizeof(array2) / sizeof(array2[0]); ++i) {
printf("%s\t", array2[i]);
}
printf("\nArray 3:\n");
for (int i = 0; i < 2; ++i) {
printf("%s\t", array3[i]);
}
printf("\n");
free(array3);
int matrix[rows][cols] = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
printf("Matrix:\n");
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
printf("%d\t", matrix[i][j]);
}
printf("\n");
}
getchar();
return 0;
}
Que mirar en asm¶
- calculo de indice:
base + i*size - doble indice en matriz:
base + (i*cols + j)*size - loops anidados (
cmp/jcc,inc,jmp)
Error comun¶
Confundir un puntero doble (char**) con un array 2D real.
En memoria no son equivalentes.
Slide 6 - struct¶
analisis del binario de struct
#include <stdio.h>
#include <stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
struct Employee {
int id;
char name[50];
char gender;
unsigned int age;
int monthlySalary;
};
void printEmployee(struct Employee* emp) {
printf("\n--- Employee Information ---\n");
printf("ID: %d\n", emp->id);
printf("Name: %s\n", emp->name);
printf("Gender: %c\n", emp->gender);
printf("Age: %u\n", emp->age);
printf("Monthly Salary: %d\n", emp->monthlySalary);
printf("Annual Salary: %d\n", emp->monthlySalary * 12);
}
int main() {
struct Employee* emp = (struct Employee*)malloc(sizeof(struct Employee));
if (emp == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
printf("Enter employee ID: ");
scanf_s("%d", &emp->id);
printf("Enter name: ");
scanf_s("%s", emp->name, (unsigned)_countof(emp->name));
printf("Enter gender (M/F): ");
scanf_s(" %c", &emp->gender, 1);
printf("Enter age: ");
scanf_s("%u", &emp->age);
printf("Enter monthly salary: ");
scanf_s("%d", &emp->monthlySalary);
printEmployee(emp);
free(emp);
return 0;
}
Reversing checklist¶
- identificar offsets reales de campos
- detectar padding/alineacion
- verificar si vive en stack o heap (
malloc/new) - seguir funciones que reciben
struct*
Slide 7 - union¶
// Advanced example: Status Register
union StatusRegister {
struct {
unsigned int carry : 1;
unsigned int zero : 1;
unsigned int sign : 1;
unsigned int overflow : 1;
unsigned int reserved : 4;
} flags;
unsigned char value;
};
Implicacion en reversing¶
El mismo offset puede representar tipos distintos segun contexto. No fuerces una sola interpretacion temprano.
Slide 8 - Punteros¶
#include <stdio.h>
int main() {
int number = 42;
int* p_number = &number;
printf("--- Basic Concepts ---\n");
printf("Value of 'number': %d\n", number);
printf("Address of 'number': %p\n", (void*)&number);
printf("Value via pointer 'p_number': %d\n", *p_number);
printf("Address stored in 'p_number': %p\n", (void*)p_number);
printf("\n--- Pointer Modification ---\n");
*p_number = 100;
printf("New value of 'number': %d\n", number);
printf("\n--- Pointer Arithmetic ---\n");
int numbers[] = { 10, 20, 30 };
int* p = numbers;
printf("First element: %d (address: %p)\n", *p, (void*)p);
p++;
printf("Second element: %d (address: %p)\n", *p, (void*)p);
printf("\n--- Null Pointers ---\n");
int* p_null = NULL;
if (p_null == NULL) {
printf("p_null is a null pointer!\n");
}
return 0;
}
En asm¶
leasuele construir direccionesmov reg, [reg+offset]suele dereferenciartest reg, reg/cmp reg, 0para null-check
Slide 9 - Clases C++ (base)¶
#include <cstdio>
#include <cstring>
#define _CRT_SECURE_NO_WARNINGS
class Rectangle {
private:
int width;
int height;
char name[50];
public:
Rectangle(int w, int h, const char* n) : width(w), height(h) {
strncpy_s(name, n, sizeof(name) - 1);
name[sizeof(name) - 1] = '\0';
}
~Rectangle() {
printf("Destroyed: %s\n", name);
}
int area() const {
return width * height;
}
virtual void print() const {
printf("%s: %dx%d\n", name, width, height);
}
static const char* className() {
return "Rectangle";
}
};
class ColoredRectangle : public Rectangle {
char color[20];
public:
ColoredRectangle(int w, int h, const char* n, const char* c)
: Rectangle(w, h, n) {
strncpy_s(color, c, sizeof(color) - 1);
color[sizeof(color) - 1] = '\0';
}
void print() const override {
printf("Colored %s: %s\n", className(), color);
}
};
int main() {
Rectangle rect1(3, 4, "StackRect");
rect1.print();
printf("Area: %d\n", rect1.area());
Rectangle* rect2 = new Rectangle(5, 6, "HeapRect");
rect2->print();
delete rect2;
ColoredRectangle coloredRect(10, 20, "PolymorphRect", "Red");
coloredRect.print();
printf("Class Name: %s\n", Rectangle::className());
return 0;
}
Que mirar en reversing¶
thisenRCX- constructor inicializando campos por offset
- destructor limpiando recursos
- llamadas virtuales indirectas via vtable
- metodos
staticsinthis
Explicación sobre vtable¶
- En C++, una vtable (tabla de funciones virtuales) es un mecanismo generado por el compilador que facilita el polimorfismo en tiempo de ejecución (despacho dinámico). Es básicamente un arreglo estático de punteros a funciones, creado para cualquier clase que contiene o hereda funciones virtuales.
Slide 10 - Preguntas tecnicas para autoevaluacion¶
- Como distingues signed vs unsigned solo viendo saltos?
- Que cambia en el asm entre
/Ody/O2? - Como identificas un campo de
structsin tipos? - Que pista fuerte te confirma llamada virtual?
- Donde esperas ver
thisen Win64?
Slide 11 - Practica y evaluacion¶
Valores del slide:
0x434F5245(int, big endian interpretado por bytes)0x45524F43(int, little endian segun representacion en memoria x86/x64)
Ejercicio recomendado¶
- Cargar ambos en memoria y verificar orden de bytes en debugger.
- Confirmar con
db/ddla diferencia entre valor logico y representacion.
Metodologia recomendada para este modulo¶
Para cada ejemplo:
- Abrir IDA, pararse en main.
- Pasar todos los flirts/sig-files que tengas en IDA.
- Pasar el class informer y el hrt.
- Decompilar las funciones principales y empezar a armar clases/uniones/structs e ir seteando en el codigo en donde se utilizan estos tipos de datos.
- Analizar comportamiento e ir tomando notas.
Hotkeys¶
Cheatsheet: Hotkeys para structs y offsets en IDA¶
- Alt+Q: Aplicar estructura al puntero seleccionado (Set structure type).
- T: Cambiar tipo de dato (Type) en la posición actual.
- Shift+T: Cambiar tipo de dato para un rango seleccionado.
- Ctrl+S: Abrir el editor de estructuras (Structures window).
- Ctrl+Shift+S: Crear nueva estructura.
- Ctrl+Alt+S: Buscar estructura por nombre.
- Ctrl+Shift+M: Aplicar estructura a memoria (Make structure).
- Ctrl+Shift+U: Deshacer estructura aplicada.
Tips¶
- Para setear offsets, selecciona el campo y usa T para asignar el tipo correcto.
- En el Structures window, puedes arrastrar campos para ajustar offsets manualmente.
- Si tienes un puntero a struct, usa Alt+Q para aplicar la estructura directamente.
Tips Structs C++¶
- Apretar la D sobre el primer elemento:
struct my_block {
int field;
...
}
- Apretar asterisco para definir arreglo.
- Click derecho -> convert to struct
- Pasar los structs definidos al código donde se usan (main, printEmployeeInfo, etc).
- Local Types -> ins add type
- hrt -> recast item
- hrt -> create dummy struct -> copiar y pegar definicion del struct en C-like -> aplicar tipo a puntero en main y printEmployeeInfo
- Decompiler -> click derecho -> convert to struct -> seleccionar struct creado -> aplicar tipo a puntero en main y printEmployeeInfo
#### Tips Unions C++
- options -> setup data types -> y lo modificamos.
- **Si hay un diferente tipo de dato en la misma dirección es un candidato a union**.
- Local types -> create union
#### Tips clases C++
- Para clases utilizar class informer y hrt.
- Armar structs en el local type con las clases del class informer
- Detectar: En donde se utilizan las clases, su constructor y destructor, y si hay funciones virtuales (vtable).
Referencia: IDA Structure Hotkeys
T hotkey structure offset¶
