Come bloccare le classi Java compilate per impedire la decompilazione?


96

Come posso bloccare le classi Java compilate per impedire la decompilazione?

So che questo deve essere un argomento discusso molto bene su Internet, ma non sono riuscito a giungere a nessuna conclusione dopo averlo riferito.

Molte persone suggeriscono l'offuscatore, ma si limitano a rinominare classi, metodi e campi con sequenze di caratteri difficili da ricordare, ma che dire dei valori costanti sensibili?

Ad esempio, hai sviluppato il componente di crittografia e decrittografia basato su una tecnica di crittografia basata su password. Ora, in questo caso, qualsiasi persona Java media può utilizzare JAD per decompilare il file di classe e recuperare facilmente il valore della password (definito come costante) così come il sale ea sua volta può decriptare i dati scrivendo un piccolo programma indipendente!

O tali componenti sensibili dovrebbero essere costruiti in codice nativo (ad esempio, VC ++) e chiamarli tramite JNI ?


Anche il codice nativo disassemblato è abbastanza leggibile per alcune persone, dovresti probabilmente usare qualche offuscatore o assemblaggio fatto a mano per renderlo non ovvio (il comune C ++ compilato con l'ottimizzazione è abbastanza leggibile). Qualunque codice venga eseguito sul dispositivo dell'utente, può essere intercettato. Sebbene i requisiti di costo / abilità di tali intercettazioni possano essere piuttosto elevati, ad esempio la violazione del codice dei chip "a prova di manomissione" delle smart card non è banale, ma fattibile solo con le migliori attrezzature e abilità. Con le classi Java ... non mi preoccuperei molto, probabilmente puoi crittografarle abbastanza da allontanare i ragazzi degli script, non di più.
Ped7g

Risposte:


96

Alcuni degli offuscatori di bytecode Java più avanzati fanno molto di più che modificare il nome di una classe. Zelix KlassMaster , ad esempio, può anche rimescolare il flusso del codice in un modo che lo rende davvero difficile da seguire e funziona come un eccellente ottimizzatore di codice ...

Inoltre, molti degli offuscatori sono anche in grado di rimescolare le costanti di stringa e rimuovere il codice inutilizzato.

Un'altra possibile soluzione (che non esclude necessariamente l'offuscamento) è quella di utilizzare file JAR crittografati e un classloader personalizzato che esegue la decrittografia (preferibilmente utilizzando la libreria runtime nativa).

Terzo (e possibilmente che offre la protezione più forte) è utilizzare compilatori nativi anticipati come GCC o Excelsior JET , ad esempio, che compilano il codice Java direttamente su un binario nativo specifico della piattaforma.

In ogni caso, devi ricordare che, come si suol dire in estone, "le serrature sono per gli animali". Significa che ogni bit di codice è disponibile (caricato in memoria) durante il runtime e con sufficiente abilità, determinazione e motivazione, le persone possono decompilare, decodificare e hackerare il tuo codice ... Il tuo compito è semplicemente rendere il processo scomodo come puoi e continuare a far funzionare la cosa ...


13
+1 per "Le serrature sono per gli animali". Immagino che il termine appropriato qui sarebbe script kiddies.
Antimonio

Vuoi dire GCJ, ed è morto.
Marchese di Lorne

1
Anche la crittografia del file jar Componio è morta. Usa invece JarProtector .
J.Profi

16

Finché hanno accesso sia ai dati crittografati che al software che li decrittografa, praticamente non è possibile renderli completamente sicuri. Il modo in cui questo è stato risolto in passato è quello di utilizzare una qualche forma di scatola nera esterna per gestire la crittografia / decrittografia, come dongle, server di autenticazione remoti, ecc. Ma anche in questo caso, dato che l'utente ha pieno accesso al proprio sistema, questo fa solo cose difficile, non impossibile, a meno che tu non possa legare il tuo prodotto direttamente alle funzionalità memorizzate nella "scatola nera", come, ad esempio, i server di gioco online.


13

Disclaimer: non sono un esperto di sicurezza.

Sembra una cattiva idea: permetti a qualcuno di crittografare le cose con una chiave "nascosta" che gli dai. Non credo che questo possa essere reso sicuro.

Forse le chiavi asimmetriche potrebbero funzionare:

  • distribuire una licenza crittografata con una chiave pubblica per decrittografare
  • lascia che il cliente crei una nuova licenza e te la invii per la crittografia
  • inviare una nuova licenza al client.

Non ne sono sicuro, ma credo che il client possa effettivamente crittografare la chiave di licenza con la chiave pubblica che gli hai fornito. Puoi quindi decrittografarlo con la tua chiave privata e anche ricodificarlo.

Potresti mantenere una coppia di chiavi pubblica / privata separata per cliente per assicurarti di ricevere effettivamente le cose dal cliente giusto: ora sei responsabile delle chiavi ...


2
Ho usato questa tecnica prima e funziona bene. Tuttavia, dal punto di vista dell'attacco, il primo approccio sarebbe semplicemente modificare il codice che esegue il controllo della licenza e rimuoverlo. Ci sono cose che puoi fare per rendere questo vettore di attacco più difficile, ma se dai al malintenzionato il controllo dell'hardware, sei destinato a fallire con un attaccante adeguatamente motivato e qualificato. In pratica, l'obiettivo è solo quello di mantenere le persone per lo più oneste, oneste.
Jim Rush

12

Qualunque cosa tu faccia, può essere "decompilato". Diamine, puoi semplicemente smontarlo. Oppure guarda un dump della memoria per trovare le tue costanti. Vedi, il computer ha bisogno di conoscerli, quindi anche il tuo codice dovrà esserlo.

Cosa fare al riguardo?

Cerca di non inviare la chiave come costante hardcoded nel tuo codice: tienila come impostazione per utente. Rendere l'utente responsabile della cura di quella chiave.


6

@jatanp: o meglio ancora, possono decompilare, rimuovere il codice di licenza e ricompilare. Con Java, non credo che esista una soluzione adeguata a questo problema a prova di hacker. Nemmeno un piccolo dongle malvagio potrebbe impedirlo con Java.

I miei manager aziendali si preoccupano di questo, e penso troppo. Ma poi di nuovo, vendiamo la nostra applicazione a grandi società che tendono a rispettare le condizioni di licenza, generalmente un ambiente sicuro grazie ai contatori di fagioli e agli avvocati. L'atto di decompilarsi può essere illegale se la tua licenza è scritta correttamente.

Quindi, devo chiedere, hai davvero bisogno di una protezione rafforzata come stai cercando per la tua applicazione? Com'è la tua base di clienti? (Aziende? O le masse di giocatori adolescenti, dove questo sarebbe più un problema?)


In effetti, esiste una soluzione adeguata, a prova di hacker che tra l'altro sembra un dongle: excelsior-usa.com/blog/excelsior-jet/…
Dmitry Leskov

@DmitryLeskov "resistente agli hack", forse. Ma è solo un aumento di velocità per chiunque desideri il codice. Alla fine della giornata, il codice byte deve essere eseguito su una piattaforma host non crittografata. Punto.
Stu Thompson

Non hai letto il post a cui mi sono collegato. Il bytecode viene convertito nel codice CPU del dongle e crittografato. Quando l'utente finale esegue l'app protetta, il codice crittografato viene trasferito al "dongle". Il dongle lo decrittografa e lo esegue sulla sua CPU.
Dmitry Leskov

2
Giocatori adolescenti aziendali.
odiszapc

3

Se stai cercando una soluzione di licenza, puoi controllare l' API TrueLicense . Si basa sull'uso di tasti asimmetrici. Tuttavia, ciò non significa che la tua applicazione non possa essere violata. Ogni applicazione può essere violata con sufficiente sforzo. Ciò che è veramente importante, come ha risposto Stu , è capire quanto sia forte la protezione necessaria.


2

Non credo che esista un metodo antipirateria offline efficace. L'industria dei videogiochi ha cercato di scoprirlo molte volte ei loro programmi sono sempre stati violati. L'unica soluzione è che il programma debba essere eseguito online connesso ai tuoi server, in modo da poter verificare la chiave di licenza, e che ci sia una sola connessione attiva alla volta da parte del licenziatario. Ecco come funzionano World of Warcraft o Diablo . Anche se ci sono server privati ​​sviluppati per aggirare la sicurezza.

Detto questo, non credo che le aziende medio / grandi utilizzino software copiato illegalmente, perché il costo della licenza per loro è minimo (forse, non so quanto vuoi far pagare per il tuo programma) rispetto a il costo di una versione di prova.


2

Puoi utilizzare la crittografia byte-code senza paura.

Il fatto è che il documento sopra citato “Cracking Java byte-code encryption” contiene un errore logico. L'affermazione principale del documento è che prima di eseguire tutte le classi devono essere decrittografate e passate al ClassLoader.defineClass(...)metodo . Ma questo non è vero.

L'ipotesi qui mancata è che siano in esecuzione in un ambiente run-time java autentico o standard . Niente può obbligare l'app java protetta non solo a lanciare queste classi ma anche a decrittarle e passarle ClassLoader. In altre parole, se sei in JRE standard non puoi intercettare il defineClass(...)metodo perché il java standard non ha API per questo scopo, e se usi JRE modificato con patch ClassLoadero qualsiasi altro "trucco hacker" non puoi farlo perché protetto l'app java non funzionerà affatto e quindi non avrai nulla da intercettare. E non importa assolutamente quale "patch finder" viene utilizzato o quale trucco viene utilizzato dagli hacker. Questi dettagli tecnici sono una storia completamente diversa.


Come intendi rilevare esattamente una JVM patchata? Ad ogni modo, tutto ciò che fa è rendere le cose leggermente più difficili.
Antimonio

Non riesci a trovare una chiamata a defineClass () nel tuo programma di avvio delle app? Quando effettui quella chiamata, devi comunque consegnare un array di byte decrittografati. Non è un altro punto in cui la fonte originale potrebbe trapelare?
Ascendente

4
Non sono davvero d'accordo con questa risposta. Per me questo suona come, "Domanda: qual è il modo più semplice per trovare Pi? Risposta: prendi 2 * Pi e dividi per due". Non sono in disaccordo con l'idea, ma potresti includere maggiori dettagli? Ad esempio, ti aspetti che il programma principale sia scritto in puro java? Questo include il codice che sta cercando modifiche?
Patrick M

-1

D: Se crittografo i miei file .class e utilizzo un classloader personalizzato per caricarli e decrittografarli al volo, questo impedirà la decompilazione?

R: Il problema di impedire la decompilazione del codice byte Java è vecchio quasi quanto il linguaggio stesso. Nonostante una gamma di strumenti di offuscamento disponibili sul mercato, i programmatori Java alle prime armi continuano a pensare a modi nuovi e intelligenti per proteggere la loro proprietà intellettuale. In questa puntata di domande e risposte su Java, sfoglio alcuni miti su un'idea che viene spesso rimossa nei forum di discussione.

L'estrema facilità con cui i file Java .class possono essere ricostruiti in sorgenti Java che assomigliano molto agli originali ha molto a che fare con gli obiettivi di progettazione del codice byte Java e con i compromessi. Tra le altre cose, il codice byte Java è stato progettato per compattezza, indipendenza dalla piattaforma, mobilità di rete e facilità di analisi da parte di interpreti di codice byte e compilatori dinamici JIT (just-in-time) / HotSpot. Probabilmente, i file .class compilati esprimono l'intento del programmatore in modo così chiaro che potrebbero essere più facili da analizzare rispetto al codice sorgente originale.

Si possono fare diverse cose, se non per impedire completamente la decompilazione, almeno per renderla più difficile. Ad esempio, come passaggio di post-compilazione è possibile massaggiare i dati .class per rendere il codice byte più difficile da leggere quando decompilato o più difficile da decompilare in codice Java valido (o entrambi). Tecniche come l'esecuzione di un sovraccarico estremo del nome del metodo funzionano bene per il primo e la manipolazione del flusso di controllo per creare strutture di controllo che non è possibile rappresentare tramite la sintassi Java funziona bene per il secondo. Gli offuscatori commerciali di maggior successo utilizzano un mix di queste e altre tecniche.

Sfortunatamente, entrambi gli approcci devono effettivamente modificare il codice che verrà eseguito dalla JVM e molti utenti temono (giustamente) che questa trasformazione possa aggiungere nuovi bug alle loro applicazioni. Inoltre, la ridenominazione di metodi e campi può causare l'interruzione del funzionamento delle chiamate di riflessione. La modifica dei nomi delle classi e dei pacchetti effettivi può interrompere diverse altre API Java (JNDI (Java Naming and Directory Interface), provider di URL, ecc.). Oltre ai nomi alterati, se l'associazione tra gli offset del codice byte di classe e i numeri di riga di origine viene alterata, il ripristino delle tracce dello stack di eccezioni originali potrebbe diventare difficile.

Poi c'è la possibilità di offuscare il codice sorgente Java originale. Ma fondamentalmente questo causa una serie simile di problemi. Crittografare, non offuscare?

Forse quanto sopra ti ha fatto pensare: "Bene, e se invece di manipolare il codice a byte crittografassi tutte le mie classi dopo la compilazione e le decifrassi al volo all'interno della JVM (cosa che può essere eseguita con un caricatore di classi personalizzato)? Allora la JVM esegue il mio codice byte originale e tuttavia non c'è nulla da decompilare o da decodificare, giusto? "

Sfortunatamente, sbaglieresti, sia nel pensare di essere stato il primo a proporre questa idea sia nel pensare che funzioni davvero. E il motivo non ha nulla a che fare con la forza del tuo schema di crittografia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.