Ciao,
Un obfuscator non fà altro che incasinare il codice, nei linguaggi interpretati (python/perl/ruby ecc...) incasina il codice sorgente che deve essere per forza presente per essere eseguito.
ad esempio:
def calcolaUnNumero():
a = 26
b = 5
c = 3
D = 28
a = b * c + d
return a
diventa
def __():
_ = 20 + 6 - 0
___ = 1+1+1+1+1
____ = 2-1+2
_$$_ = 20-8+16
_ = __ * ___ + _$$_
return _
Questo è un esempio stupidissimo i veri obfuscator fanno di peggio! L'importante è che però il codice è uguale a quello di prima solo è molto più difficile da leggere e capire per un umano!
I linguaggi compilati invece non portano con sè il codice sorgente ma possono essere studiati dalle loro istruzioni macchina. In questo particolare case l'obfuscator aggiunge alle routine codice in più (parliamo di pochissimi kilobyte) che non altera le prestazioni del programma (non spara la cpu al 100% fissa) ma semplicemente non fa nulla ovvero non modifica l'esecuzione del programma, rende solo la vita difficile a chi tenta di capire cosa fa una determinata routine!
nei linguaggi "intermedi" come .NET che comunque creano un eseguibile ma girano su una VM (mi si passi il termine) gli obfuscator usano un mix delle due tecniche.
Spero di esserti stato utile (perlomeno esaustivo)!
Ciao!