Come posso nascondere e proteggere completamente le stringhe dal giocatore in Unity?


47

Ho usato Unity per creare un gioco 2D che sarà completamente offline (che è il problema), il gioco richiede l'inserimento di determinate stringhe a determinati livelli e Unity si compila in DLL, che possono essere facilmente decodificate, quindi è esiste un modo per proteggere quelle stringhe (il gioco è offline quindi non riesco a recuperare da altre fonti)?

Il gioco fa molto affidamento su queste stringhe, e sì, sono a conoscenza di Obfuscation ma voglio qualcosa di più robusto. E so che la semplice via d'uscita sarebbe fare tutto online da una fonte di dati, ma mi chiedevo se fosse possibile.

Può essere decompilato in questo modo: inserisci qui la descrizione dell'immagine


10
Mentre sono d'accordo che è una battaglia che non puoi mai veramente vincere, puoi sicuramente renderla più difficile con un piccolo sforzo. obfuscar.codeplex.com
Jacob Persi

46
@Gabriele Huh? Decompilare il codice C # non offuscato è quasi semplice. In questo modo ottieni un codice praticamente perfettamente leggibile, confrontalo con quello che IDA genera per il codice C o C ++ ottimizzato. Detto questo, con sufficiente sforzo, il codice nativo può essere compreso tanto, ma i suoi ordini di grandezza sono più difficili. Non ho idea di quanto bene funzioni l'offuscamento - se fa cadere i soliti decompilatori (DotPeek, ILSpy, qualcos'altro?) Sul codice IL che dovrebbe introdurre una barriera per tenere lontano la persona casuale.
Voo,

15
@GabrieleVierti, estrarre il testo da una DLL è banale: sotto Linux o Cygwin, puoi farlo semplicemente puntando il stringsprogramma su di esso.
Segna il

31
Cosa stai esattamente cercando di fare qui? Sembra un caso piuttosto grave del problema XY. meta.stackexchange.com/questions/66377/what-is-the-xy-problem Qualunque cosa tu stia cercando di realizzare (dal punto di vista del gameplay, non dal punto di vista tecnico) non è quasi certamente il migliore servizio cercando di nascondere e crittografare queste stringhe .
GrandOpener,

36
Mi chiedo se nascondere le stringhe abbia effettivamente uno scopo: una volta che alcuni giocatori le hanno risolte, molto probabilmente si diffonderanno in wiki o simili, quindi chiunque voglia conoscerle sarà facilmente in grado di cercarle. Sì, offuscandoli, il giocatore non può semplicemente aprire la dll in un editor di testo e cercare stringhe, ma la maggior parte consulterà prima google (o il loro motore di ricerca preferito) ...
hoffmale

Risposte:


159

Non archiviare quelle stringhe, memorizzarne l'hash (crittografico).

Una funzione hash (crittografica), come la crittografia, è un modo per trasformare una stringa in "incomprensibile" (chiamato hash), ma a differenza della crittografia, non è possibile ottenere la stringa originale da questo hash (a meno che non sia possibile forzare la forza o l'hash la funzione è interrotta). La maggior parte (se non tutte) le funzioni hash accetta una stringa di lunghezza arbitraria e restituisce una stringa di lunghezza costante (dipende dalla funzione).

Come si controlla che una stringa immessa dall'utente sia quella corretta? Poiché non è possibile ottenere la stringa valida dall'hash, l'unica cosa che è possibile fare è eseguire l'hash dell'ipotesi dell'utente e confrontarla con l'hash corretta.

Avvertenza (di Eric Lippert): NON UTILIZZARE la funzione integrata in GetHashCodequanto tale - il suo risultato può differire tra versioni e piattaforme .NET diverse, facendo funzionare il codice solo su versioni e piattaforme .NET Framework specifiche.


81
Questa è davvero la risposta migliore. Ma ricorda che non devi assolutamente usare l'algoritmo di hash incorporato nelle stringhe . è progettato per fare solo una cosa e una cosa e cioè bilanciare una tabella di hash. Non è possibile archiviare hash di stringhe e utilizzarli come autenticatori di un segreto condiviso poiché gli autori di runtime .NET si riservano il diritto di modificare l'algoritmo di hashing delle stringhe in qualsiasi momento per qualsiasi motivo e in effetti lo hanno già fatto in passato . Usa un hash standard di cripto-forza o implementa il tuo hash semplice.
Eric Lippert,

4
Questo. Esattamente. Se usi un algoritmo come sha256 (ci sono molte librerie che implementano questo in modo da non dover scrivere il tuo) allora avrai qualcosa che non può essere rotto facilmente ed è molto affidabile.
Micheal Johnson,

12
@Michael Johnson usando un salt renderà molto più difficile usare le tabelle arcobaleno, e usare un hash password come bcrypt renderà molto più lento e quindi più difficile da rompere. Ma alla fine, alla fine, questo sembra uno sforzo eccessivo; l'utente ha acquistato il gioco se vuole imbrogliare questa è la sua scelta
Melkor,

2
@MichealJohnson: l' allungamento delle chiavi potrebbe rendere un po 'più difficile un attacco di forza bruta (diciamo, di un fattore di circa un miliardo). Ma il vero problema con questa risposta è che, presumibilmente, ad un certo punto il gioco deve essere in grado di dire al giocatore in quale stringa devono entrare. A meno che quelle stringhe non siano in realtà soluzioni a una sorta di puzzle che il giocatore deve risolvere, immagino. O a meno che le stringhe non siano fornite online, anche se il gioco è offline, un po 'come chiavi di licenza vecchio stile.
Ilmari Karonen,

5
@Sentinel Ciò significa che il gameplay potrebbe essere diverso per i diversi giocatori. Dobbiamo davvero sapere di che tipo di stringhe stiamo parlando, se sono contenute in libri / segni / dialoghi all'interno del gioco, se sono soluzioni ai puzzle in cui la risposta effettiva non viene data direttamente al giocatore, o se sono generati casualmente. E se sono parole, frasi o caratteri casuali.
Micheal Johnson,

106

Quello che stai cercando di fare è inutile e inutile.

È inutile perché non c'è modo di nascondere correttamente le informazioni che si trovano sul computer dell'utente. Chiunque sia abbastanza dedicato lo troverà. Puoi renderlo più difficile, ma non puoi mai prevenirlo. Se lo crittografate, è necessario archiviare la chiave di crittografia e l'algoritmo da qualche parte. Indipendentemente dal numero di livelli di crittografia aggiunti, il livello più esterno dovrà sempre essere non crittografato affinché il gioco funzioni.

È anche inutile, perché viviamo nell'era di Internet. Quando il tuo gioco diventa molto popolare in remoto, questi passcode saranno pubblicati su tutto il Web.

Tutto quello che puoi fare è fidarti che il giocatore non rovini la propria esperienza di gioco cercando informazioni che il gioco non dovrebbe ancora dire. La stragrande maggioranza dei giocatori non inizierà comunque a decodificare il gioco. E se i pochi che hanno le competenze necessarie lo fanno, allora è colpa loro.


38
Il reverse engineering è un gioco tutto suo! Questa è l'unica risposta corretta: al giorno d'oggi non si dovrebbero nascondere informazioni nei giochi per giocatore singolo, i giocatori accederanno se lo desiderano.
Mephy,

27
@TheBinaryGuy Sicurezza da cosa? I tuoi utenti stanno giocando una partita offline . Quale minaccia presenta l'esposizione del codice? Il giocatore alla fine dovrebbe scoprirlo comunque per poter giocare! Un'importante regola di sicurezza è che è necessario identificare il trattamento da cui si sta proteggendo; questo è indicato come un "modello di minaccia".
jpmc26,

7
@TheBinaryGuy Oltre agli altri punti, metterei in dubbio la sensibilità dell'utilizzo di passcode "fissi" - anche senza cercare i codici online / tramite reverse engineering, solo giocare una seconda volta consentirà ai giocatori di saltare direttamente sezioni del gioco (poiché conoscono già i codici). Se vuoi davvero "forzare" i giocatori a guadagnare questi codici devi farli cambiare su ogni playthrough (es: avere una qualche forma di randomizzazione)
UnholySheep

6
Questa risposta ha alcuni punti positivi ma il secondo paragrafo non è corretto. Non è necessario crittografare la stringa. Puoi hash. Se un giocatore può rompere l'hash, invece deruba i conti bancari, sarà assunto dall'FBI o qualcosa del genere. Gli altri punti sono validi però.
Pedro A,

5
@Hamsterrific Immagino che la risposta presuma che tu abbia bisogno di memorizzare le stringhe effettive, ad es. Per mostrarle al giocatore ad un certo punto, il che significa che l'hash non funzionerà.
Frank Hopkins,

4

Se una cosa del genere è davvero desiderata, quindi invece di eseguire l'hashing, potresti considerare di costruire le stringhe da un valore di input numerico in fase di esecuzione.

Il vantaggio è che, come sottolineato da @Philipp, è in qualche modo inutile cercare di nascondere i codici nell'eseguibile se ci si può aspettare che vengano comunque pubblicati su Internet. Tratteggiato o meno, la stessa parola trovata su Internet e inserita nel gioco darà lo stesso hash e funzionerà in entrambi i modi.

Tranne ... tranne se il codice di qualcun altro non funziona per te. Cosa che puoi fare banalmente - non al 100% a prova di manomissione ma ragionevolmente difficile da aggirare per l'utente medio. Qualunque cosa semplice come farà il "Generatore di nomi di elfi online" (può essere arbitrariamente semplice, in realtà non ha bisogno di un gran motore di testo markov, estrarre 4-5 sillabe da un elenco casuale è abbastanza buono).

Basta generare un numero un po 'specifico dell'utente o specifico della macchina, non deve nemmeno essere perfettamente unico o molto resistente alle manomissioni. Qualcosa che è probabilmente diverso per la maggior parte delle persone e che difficilmente cambierà regolarmente, ad esempio il nome di rete del computer, l'indirizzo MAC o il GUID dell'unità disco di sistema, qualunque cosa (il numero di serie della GPU potrebbe essere un pessimoidea dal momento che è probabile che gli utenti aggiornino le GPU). Aggiungi a quello il codice numerico a cui fa riferimento il codice di sblocco e inseriscilo nel tuo generatore di parole. Preparati a rispondere alle domande di supporto quando i giocatori usano due computer o cambiano la loro scheda di rete (cosa insolita, ma non impossibile). Potrebbe essere un buon piano generare l'ID casuale una sola volta e memorizzarlo con le impostazioni del gioco. In questo modo, almeno non interrompe le installazioni esistenti sulla stessa macchina se qualcosa cambia.

Oppure, potresti semplicemente usare il numero di serie del gioco che è unico e funzionerà se l'utente cambia hardware (ironicamente, tuttavia, ciò potrebbe promuovere la pirateria poiché i codici di sblocco condivisi funzionano per i serial piratati ma non per i clienti legittimi!).

Nota che impedire agli utenti di barare non è necessariamente una buona cosa. In un gioco offline (ovvero un gioco non competitivo) di solito non è un problema se l'utente imbroglia e ottiene i codici da qualche parte piuttosto che dal giocare. Si sta solo tradendo. Che importa.
D'altra parte, mettersi troppo sulla loro strada se vogliono davvero imbrogliare è una grande opportunità per far incazzare completamente i clienti paganti.

Quindi ... prima di fare qualcosa in quel modo, pensa attentamente se lo vuoi davvero e cosa vuoi. Molto probabilmente, avere stringhe leggibili dall'uomo (o rese banalmente "illeggibili" con xor) è abbastanza buono e anzi preferibile.


Quale processo prevedi? Se il programma genera il valore hash dopo il download, deve avere la stringa non cancellata quando viene scaricato. Quindi il server interrogherà il client per identificare le informazioni e quindi genererà l'hash lato server?
Accumulo

@ Accumulazione: quale server? Q dice "completamente offline". Il che probabilmente significa un programma su un DVD (o forse un download) più un numero seriale. Quindi hai eventi 1,2,3,4 per i quali deve esistere un passcode. Si calcola ad esempio hash(serial + 1)per ottenere un numero corrispondente al primo codice. Quindi inseriscilo nel tuo generatore di parole, che estrae, diciamo, una sillaba da un elenco di 16 per ogni 4 bit di input. Ecco qua, singole "parole" per ogni utente.
Damon,

Se si tratta di un download, viene scaricato da un server. Se il programma calcola hash(serial+1) dopo il download, cosa impedisce all'utente di calcolare hash(serial+1)? Una volta scaricato il programma, l'utente ha accesso a tutto ciò che fa il programma.
Accumulo

@ Accumulazione: nulla impedisce all'utente di decompilare prima il programma e quindi di calcolarlo hash(serial + 1). E allora? Questo non è un problema. Guarda, se qualcuno investe da una a due ore (probabilmente 6-8 ore per un tipico "utente" senza background di sviluppatori software) solo per ingannare se stesso, beh ... lascialo. Il fatto è che funziona per una persona, ma non per tutti, e non è competitivo ... quindi, nessun problema.
Damon,

3

Se non hai bisogno di mostrare le stringhe, allora l'idea di hashing è probabilmente la strada da percorrere. Se, d'altra parte, è necessario mostrarli all'utente, esistono altri modi per evitare che vengano visualizzati direttamente nella DLL.

Un modo per affrontare questo oltre a crittografare o altrimenti offuscare le stringhe è quello di romperle. Forse hai solo un dizionario in ordine alfabetico di tutte le parole possibili da tutte le stringhe del gioco. Quindi disponi di un array da qualche parte che ti permetta di mettere insieme le parole nella stringa di cui hai bisogno indicizzandole nell'array di parole. In questo modo non hai le stringhe complete in nessuna parte del gioco. Non è necessaria la chiave master per decrittografare le stringhe. E i dati che indicano il loro ordine potrebbero trovarsi su tutta l'origine, se, ad esempio, ogni funzione che utilizzava una stringa avesse appena un array di indici locali alla funzione. Non sono sicuro di quanto sia pratico nel tuo caso specifico, ma è un modo per farlo.

Potresti anche avere una stringa composta da poche parole, ma finiscono per essere ordinate diversamente. Ad esempio, potresti aver bisogno delle seguenti 2 stringhe:

  1. Un orso ha attraversato la mia casa
  2. La mia casa mi ha protetto da un orso

Il tuo elenco di frasi conterrebbe sia "un orso" che "la mia casa", ma avresti un ampio elenco di altre frasi che potrebbero essere inserite tra di loro, quindi capire quale sarebbe difficile quanto capire il puzzle nel gioco (o qualunque cosa). Ad esempio, le frasi d'azione potrebbero essere "percorse", "bruciate", "spinte", "protette da", "separate da", "prodotte magicamente", ecc.

Puoi farlo nel tuo gioco facendo in modo che gli indici siano basati su qualcosa che il giocatore ha raccolto o fatto. Quindi non ci sarebbe un elenco principale di indici in qualsiasi parte del gioco. Sarebbero generati dal giocatore che gioca.


4
Quindi, invece di trovare la funzione che fa riferimento a una stringa specifica, trovi la funzione che fa riferimento a una matrice con indici e quindi ricrea la stringa. Non sembra altro che una protezione aggiuntiva di 30 secondi. Ciò che protegge contro è qualcuno che utilizza solo stringscontro l'eseguibile.
Voo,

Come ho detto, se gli array che fanno riferimento alle stringhe sono distribuiti a tutte le funzioni che ne hanno bisogno, è un po 'più difficile che trovare un singolo array in una singola funzione. Non impossibile, ma copre un'area più ampia senza molto lavoro extra.
user1118321

Non è solo una forma minore di crittografia?
Arturo Torres Sánchez,

2
Aspetta, nemmeno la crittografia. Solo codifica.
Arturo Torres Sánchez,

2
Ho aggiornato la risposta per essere più chiara. Fondamentalmente, se gli indici sono basati su qualcosa che il giocatore ha fatto, allora non sono effettivamente memorizzati nel gioco. Ancora una volta, potrebbe non essere infallibile o perfetto, ma lo sto mettendo qui come un'opzione che la gente potrebbe voler esplorare.
user1118321
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.