Packer (informatica)

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca

Un packer è uno strumento che permette di rendere difficile l'analisi di un file eseguibile o, semplicemente, di ridurne la dimensione. I packer vengono sovente usati nelle versioni limitate di prodotti commerciali per impedire, o perlomeno scoraggiare, la creazione di crack. Essi usano delle tecniche anti-debug e anti-disassembly sempre più avanzate che, se non sono interpretate nella maniera giusta dal debugger/disassembler, fanno perdere molto tempo al cracker (o al reverser in generale).

Un packer, una volta elaborato un file eseguibile, produce un nuovo file eseguibile (comunemente detto "packato") la cui struttura consta di un "loader" polimorfico (perlomeno nei packer di recente concezione) affiancato ad una versione modificata, per esempio mediante algoritmi crittografici, del codice originale. Il loader, una volta eseguito, eseguirà quindi le operazioni necessarie a ripristinare il codice originale e gli cederà il controllo.

Tecniche usate dai packer

[modifica | modifica wikitesto]

Le tecniche usate dai packer sono molteplici e, perlomeno quelle più conosciute, vengono rilevate e gestite correttamente dai più comuni disassembler. In particolare, disassembler come IDA pro riescono a riconoscere la presenza di un packer e permettono un disassembling selettivo del codice (l'utente decide cosa disassemblare e cosa no). Le tecniche si possono dividere in 2 macro categorie: tecniche anti-debug e tecniche anti-disassembly (anche se a volte la distinzione non è così netta). Le tecniche anti-debug sono tecniche volte ad impedire il debug dell'applicativo tentando, ad esempio, di rilevare se un debug è in corso. Le tecniche anti-disassembly sono tecniche volte a far perdere l'allineamento al disassembler per fare in modo di camuffare le istruzioni macchina derivanti da tale processo di decodifica.

Il junk code è una tecnica che consiste nel mischiare dati e codice insieme. Questa tecnica ha lo scopo di far perdere l'allineamento al disassembler, che tenterà di decodificare dei dati (e quindi non delle istruzioni). La tecnica usata dai disassembler più avanzati è quella di considerare "dati" tutto quello che, nel corso del programma, non verrà mai eseguito (anche se spesso non è molto facile determinarlo a priori a causa degli opaque predicates).

Il junk code è facilmente identificabile anche da un essere umano, perché la sua decodifica di solito produce:

  • errore, il codice non corrisponde a nessun opcode. In questo caso la presenza di junk code è palese.
  • istruzioni privilegiate, davvero insolite per un programma funzionante a livello utente.
  • salti a porzioni di codice visibilmente fuori dal programma. Questo avviene se il codice del junk code corrisponde ad un'istruzione di salto (condizionato o no).

Il junk code può essere usato anche per altri scopi.

Ad esempio, si consideri questa porzione di codice:

     call func1
     DB...
     jmp somewhere
  
  ...
  
  func1:
     pop ebx
     inc ebx
     push ebx
     ret

In questa porzione di codice viene chiamata la funzione func1 che incrementa l'indirizzo di ritorno di func1 per fare in modo che "DB ..." non venga eseguito. Nell'analisi di questa porzione di codice con un debugger, è facile accorgersi che lo step-over della funzione "func1" non ha l'effetto sperato: l'esecuzione continua fino al termine del programma. Questo è dovuto al fatto che i più comuni strumenti di debugging, nell'eseguire lo step-over, impostano un breakpoint subito dopo la chiamata della funzione. Di conseguenza per un debugger una funzione non è terminata fin quando l'instruction pointer non punta all'istruzione successiva alla CALL (evento che non accade mai nell'utilizzo di questa tecnica). Di conseguenza, il reverser è costretto a fare lo step-into di ogni funzione.

Opaque predicates

[modifica | modifica wikitesto]

Gli "opaque predicates" sono porzioni di codice che restituiscono un valore booleano predeterminato che, per qualche ragione, necessita di essere calcolato a run-time. Si consideri quest'esempio:

  mov eax,1
  ...
  cmp eax,1
  je func1
  jne somewhere

L'istruzione "cmp eax,1" restituirà sempre vero ma nonostante ciò il suo valore dovrà essere calcolato di volta in volta a run-time. Questa tecnica, in congiunzione a quella del junk code, può bastare per confondere i disassembler più semplici facendo perdere loro l'allineamento (il disassembler non è in grado di predire quale "ramo" verrà eseguito e quale no).

Virtual machine

[modifica | modifica wikitesto]

Questa tecnica è sicuramente una delle più difficili da gestire. Consiste nel simulare un microprocessore (con un set di istruzioni personalizzato). Tutti gli opcodes presenti nel programma dovranno quindi essere decodificati dal processore virtuale e, a loro volta, da quello reale. Come è facile intuire questa tecnica introduce un leggero overhead (ridotto al minimo utilizzando istruzioni di virtualizzazione, ove presenti).

L'entropia può essere usata per stabilire se un file ha subito un processo di "packing". Quest'approccio si basa sul fatto che normalmente i file eseguibili non packati possiedono al loro interno una certa sistematicità delle istruzioni, mentre invece un file packato si presenta comunemente come un insieme di dati casuali. Alla luce di questo è possibile affermare che più l'entropia di un file si avvicina allo zero, più aumentano le probabilità che il file non sia packato. In questo modo è possibile stabilire a priori, prima di un eventuale confronto della cosiddetta "firma" del file, se esso sia packato.

Lista di packer

[modifica | modifica wikitesto]

Per eseguibili in formato Portable Executable (Windows):

  • ASPack
  • ASPR (ASProtect)
  • Armadillo Packer
  • AxProtector
  • BeRoEXEPacker
  • CExe
  • exe32pack
  • EXE Bundle
  • EXECryptor
  • EXE Stealth
  • eXPressor
  • Enigma Protector Win32 / Win64
  • Enigma Virtual BOX – freeware
  • MPRESS – freeware
  • FSG (Fast Small Good)
  • HASP Envelope
  • kkrunchy – freeware
  • MEW – development stopped
  • NeoLite
  • Obsidium
  • PECompact
  • PEPack
  • PKLite32
  • PELock
  • PESpin
  • PEtite
  • Privilege Shell
  • RLPack
  • Sentinel CodeCover (Sentinel Shell)
  • Shrinker32
  • Smart Packer Pro
  • SmartKey GSS
  • tElock
  • Themida
  • UniKey Enveloper
  • Upack (software) – freeware
  • UPXfree software
  • VMProtect
  • WWPack
  • BoxedApp Packer
  • XComp/XPack – freeware

Per eseguibili New Executable (Windows):

  • PackWin
  • WinLite
  • PKLite 2.01

Per eseguibili OS/2:

  • NeLite
  • LxLite

Per eseguibili DOS:

  • 32LiTE
  • 624
  • AINEXE
  • aPACK
  • DIET
  • HASP Envelope
  • LGLZ
  • LZEXE – First widely publicly used executable compressor for microcomputers.
  • PKLite
  • PMWLITE
  • UCEXE
  • UPX
  • WDOSX
  • WWpack
  • XE

Per eseguibili ELF:

  • gzexe
  • HASP Envelope
  • UPX

Per eseguibili .NET assembly:

  • .NETZ
  • NsPack
  • Mpress
  • HASP Envelope
  • .netshrink
  • dotBundle
  • DotProtect: Commercial protector/packer for.net and mono. Features on-line verifications and "industry standard encryption".

Per eseguibili Mach-O (Apple Mac OS X):

  • HASP Envelope
  • UPX

Per eseguibili Java JAR:

  • HASP Envelope
  • pack200

Per eseguibili Java WAR:

  • HASP Envelope

Collegamenti esterni

[modifica | modifica wikitesto]
  Portale Sicurezza informatica: accedi alle voci di Wikipedia che trattano di Sicurezza informatica