Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ExportHider — ExportHider: Generazione della tabella di esportazione durante l'esecuzione per nascondere le funzioni esportate dal file DLL. | Kitploit
Strumenti/GitHubGitHub/frkngksl/exporthider
Analisi Dinamica del Codice (DAST)ExploitReverse EngineeringAnalisi MalwareAnalisi di BinariRed TeamingSviluppo Payload
GitHubfrkngksl/exporthider

ExportHider

ExportHider: Generazione della tabella di esportazione durante l'esecuzione per nascondere le funzioni esportate dal file DLL.

Vedi Repository
3324 mesi faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

ExportHider

ExportHider genera un template DLL C++ che contiene uno stub di codice che permette di nascondere le Funzioni Esportate dalla Directory di Esportazione della DLL sul filesystem. Dopo aver inserito le definizioni delle funzioni e compilato il file, non vedrai le funzioni di esportazione nascoste attraverso visualizzatori di file PE come CFF Explorer. Tuttavia, poiché lo stub di codice nel template ricrea la Directory di Esportazione durante l'esecuzione, le chiamate legittime a GetProcAddress verranno eseguite con successo. Questo metodo funziona solo per il caricamento dinamico di DLL o per casi di custom DLL loader.

Come Funziona?

Normalmente, quando si vuole definire una Funzione Esportata in un file DLL (in C o C++), si inserisce semplicemente la parola chiave __declspec(dllexport) prima del nome della funzione, oppure si crea un file .def. Dopo la compilazione, il compilatore crea una tabella specifica chiamata Directory di Esportazione per contenere le informazioni relative alle Funzioni Esportate. La struttura della Directory di Esportazione può essere vista qui sotto:

Quando un processo vuole usare una funzione da un file DLL, il Windows Loader analizza semplicemente questa struttura e importa le funzioni richieste utilizzando gli array AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals.

La routine specifica per l'importazione di una funzione è spiegata in dettaglio nel post del blog di ferreirasc, ma in breve, per una funzione importata per nome, il Loader itera l'array AddressOfNames (i valori di questo array sono solo valori RVA) e cerca il nome dato. Una volta che il loader trova una corrispondenza nella posizione "i", si riferirà all'i-esimo indice dell'array AddressOfNameOrdinals e otterrà l'ordinale associato a questa funzione. Avendo l'ordinale, il loader si riferirà a AddressOfFunctions nella posizione del valore ordinale per ottenere infine l'RVA associato alla funzione importata.

Il punto cruciale qui è che tutte queste operazioni di ricerca e accesso da parte del Windows Loader, quando viene chiamato LoadLibrary, vengono eseguite dopo che la DLL è stata mappata nello spazio degli indirizzi del processo. Durante il mapping della DLL, l'intero file DLL, inclusi i suoi header PE, viene scritto in memoria, e il Loader analizza gli header in memoria per raggiungere la Directory di Esportazione. Ciò significa che se la DLL stessa è in grado di sovrascrivere i propri header PE in memoria per cambiare l'Indirizzo della Directory di Esportazione (semplicemente l'indice 0 del DataDirectory) dopo essersi collegata al processo, il loader può cercare funzioni da importare in una Directory di Esportazione arbitraria piuttosto che in quella aggiunta dal compilatore.

Parametri da Riga di Comando

root@kitploit:~

   __                       _          _     _
  /__\_  ___ __   ___  _ __| |_  /\  /(_) __| | ___ _ __
 /_\ \ \/ / '_ \ / _ \| '__| __|/ /_/ / |/ _` |/ _ \ '__|
//__  >  <| |_) | (_) | |  | |_/ __  /| | (_| |  __/ |
\__/ /_/\_\ .__/ \___/|_|   \__\/ /_/ |_|\__,_|\___|_|
          |_|
                     di @R0h1rr1m

Utilizzo di C:\Users\Public\DLLDemo\ExportHider.exe:

    -h | --help                                 Mostra il messaggio di aiuto.
    -i | --input <Percorso Input>               Percorso di input per l'elenco dei nomi delle funzioni da nascondere. (Obbligatorio)
    -o | --output <Percorso Output>             Percorso di output per il template DLL. (Obbligatorio)
    -n | --name <Nome DLL>                      Nome della DLL per la Directory di Esportazione. (Obbligatorio)
    -c | --count <Numero di Altre Funzioni>     Numero di altre funzioni esportate che non verranno nascoste.

Riguardo al parametro -i | --input <Percorso Input>, è necessario specificare un percorso per il file di input che memorizza i nomi delle funzioni da nascondere riga per riga. Il contenuto di un file di input di esempio sarebbe:

root@kitploit:~
TestFunction1
TestFunction2
TestFunction3

Riguardo al parametro -c | --count, se non si desidera nascondere tutte le funzioni esportate (cioè ci sono alcune funzioni esportate con __declspec(dllexport) o file .def, e appaiono nella Directory di Esportazione del file DLL nel filesystem tramite visualizzatori di file PE), basta specificare quante ce ne sono utilizzando questo parametro perché lo strumento ha bisogno di queste informazioni quando esegue calcoli di memoria.

Video Demo Rapido

Soluzioni Alternative

Se si vuole giocare con la tecnica, ci sono due punti interessanti che ho incontrato durante lo sviluppo del progetto. Potresti averne bisogno prima di modificare il progetto:

  • Il Windows Loader utilizza un algoritmo simile alla Ricerca Binaria per trovare la funzione esportata se si chiama GetProcAddress con un nome. Per questo motivo, i nomi di tutte le funzioni esportate, incluse quelle nascoste, devono essere ordinati nell'array AddressOfNames. Altrimenti, la funzione GetProcAddress restituisce NULL. Pertanto, ho utilizzato l'algoritmo Bubble Sort per ordinare i membri di questo array.
  • Come detto sopra, l'array AddressOfNames, l'array AddressOfFunctions, l'array DataDirectory e alcuni altri campi richiedono valori in Indirizzi Virtuali Relativi (RVA). Inoltre, mantengono questi valori RVA in campi di dimensione DWORD. Quando si alloca una regione di memoria per una nuova directory di esportazione arbitraria utilizzando funzioni di allocazione dinamica della memoria come VirtualAlloc o HeapAlloc, gli indirizzi forniti saranno lontani dalla regione mappata della DLL, e i valori RVA non entrano nei campi di dimensione DWORD, e si incontra un overflow intero. Ecco perché ho utilizzato variabili globali con il tipo array di byte nel template DLL per i requisiti di memoria.

Caso di DLL Importata Staticamente (alias DLL Sideloading)

Il mio primo obiettivo mentre creavo questo progetto era generare una DLL che ha esportazioni mancanti (o una completa mancanza di una tabella di esportazione) ma che viene comunque caricata con successo dal processo appena creato. Pensavo che quel comportamento potesse portare un nuovo terreno di gioco per i payload di DLL sideloading. Tuttavia, non sono riuscito a trovare alcuna funzione o modo in cui lo stub di correzione della directory di esportazione venga eseguito prima che il Windows Loader controlli le funzioni esportate della DLL.

dll_timing_problem (1)

Più tecnicamente, ho notato il seguente flusso e chiamata di funzione per ogni DLL nelle sezioni di codice relative al Windows Loader in NTDLL (raccolte dai miei vecchi appunti; potrebbero esserci alcuni errori perché non sono un reverse engineer esperto):

root@kitploit:~
1. LdrpMapDll - Qui è dove la DLL viene mappata nello Spazio degli Indirizzi del Processo. Tutte le DLL che soddisfano la condizione del nome DLL 
                vengono direttamente inserite in memoria, nessun controllo precheck per la versione del filesystem.
2. LdrpSnapModule - Qui è dove il Windows Loader inizia a risolvere le importazioni. Per ogni descrittore di importazione, analizza la struttura 
                    PE, controlla la tabella di esportazione, cerca binariamente la funzione importata, calcola l'RVA di quella,
                    e scrive il suo indirizzo nell'entry corrispondente della Tabella degli Indirizzi di Importazione del processo chiamante durante questa funzione.
3. LdrpDoPostSnapWork - Se il passo 2 ha successo per ogni funzione importata, in questa funzione vengono eseguite le protezioni di memoria, l'inizializzazione TLS, l'abilitazione CFG.
4. LdrpInitializeNode - Se il passo 3 ha successo, in questo passo ci sono funzioni di collegamento dei moduli.
5. LdrpCallTlsInitializers - Qui è dove vengono chiamati i callback TLS prima della funzione DllMain.
6. LdrpCallInitRoutine - Qui è dove la DLLMain stessa viene chiamata per la prima volta per la DLL importata. Nella soluzione 
                         originale, questa funzione è troppo tardi per correggere la tabella di esportazione.

Quando si esegue un eseguibile che importa una DLL, se il Windows loader non riesce a trovare il nome della funzione richiesta nella tabella di esportazione della DLL, interrompe l'esecuzione e non esegue funzioni che vengono eseguite dopo LdrpSnapModule.

Per il caso di DLL sideloading, non possiamo modificare il processo chiamante; quindi, l'unica possibilità per correggere dinamicamente la Tabella di Esportazione è trovare un'opportunità di esecuzione del codice tra le funzioni LdrpMapDll e LdrpSnapModule perché il Loader si ferma immediatamente durante i controlli della funzione LdrpSnapModule. Ho provato callback TLS, secondi caricamenti di DLL, esportazioni inoltrate e alcune altre soluzioni alternative, ma nessuna mi ha aiutato a trovare un posto del genere, quindi sfortunatamente questo metodo non funziona direttamente per DLL sideloading o DLL importate staticamente. Se scopri una soluzione o una soluzione alternativa valida per questo problema, sarei molto felice di esplorarla ulteriormente — che si tratti di discutere l'idea, pensare all'approccio insieme o implementarla. Qualsiasi contributo in questa direzione sarebbe molto apprezzato.

Un modo possibile per utilizzare questo metodo per i casi di DLL Sideloading è dividere l'intero lavoro in due DLL, ovvero la DLL Proxy e la DLL Payload. La DLL Proxy prende il nome che l'EXE si aspetta e ha esportazioni visibili che soddisfano il controllo di importazione statica del loader, mentre la DLL Payload contiene la funzionalità nascosta reale, ha esportazioni mancanti e ricostruisce la sua tabella di esportazione in DllMain. Non penso che questa sia una buona soluzione alternativa per questo problema, quindi non l'ho implementata.

Riferimenti

  • https://rioasmara.com/2021/10/10/analyze-dll-export-with-pe-bear/
  • https://ferreirasc.github.io/PE-Export-Address-Table/

Disclaimer

Solo per test di sicurezza autorizzati. L'uso improprio di questo strumento contro sistemi senza esplicita autorizzazione è illegale.

Scarica lo strumento