Wie kann ich Saiten in Unity vollständig vor dem Player verbergen und schützen?

47

Ich habe Unity verwendet, um ein 2D-Spiel zu erstellen, das vollständig offline ist (was das Problem ist). Für das Gameplay müssen Sie bestimmte Zeichenfolgen auf bestimmten Ebenen eingeben und Unity wird in DLLs kompiliert, die problemlos rückentwickelt werden können gibt es eine Möglichkeit, diese Zeichenfolgen zu schützen (das Spiel ist offline, sodass ich sie nicht von einer anderen Quelle abrufen kann)?

Das Spiel stützt sich stark auf diese Saiten, und ja, ich bin mir der Verschleierung bewusst, aber ich möchte etwas Robusteres. Und ich weiß, dass der einfache Ausweg darin besteht, alles von einer Datenquelle aus online zu erledigen, aber ich habe mich gefragt, ob das möglich ist.

Es kann wie folgt dekompiliert werden: Bildbeschreibung hier eingeben

TheBinaryGuy
quelle
10
Ich bin damit einverstanden, dass es ein Kampf ist, den Sie niemals wirklich gewinnen können, aber Sie können es mit wenig Aufwand auf jeden Fall schwieriger machen. obfuscar.codeplex.com
Jacob Persi
46
@ Gabriele Huh? Das Dekompilieren von nicht verschleiertem C # -Code ist denkbar einfach. Auf diese Weise erhalten Sie so gut wie perfekt lesbaren Code. Vergleichen Sie dies mit dem, was IDA für optimierten C- oder C ++ - Code generiert. Das heißt, mit genügend Aufwand kann nativer Code genauso gut verstanden werden, aber es ist um Größenordnungen schwieriger. Keine Ahnung, wie gut die Verschleierung funktioniert - wenn es die üblichen Dekompilierer (DotPeek, ILSpy, etwas anderes?) Auf dem IL-Code blockiert, die eine Barriere einführen sollten, um die gelegentliche Person davon fernzuhalten.
Voo
15
@ Gabriele Vierti, das Abrufen von Text aus einer DLL ist trivial: Unter Linux oder Cygwin können Sie dies einfach tun, indem Sie das stringsProgramm darauf richten .
Mark
31
Was genau versuchst du hier zu tun? Dies klingt nach einem ziemlich schweren Fall des XY-Problems. meta.stackexchange.com/questions/66377/what-is-the-xy-problem Was auch immer Sie erreichen möchten (aus Gameplay-Sicht, nicht aus technischer Sicht), ist mit ziemlicher Sicherheit nicht der beste Weg, diese Zeichenfolgen zu verstecken und zu verschlüsseln .
GrandOpener
36
Ich frage mich, ob das Verstecken der Saiten tatsächlich einen Zweck erfüllt: Wenn einige Spieler sie gelöst haben, werden sie höchstwahrscheinlich in Wikis oder Ähnlichem verbreitet, sodass jeder, der sie kennenlernen möchte, leicht nach ihnen suchen kann. Ja, durch das Verschleiern kann der Spieler die DLL nicht einfach in einem Texteditor öffnen und nach Zeichenfolgen suchen, aber die meisten konsultieren zuerst Google (oder die von ihnen gewählte Suchmaschine) ...
hoffmale

Antworten:

159

Speichern Sie diese Zeichenfolgen nicht, sondern deren (kryptografischen) Hash.

Eine (kryptografische) Hash-Funktion ist wie die Verschlüsselung eine Möglichkeit, eine Zeichenfolge in "Kauderwelsch" (als Hash bezeichnet) umzuwandeln. Im Gegensatz zur Verschlüsselung können Sie die ursprüngliche Zeichenfolge jedoch nicht aus dieser Hash-Datei abrufen (es sei denn, Sie können sie oder den Hash erzwingen) Funktion ist kaputt). Die meisten (wenn nicht alle) Hash-Funktionen verwenden eine Zeichenfolge beliebiger Länge und geben eine Zeichenfolge konstanter Länge zurück (abhängig von der Funktion).

Wie können Sie überprüfen, ob eine vom Benutzer eingegebene Zeichenfolge korrekt ist? Da Sie die gültige Zeichenfolge nicht aus dem Hash abrufen können, können Sie nur die Vermutung des Benutzers mit einem Hash abgleichen und mit dem richtigen Hash vergleichen.

Warnung (von Eric Lippert): VERWENDEN Sie die integrierte Funktion NICHT GetHashCodeals solche - das Ergebnis kann zwischen verschiedenen .NET-Versionen und -Plattformen variieren, sodass Ihr Code nur auf bestimmten .NET Framework-Versionen und -Plattformen funktioniert.

user49822
quelle
81
Dies ist in der Tat die beste Antwort. Denken Sie jedoch daran, dass Sie den eingebauten Hash-Algorithmus auf keinen Fall für Zeichenfolgen verwenden dürfen . Es wurde entwickelt, um eine Sache und nur eine Sache zu tun, und zwar, um eine Hash-Tabelle auszugleichen. Sie können keine Hashes von Zeichenfolgen speichern und sie als Authentifikatoren eines gemeinsam genutzten Geheimnisses verwenden, da sich die .NET-Laufzeitautoren das Recht vorbehalten, den Algorithmus für das Hashing von Zeichenfolgen jederzeit und aus beliebigen Gründen zu ändern . Verwenden Sie einen Standard-Hash mit Kryptostärke oder implementieren Sie Ihren eigenen einfachen Hash.
Eric Lippert
4
Diese. Genau. Wenn Sie einen Algorithmus wie sha256 verwenden (es gibt viele Bibliotheken, die dies implementieren, so dass Sie keine eigenen schreiben müssen), haben Sie etwas, das nicht einfach zu knacken ist und sehr zuverlässig ist.
Micheal Johnson
12
@Michael Johnson, der ein Salz verwendet, erschwert die Verwendung von Regenbogentabellen erheblich, und die Verwendung eines Passwort-Hashs wie bcrypt verlangsamt die Verarbeitung und erschwert das Knacken. Aber letztendlich scheint dies viel zu viel Aufwand zu sein; Der Benutzer hat das Spiel gekauft, wenn er nach eigener Wahl betrügen möchte
Melkor
2
@MichealJohnson: Key Stretching könnte solche Brute-Force-Angriffe etwas schwieriger machen (etwa um den Faktor eine Milliarde). Das eigentliche Problem bei dieser Antwort ist jedoch, dass das Spiel vermutlich irgendwann in der Lage sein muss, dem Spieler mitzuteilen, welche Zeichenfolge er eingeben muss. Es sei denn, diese Zeichenfolgen sind Lösungen für eine Art Puzzle, das der Spieler lösen muss. Oder es sei denn, die Zeichenfolgen werden online bereitgestellt, obwohl das Spiel offline ist, ähnlich wie Lizenzschlüssel im alten Stil.
Ilmari Karonen
5
@Sentinel Das bedeutet, dass das Gameplay für verschiedene Spieler unterschiedlich sein kann. Wir müssen wirklich wissen, um welche Arten von Zeichenfolgen es sich handelt, ob sie in Büchern / Zeichen / Dialogen im Spiel enthalten sind oder ob es sich um Lösungen für Rätsel handelt, bei denen die eigentliche Antwort nicht direkt an den Spieler geht. oder wenn sie zufällig generiert werden. Und wenn es sich um Wörter, Sätze oder zufällige Zeichen handelt.
Micheal Johnson
106

Was Sie versuchen zu tun, ist sinnlos und sinnlos.

Es ist zwecklos, weil es keine Möglichkeit gibt, Informationen, die sich auf dem Computer des Benutzers befinden, ordnungsgemäß zu verbergen. Jeder, der genug engagiert ist, wird es finden. Sie können es schwieriger machen, aber Sie können es nie verhindern. Wenn Sie es verschlüsseln, müssen Sie den Verschlüsselungsschlüssel und den Algorithmus irgendwo speichern. Unabhängig davon, wie viele Verschlüsselungsebenen Sie hinzufügen, muss die äußerste Ebene immer unverschlüsselt sein, damit Ihr Spiel ausgeführt werden kann.

Es ist auch sinnlos, weil wir im Internetzeitalter leben. Wenn Ihr Spiel nur aus der Ferne populär wird, werden diese Passcodes im gesamten Web veröffentlicht.

Sie können nur darauf vertrauen, dass der Spieler sein Spielerlebnis nicht dadurch ruiniert, dass er nach Informationen sucht, die ihm das Spiel noch nicht mitteilen soll. Die überwiegende Mehrheit der Spieler wird Ihr Spiel sowieso nicht rückentwickeln. Und wenn die wenigen, die über die erforderlichen Fähigkeiten verfügen, dies tun, ist es ihre eigene Schuld.

Philipp
quelle
38
Reverse Engineering ist ein Spiel für sich! Dies ist die einzig richtige Antwort - man sollte heutzutage Informationen in Einzelspieler-Spielen nicht verbergen, die Spieler werden darauf zugreifen, wenn sie wollen.
Mephy
27
@TheBinaryGuy Sicherheit von was? Ihre Benutzer spielen ein Offline-Spiel . Welche Bedrohung birgt das Aufdecken des Codes? Der Spieler soll es schließlich trotzdem entdecken, um das Spiel spielen zu können! Eine wichtige Sicherheitsregel ist, dass Sie die Behandlung identifizieren müssen , vor der Sie schützen. Dies wird als "Bedrohungsmodell" bezeichnet.
jpmc26
7
@TheBinaryGuy Zusätzlich zu den anderen Punkten würde ich die Sinnhaftigkeit der Verwendung "fester" Passcodes in Frage stellen - selbst ohne die Codes online / durch Reverse Engineering nachzuschlagen, wird es den Spielern bereits ermöglichen, das Spiel ein zweites Mal zu spielen, um direkt durchzuspringen Abschnitte des Spiels (wie sie die Codes bereits kennen). Wenn du die Spieler wirklich dazu zwingen willst, sich diese Codes zu verdienen, musst du sie bei jedem Durchspielen ändern (z. B. eine Form der Randomisierung haben)
UnholySheep
6
Diese Antwort hat einige gute Punkte, aber der zweite Absatz ist falsch. Sie müssen die Zeichenfolge nicht verschlüsseln. Sie können es haschen. Wenn ein Spieler den Hash knacken kann, dann wird er stattdessen Bankkonten ausrauben, vom FBI engagiert werden oder so etwas. Die anderen Punkte sind jedoch gültig.
Pedro A
5
@Hamsterrific In der Antwort wird davon ausgegangen, dass Sie die tatsächlichen Zeichenfolgen speichern müssen, um sie z. B. dem Player zu einem bestimmten Zeitpunkt anzuzeigen, was bedeutet, dass Hashing nicht funktioniert.
Frank Hopkins
4

Wenn so etwas wirklich gewünscht ist, können Sie anstelle von Hashing die Zeichenfolgen zur Laufzeit aus einem numerischen Eingabewert erstellen.

Der Vorteil ist, dass es, wie von @Philipp hervorgehoben, etwas sinnlos ist, Codes in der ausführbaren Datei zu verstecken, wenn Sie damit rechnen können, dass sie ohnehin im Internet veröffentlicht werden. Ob mit oder ohne Hash, dasselbe Wort, das im Internet gefunden und in das Spiel eingegeben wurde, gibt den gleichen Hash und funktioniert in beide Richtungen.

Außer ... außer wenn der Code eines anderen nicht für Sie funktioniert . Was Sie trivialerweise tun können - nicht 100% manipulationssicher, aber für den Durchschnittsbenutzer einigermaßen umständlich. Alles, was so einfach ist wie der "Online Elven-Namensgenerator" (kann beliebig einfach sein, braucht wirklich nicht viel von einer Markov-Text-Engine, 4-5 Silben aus einer zufälligen Liste zu ziehen, ist gut genug).

Generieren Sie einfach eine etwas benutzerspezifische oder maschinenspezifische Nummer, sie muss nicht einmal absolut eindeutig oder sehr manipulationssicher sein. Etwas, das für die meisten Menschen wahrscheinlich anders ist und sich wahrscheinlich nicht regelmäßig ändert, z. B. der Netzwerkname des Computers, die MAC-Adresse oder die GUID des Systemlaufwerks, unabhängig davon (die GPU-Seriennummer ist möglicherweise sehr schlecht)Idee, da Benutzer wahrscheinlich GPUs aktualisieren). Fügen Sie dazu den numerischen Code hinzu, auf den sich der Entsperrcode bezieht, und geben Sie diesen in Ihren Textgenerator ein. Seien Sie jedoch bereit, Supportanfragen zu beantworten, wenn Spieler zwei Computer verwenden oder ihre Netzwerkkarte wechseln (was ungewöhnlich, aber nicht unmöglich ist). Es könnte ein guter Plan sein, die zufällige ID nur einmal zu generieren und mit den Einstellungen des Spiels zu speichern. Auf diese Weise werden zumindest vorhandene Installationen auf demselben Computer nicht beschädigt, wenn sich etwas ändert.

Oder Sie verwenden einfach die Seriennummer des Spiels, die eindeutig ist und funktioniert, wenn der Benutzer die Hardware wechselt (ironischerweise kann dies jedoch zu Raubkopien führen, da freigegebene Freischaltcodes für Raubkopien funktionieren, aber nicht für legitime Kunden!).

Beachten Sie, dass es nicht unbedingt gut ist, zu verhindern, dass Benutzer betrügen. In einem Offline-Spiel (dh einem Spiel ohne Konkurrenz) ist es normalerweise kein Problem, wenn der Benutzer betrügt und die Codes von irgendwoher erhält, anstatt sie zu spielen. Er betrügt sich nur. Wen interessiert das.
Andererseits ist es eine großartige Gelegenheit, sich zu sehr in den Weg zu stellen, wenn sie wirklich betrügen wollen, um zahlende Kunden völlig zu verärgern .

Also ... bevor Sie etwas auf diese Weise tun, überlegen Sie sich genau, ob Sie das wirklich wollen und was Sie wollen. Möglicherweise ist es gerade gut genug und in der Tat vorzuziehen, von Menschen lesbare Zeichenfolgen zu haben (oder mit xor trivial "unlesbar" zu machen).

Damon
quelle
Welchen Prozess stellen Sie sich vor? Wenn das Programm den Hash-Wert nach dem Herunterladen generiert, muss der String beim Herunterladen nicht mit einem Hash versehen sein. Wird der Server den Client nach identifizierenden Informationen abfragen und dann den Hash-Server generieren?
Ansammlung
@Acccumulation: Welcher Server? Q sagt "völlig offline". Was wahrscheinlich ein Programm auf einer DVD (oder vielleicht ein Download) plus eine Seriennummer bedeutet. Sie haben also Ereignisse 1, 2, 3, 4, für die ein Passcode existieren muss. Sie berechnen zum Beispiel hash(serial + 1), um eine Zahl zu erhalten, die dem ersten Code entspricht. Dann speisen Sie das in Ihren Wortgenerator ein, der beispielsweise eine Silbe aus einer Liste von 16 für jeweils 4 Eingabebits zieht. Los geht's, individuelle "Wörter" für jeden User.
Damon
Wenn es sich um einen Download handelt, wird er von einem Server heruntergeladen. Was kann der Benutzer daran hindern, zu berechnen, wenn das Programm hash(serial+1) nach dem Herunterladen berechnet hash(serial+1)? Sobald das Programm heruntergeladen ist, hat der Benutzer Zugriff auf alles, was das Programm tut.
Akkumulation
@Acccumulation: Nichts hindert den Benutzer daran, das Programm erst zu dekompilieren und dann zu berechnen hash(serial + 1). Na und? Das ist kein Problem. Schauen Sie, wenn jemand ein bis zwei Stunden investiert (wahrscheinlich 6-8 Stunden für einen typischen "Benutzer" ohne Softwareentwickler-Hintergrund), nur um sich selbst zu betrügen, naja ... lassen Sie ihn. Die Sache ist, das funktioniert für eine Person, aber nicht für alle, und es ist nicht wettbewerbsfähig ... also kein Problem.
Damon
3

Wenn Sie die Zeichenfolgen nicht zeigen müssen, ist die Hashing-Idee wahrscheinlich der richtige Weg. Wenn Sie sie andererseits dem Benutzer anzeigen müssen, können Sie auf andere Weise verhindern, dass sie direkt in Ihrer DLL angezeigt werden.

Ein Weg, um damit umzugehen, neben dem Verschlüsseln oder anderweitigen Verschleiern der Zeichenfolgen, besteht darin, sie aufzubrechen. Vielleicht haben Sie nur ein alphabetisch sortiertes Wörterbuch aller möglichen Wörter aus allen Zeichenfolgen im Spiel. Dann haben Sie irgendwo ein Array, mit dem Sie die Wörter zu der Zeichenfolge zusammenfügen können, die Sie benötigen, indem Sie das Array mit den Wörtern indizieren. Auf diese Weise hast du nirgendwo im Spiel die kompletten Saiten. Zum Entschlüsseln der Zeichenfolgen ist kein Hauptschlüssel erforderlich. Und die Daten, die ihre Reihenfolge angeben, könnten sich über Ihre gesamte Quelle erstrecken, wenn beispielsweise jede Funktion, die eine Zeichenfolge verwendete, nur ein Array von Indizes vor Ort für die Funktion hatte. Ich bin mir nicht sicher, wie praktisch das in Ihrem speziellen Fall ist, aber es ist eine Möglichkeit, es zu tun.

Möglicherweise besteht die Zeichenfolge sogar aus wenigen Wörtern, die jedoch in unterschiedlicher Reihenfolge angezeigt werden. Beispielsweise benötigen Sie möglicherweise die folgenden 2 Zeichenfolgen:

  1. Ein Bär ging durch mein Haus
  2. Mein Haus beschützte mich vor einem Bären

Ihre Liste der Phrasen würde sowohl "ein Bär" als auch "mein Haus" enthalten, aber Sie hätten eine große Liste anderer Phrasen, die zwischen ihnen eingefügt werden könnten das Puzzle im Spiel (oder was auch immer). Zum Beispiel könnten die Aktionsphrasen "durchgehen", "niederbrennen", "überschieben", "mich beschützen vor", "mich trennen von", "magisch produziert" usw.

Sie können dies in Ihr Spiel einfließen lassen, indem Sie dafür sorgen, dass die Indizes auf etwas basieren, das der Spieler gesammelt oder getan hat. Es würde also nirgendwo im Spiel eine Master-Liste von Indizes geben. Sie werden vom Spieler generiert, der das Spiel spielt.

user1118321
quelle
4
Anstatt also die Funktion zu suchen, die auf eine bestimmte Zeichenfolge verweist, suchen Sie die Funktion, die auf ein Array mit Indizes verweist, und erstellen die Zeichenfolge neu. Das scheint nicht mehr als 30 Sekunden Schutz zu sein. Was es schützt, ist jemand, der es nur stringsgegen das Ausführbare benutzt.
Voo
Wie gesagt, wenn die Arrays, die auf die Zeichenfolgen verweisen, auf alle Funktionen verteilt sind, die sie benötigen, ist es etwas schwieriger, als nur ein einzelnes Array in einer einzelnen Funktion zu finden. Nicht unmöglich, deckt aber einen größeren Bereich ohne viel zusätzliche Arbeit ab.
user1118321
Ist das nicht nur eine geringere Form der Verschlüsselung?
Arturo Torres Sánchez
2
Warten Sie nicht einmal Verschlüsselung. Nur codieren.
Arturo Torres Sánchez
2
Ich habe die Antwort aktualisiert, um sie klarer zu gestalten. Wenn die Indizes auf etwas basieren, was der Spieler getan hat, werden sie im Grunde nicht im Spiel gespeichert. Auch hier mag es nicht narrensicher oder perfekt sein, aber ich stelle es hier als Option zur Verfügung, die die Leute gerne erkunden möchten.
user1118321