Das uncrackbare Programm - ein Ansatz?

Hi @ all,

ganz kurz zu meiner Person: ich bin zwar hauptsächlich Programmierer, jedoch auch sehr am Reversen interessiert. Ich hab mir in der letzten Zeit einige Gedanken bzgl. Cracking gemacht.

"Jedes Programm kann gecrackt werden."

Klar, aber die Frage ist, wie viel Aufwand dafür notwendig ist. Wenn es (im Extremfall) länger dauert einen Crack zu finden als die Software selbst überhaupt interessant ist (z.B. aufgrund technischer Veralterung), dann kann man wohl de facto von einem in der Praxis uncrackbaren Programm sprechen.

Der Ansatz ist daher also, das Cracken extrem zeitaufwändig zu gestalten. Das widerum könnte erreicht werden, indem ein Programm mit Hilfe von Automatismen erstellt wird, die beim Cracken jedoch nicht wieder automatisch aufgelöst werden können. So quasi nach dem Motto, dass ein Programm an z.B. 10.000 Stellen im Code manuell gepatcht werden müsste.

Das kann natürlich nur dann erreicht werden, wenn es keinen zentralen Punkt gibt, an dem das Programm angegriffen werden kann. Eine Methode um das zu erreichen könnte in etwa wie folgt aussehen:


1) An der Stelle im Programm, wo ein eingegebener Schlüssel auf Gültigkeit überprüft wird, werden mit Hilfe eines mathematischen Verfahrens ein ganzer Haufen (z.B. 1.000) unterschiedliche int-Werte aus dem Schlüssel berechnet.


2) Diese int-Werte (im Folgenden crVal[] genannt) haben die Eigenschaft, dass sie in einem bestimmten Muster "abgefragt" werden können und aus dem Ergebnis rückschließen lassen, ob ein Schlüssel gültig ist. Es ist dem Software-Autor also bekannt, dass z.B. die Bedingung

crVal[312] * crVal[92] > crVal[719] - crVal[238] + 17

erfüllt sein muss, wenn das Programm registriert sein soll. Diese Abfrage wird dann z.B. verwendet, um dem Benutzer bei der Eingabe eine "Schlüssel richtig" oder "Schlüssel falsch" Meldung auszugeben.


3) In den Teilen bzw. Funktionen des Programms, die einen gültigen Schlüssel erfordern, wird das korrekte Funktionieren des Codes von den crVal[]-Werten abhängig gemacht. Sprich dass diese Werte in Bedingungen, Schleifen, Variablenzuweisungen etc. der Ablauflogik eingebaut werden.


4) Hier kommt der angesprochene Automatismus ins Spiel: der Quellcode kann vor dem Kompilieren z.B. mit einem eigenen Präprozessor verarbeitet werden, der automatisch in die gewünschten Funktionen beliebig viele (natürlich unterschiedliche) Abhängigkeiten auf die Werte im crVal[] einbaut.


Da dem Cracker rein aufgrund dem Vorliegen einer exe nicht bekannt ist, welche Zahlen im crVal[] Array für einen korrekten Programmablauf stehen müssen, kann die exe alleine nur extrem aufwändig gecrackt werden - nämlich indem an allen Stellen der Ablauflogik die benötigten Werte des crVal[] Arrays durch Reverse Engineering manuell heraus gefunden werden. Ein aussichtsloses Unterfangen.

Die Sache schaut natürlich anders aus, wenn dem Cracker bereits ein gültiger Key bekannt ist. Auch dafür gibt es jedoch, wie ich glaube, ähnlich effiziente Gegenmaßnahmen. Bevor ich darauf eingehen möchte, bin ich aber erst mal sehr gespannt auf alle Antworten - ich freue mich auf eine interessante Diskussion!

--ar08
 
Hi,

ich würde an deiner Stelle da weiterforschen und wenn sich was ergibt eine Diss draus machen.

ciao
serow
 
wenn ich den ansatz mal aufs wesentliche runterbrechen darf:

du möchtest durch einen automatismus zu viele stellen schaffen die geändert werden müssten, so dass dies zu viel arbeit für einen menschen wäre ... da du die stellen nicht alle selbst erschaffen willst, lässt du sie von einem algorithmus ableiten der sich auf einen gültigen key bezieht ...

dein crval array wäre vermutlich das array mit den meisten referenzen, und daher sehr auffällig (der bereich, nicht eine adresse) ... nahezu jede funktion greift auf diesen bereich zu ...

also sieht man sich an wo auf den bereich geschrieben wird ... spätestens da sollte klar werden, dass das mit dem key zu tun hat ...

danach stellt sich mir die frage, warum ich x-hundert mal patchen soll -> ich würde herausfinden wollen was eine gültige initialisierung ist ... diese in den bereich schreiben und sehen was passiert ... wenns das war, kann man den ganzen patch wahnwitz vermeiden, in dem man deinem programm einen loader verpasst, der dies bei jedem start tut

alternativ, kann man versuchen die stellen zu identifizieren (bezüge auf den bereich von crval sind da doch irgendwie verräterisch) ... das lässt sich freundlicher weise genauso automatisieren wie deine erzeugung der stellen, wenn erstmal der start und die länge von crval bekannt ist ... hat man alle stellen gefunden, kann man relativ einfach mitschreiben lassen wie gültige initialisierungen aussehen...

ein allheilmittel gibt es nicht ... weder gegen cracks noch gegen anti-crack spielchen ... das zerrupfen von crval kann beispielsweise die suche nach den stellen erschweren ... verhindern allerdings nicht, da du irgendwann auf crval schreiben musst ...

aber die antwort auf automatisiert erzeugte massen an zu patchenden stellen, ist im zweifel vermutlich das (zumindest semi-)automatisierte patchen dieser stellen
 
3 Probleme die ich dabei sehe:

1. Irgendwann steckt man wieder mehr Aufwand in die Protection als in das Programm selbst und auf solche Software kann ich verzichten

2. Du brauchst extrem viele math. Algorithmen um den Key an verschiedenen Stellen zu überprüfen. Zwei mal der gleiche Algorithmus würde ja keinen Sinn ergeben.
Außerdem müssen alle Keys allen Algorithmen entsprechen und das wäre m.M.n. ein enormer Aufwand beim berechnen der Schlüssel oder?

3. Die Stellen zum Überprüfen finde ich mit Hardware-Breakpoints auch in kurzer Zeit.

Dann gibts das schon von dir genannte Problem wenn der Cracker einen Key kennt.
-> Dazu würden mir 2 Möglichkeiten einfallen:
1. Online-Auth-Server, aber die erzwingen, dass man zumindest bei der Installation online ist.
Außerdem können auch diese in kürzester Zeit umgangen werden, wenn man die host-Datei umbiegt und den Auth-Server simuliert.

2. Hardware-based Keys:
Schön und gut, aber für Massen-Produkte eher unvorstellbar, wenn diese an einen bestimmten PC gebunden sind (Es leiden im Endeffekt wieder die legalen User, wenn sie sich einen neuen PC kaufen).
Bei Software die wirklich teuer ist und die Lizenzen für einzelne PCs kauft wäre das zwar möglich, aber egal ob MAC-Addr, HDD-Serial, etc. die Apis dazu sind bekannt und undokumentierte Apis in produktiver Software zu verwenden halte ich für <Insert 24/7 Support-Hotline here>.

MfG
Inliferty
 
So wie ich das sehe, bleibt der Flaschenhals der Überprüfung
crVal[312] * crVal[92] > crVal[719] - crVal[238] + 17
Hier ein paar Bytes geändert und schon nützt der Schutz nichts mehr. Das Hauptproblem ist, dass der Endbenutzer Zugriff auf den Code im Speicher hat.

Ich glaube ein sicherer Ansatz könnte so aussehen, dass man Technologien aus dem Bereich trusted computing (TPM & Intels TXT) verwendet. Über TXT lassen sich Speicherbereiche schützen, sodass ein Zugriff über die CPU oder DMA verhindert werden kann. Über das TPM kann man die Integrität der Anwendung sicherstellen, außerdem gibt es die Möglichkeit den Teil der Anwendung, der für die Überprüfung der Lizenz zuständig ist, zu verschlüsseln und erst dann zu entschlüsseln, wenn die Integrität der Anwendung sichergestellt und die Speicherbereiche, in denen sich die Anwendung befindet, geschützt sind.
 
Hier im Forum gab es doch mal ein Thread über ein "uncrackbares" crackme. War CDW, der den Link zu einem Delphi Forum gepostet hatte. Wenn ich mich recht entsinne waren sich wohl einige hier einig, dass man es wirklich nicht cracken kann...
 
dein crval array wäre vermutlich das array mit den meisten referenzen, und daher sehr auffällig (der bereich, nicht eine adresse) ... nahezu jede funktion greift auf diesen bereich zu ...

also sieht man sich an wo auf den bereich geschrieben wird ... spätestens da sollte klar werden, dass das mit dem key zu tun hat ...

Klar. Es geht ja auch gar nicht darum, das zu verschleiern.

danach stellt sich mir die frage, warum ich x-hundert mal patchen soll -> ich würde herausfinden wollen was eine gültige initialisierung ist ... diese in den bereich schreiben und sehen was passiert ... wenns das war, kann man den ganzen patch wahnwitz vermeiden, in dem man deinem programm einen loader verpasst, der dies bei jedem start tut

Das Cracken durch Verwendung eines gültigen Keys + Loaders ist in dieser Variante, wie vorher gesagt, absichtlich nicht berücksichtigt - aus dem Grund, dass die von mir gepostete Beschreibung nur ein Teil des gesamten Ansatzes ist. In diesem Teil geht es darum, das "einfache" Patchen zu verhindern. Gegenmaßnahmen zur Verwendung eines Loaders sind ja prinzipiell unabhängig von Maßnahmen gegen das Patchen.

hat man alle stellen gefunden, kann man relativ einfach mitschreiben lassen wie gültige initialisierungen aussehen...

Nein. Wenn du nicht bereits einen gültigen Key kennst, kannst du das nicht: wenn nun z.B. crVal[x] den Wert y haben muss, damit das Programm funktioniert, kannst du, wenn dieser Wert in der Programmlogik z.B. innerhalb einer Schleife verwendet wird, nicht so leicht feststellen, was da hingehören müsste. Oder seh ich das falsch?
 
Hi,
da meine Vorposter schon sehr gute konkrete Überlegungen zu Deinem technischen Ansatz gebracht haben, möchte ich hier noch eine Einwand vorbringen, der eher allgemeiner Natur ist und sich auf diese grundlegende Überlegung von Dir bezieht:
ar08:
Klar, aber die Frage ist, wie viel Aufwand dafür notwendig ist. Wenn es (im Extremfall) länger dauert einen Crack zu finden als die Software selbst überhaupt interessant ist (z.B. aufgrund technischer Veralterung), dann kann man wohl de facto von einem in der Praxis uncrackbaren Programm sprechen.
Theoretisch ist diese Überlegung sicher richtig und sie gilt ja z. B. auch in der Kryptografie, wo ein Verschlüsselung dann als sicher gilt, sobald der zeitliche Aufwand sie zu brechen, größer als die Zeitspanne ist, die der verschlüsselte Inhalt geheim bleiben muß.
Aber hier gibt es, meiner Meinung nach, einen wichtigen Unterschied: Im Falle der Verschlüsselung von Daten gibt es für gewöhnlich einen sehr konkreten Tag X an dem die Daten ihren Wert verlieren, so sind z. B. die Modalitäten für eine geschäftliche Verhandlung wertlos, sobald die Verhandlungen abgeschlossen sind und eine Einigung erzielt wurde.
Im Fall der Schutzmaßnahmen einer Software liegt der Fall jedoch anders, denn diese dienen dazu eine kommerzielle Anwendung vor unbefugten Zugriff zu schützen und den Publisher so vor finanziellen Einbußen zu bewahren. Doch wann verliert eine Anwendung ihren Wert? Nur weil neuere Versionen dieser Software erscheinen, verlieren die alten Versionen nicht ihren Nutzen - es fehlen lediglich ein paar neue Features. Und solange man eine ältere, gecrackte Version kostenlos nutzen kann, werden viele User auf den Erwerb einer neueren, optimierten Version verzichten - der finanzielle Schaden für den Publisher wird also nicht abgewendet...
 
3 Probleme die ich dabei sehe:

1. Irgendwann steckt man wieder mehr Aufwand in die Protection als in das Programm selbst und auf solche Software kann ich verzichten

Ja, es muss natürlich ganz generell ein Kompromiss zwischen Usability und Security gefunden werden. Aber das ist eine andere Geschichte.

2. Du brauchst extrem viele math. Algorithmen um den Key an verschiedenen Stellen zu überprüfen. Zwei mal der gleiche Algorithmus würde ja keinen Sinn ergeben.
Außerdem müssen alle Keys allen Algorithmen entsprechen und das wäre m.M.n. ein enormer Aufwand beim berechnen der Schlüssel oder?

Nein. In etwa wie im Beispiel vorher - ein paar Grundrechenarten können zur Überprüfung ausreichen. Das Berechnen der Werte selbst kann durchwegs aufwändiger sein, aber das muss nur ein Mal beim Programmstart bzw. Eingeben des Keys passieren.

3. Die Stellen zum Überprüfen finde ich mit Hardware-Breakpoints auch in kurzer Zeit.

Ja, aber das bringt dir nicht viel. Wie willst du diese Stellen patchen? Wenn du z.B. die folgende Stelle findest (in C++ Code):

if (a < b && c < crVal[50])
{
...weiterer Code...
}

a, b und c sind dabei Variablen, die das Programm zur korrekten Ausführung braucht. Dann kannst du, ohne einen gültigen Wert von crVal[50] zu kennen, nichts machen, außer den gesamten Code zu verstehen und daraus zu schließen, dass der Ausdruck "c < crVal[50]" nun entweder mit true oder false zu patchen wäre. Aber wenn nun alle paar 100 Zeilen eine solche Überprüfung steht, steigt der Aufwand dafür ins Unendliche.

Dann gibts das schon von dir genannte Problem wenn der Cracker einen Key kennt.
-> Dazu würden mir 2 Möglichkeiten einfallen:
1. Online-Auth-Server, aber die erzwingen, dass man zumindest bei der Installation online ist.
Außerdem können auch diese in kürzester Zeit umgangen werden, wenn man die host-Datei umbiegt und den Auth-Server simuliert.

2. Hardware-based Keys:
Schön und gut, aber für Massen-Produkte eher unvorstellbar, wenn diese an einen bestimmten PC gebunden sind (Es leiden im Endeffekt wieder die legalen User, wenn sie sich einen neuen PC kaufen).
Bei Software die wirklich teuer ist und die Lizenzen für einzelne PCs kauft wäre das zwar möglich, aber egal ob MAC-Addr, HDD-Serial, etc. die Apis dazu sind bekannt und undokumentierte Apis in produktiver Software zu verwenden halte ich für <Insert 24/7 Support-Hotline here>.

Ja. Wie gesagt, bezieht sich dieser Teil des Ansatzes nur aufs Patchen. Aber um trotzdem kurz drauf einzugehen: der andere Teil des Ansatzes ist tatsächlich, eine Art von Hardware-basierten Keys zu verwenden. Bei guter Umsetzung bzw. Lizenzbedingungen muss die Usability nicht darunter leiden.

Und ja, natürlich sind die API's bekannt, um solche ID's auszulesen. Ich würde das auch auf eine andere Art und Weise machen. Ich komm ein bisschen später darauf zurück, wenn dieser Teil des Ansatzes auch von Interesse sein sollte.
 
So wie ich das sehe, bleibt der Flaschenhals der Überprüfung

crVal[312] * crVal[92] > crVal[719] - crVal[238] + 17

Hier ein paar Bytes geändert und schon nützt der Schutz nichts mehr.

Wieso? Du patcht damit gerade mal die Meldung "Falscher Code" weg, so dass eben die Meldung "Richtiger Code" erscheint. Aber das bringt doch überhaupt nichts. Die Stellen im Code, die die korrekten crVal-Werte brauchen, werden deswegen trotzdem nicht funktionieren.

Das Hauptproblem ist, dass der Endbenutzer Zugriff auf den Code im Speicher hat. Ich glaube ein sicherer Ansatz könnte so aussehen, dass man Technologien aus dem Bereich trusted computing (TPM & Intels TXT) verwendet. Über TXT lassen sich Speicherbereiche schützen, sodass ein Zugriff über die CPU oder DMA verhindert werden kann. Über das TPM kann man die Integrität der Anwendung sicherstellen, außerdem gibt es die Möglichkeit den Teil der Anwendung, der für die Überprüfung der Lizenz zuständig ist, zu verschlüsseln und erst dann zu entschlüsseln, wenn die Integrität der Anwendung sichergestellt und die Speicherbereiche, in denen sich die Anwendung befindet, geschützt sind.

Ja, trusted computing ist natürlich auch ein Ansatz.
 
Wieso? Du patcht damit gerade mal die Meldung "Falscher Code" weg, so dass eben die Meldung "Richtiger Code" erscheint. Aber das bringt doch überhaupt nichts. Die Stellen im Code, die die korrekten crVal-Werte brauchen, werden deswegen trotzdem nicht funktionieren.
Sry, hatte mich verlesen. Aber das was GrafZahl geschrieben hat, würde ich nicht vernachlässigen. Man muss auch keinen Loader schreiben, sondern kann auch die jeweiligen crVals direkt an ihren Platz schreiben. Voraussetzung ist natürlich ein gültiger Key. Da die crVals aber nicht variieren dürfen, kann man anhand der gecrackten Software nicht nachvollziehen, welcher Key benutzt wurde.
 
Doch wann verliert eine Anwendung ihren Wert? Nur weil neuere Versionen dieser Software erscheinen, verlieren die alten Versionen nicht ihren Nutzen - es fehlen lediglich ein paar neue Features. Und solange man eine ältere, gecrackte Version kostenlos nutzen kann, werden viele User auf den Erwerb einer neueren, optimierten Version verzichten - der finanzielle Schaden für den Publisher wird also nicht abgewendet...

Ja. Aber auch wenn Software natürlich kein bestimmtes "Verfalldatum" hat, so hat sie im Allgemeinen doch eine bestimmte "Halbwärtszeit" (betreffend ihrer Verbreitung und Verwendung). 10 Jahre nach ihrem Release wird z.B. kaum eine Software noch eine breite Verwendung vorweisen können. Von Win XP vielleicht mal abgesehen, das dürfte sich wohl ausgehen :) Aber das haben unsere Freunde in Redmond auch selbst verbockt.

Abgesehen davon dass 10 Jahre natürlich ein unglaublich langer Zeitraum wären, um einen Crack zu finden, ist aber auf jeden Fall der sogenannte finanzielle "Schaden" für den Entwickler um so geringer, je länger es dauert das Programm zu cracken. Allein deswegen würde es sich für den Software-Autor auszahlen, mit der "Crack-Verzögerungs-Strategie" zu arbeiten.
 
Verstehe ich nicht. Einmal mit einem gültigen Key die Initialisierung durchlaufen lassen, dann laufendes Produkt dumpen und schon kann man seine nfo schreiben und deine Software als Warez-Release pre'n.

Wenn man keinen gültigen Key hat, natürlich nur mit extremen Aufwand machbar. Allerdings gibt es 100% Verfahren für den Fall, dass man keinen Key hat. Man denke an einfache Verschlüsselungsverfahren wie RSA.

Also ich sehe hier keinen Vorteil.
 
Zuletzt bearbeitet:
da hier ab und an zur kryptographie geschielt wird:

die üblichen verdächtigen, namentlich verschlüsselungs verfahren wie RSA oder AES haben allesammt, ob symetrisch oder asymetrisch, eine gemeinsamkeit ... ihre sicherheit beruht unter anderem darauf, dass ALLE beteiligten ein interesse daran haben, dass die zu schützende information geheim bleibt ...

das ist in diesem fall nicht gegeben ... das ist der gleiche grund, warum anfänglich die lieben herrschaften vom paytv, die sich auf etablierte kryptographie verlassen wollten, so böse auf die nase gefallen sind ...

oder welches hoch heilige interesse hat ein kunde daran, dass das crval array geheim bleibt? er wird für den jenigen der das programm vertreibt jedenfalls keine besonderen sicherheitsmaßnahmen treffen, um zu verhindern dass da jemand ran kommt ...

es ist also anzunehmen, dass ein angreifer irgendwo zugang zu einer laufenden registrierten version, in der regel sogar zum key zugang erlangen kann ...



was die verstrickung des crval arrays in den code betrifft, hat das gavierende auswirkungen:

entweder crval ist fix für alle keys ... dann kannst du das wie geplant mit grundrechenarten verbauen ... in dem fall wäre aber ein bekanntwerden dieser information das ende jegweden schutzes ... das fixe crval kann der angreifer aus der ihm zugänglichen version extrahieren ... da das array fix ist, kann man nicht zurückschließen auf den key, damit ist nichtmal bekannt welcher kunde sich in die karten gucken ließ ...

oder crval ist abhänig vom key ... in dem fall bist du allerdings mit grundrechenarten relativ aufgeschmissen ... dir bleiben dinge wie abfragen auf größer/kleiner bestimmter schranken ... die lassen sich aber im verzweigungsgraphen des programms vollautomatisiert finden und killen wenn ich weiß wie sich die verzweigung verhält wenn der key richtig ist ... diese information kann ich mittels profiling aus der laufenden instanz gewinnen

oder es bleibt dir modular arithmetik, dass gewisse teile des crval arrays modulo eines vorgegebenen wertes immer das gleiche ergeben für alle keys ... dann bau ich dir aber nach dem chinesischen restsatz problemlos eine lineare kongruenz auf, die alle bedinungen erfüllt, unter der vorraussetzung dass ich zugang zu einer korrekt laufenden instanz habe ... die wird mir nämlich sagen zu welchem wert die kongruenz führen soll ... damit lassen sich alle teile von crval rückwärts konstruieren ... auch in diesem fall bleibt kein einwandfreier rückschluss auf den key möglich bei dem ich nachgesehen habe wie es richtig aussieht ...


wie ichs auch drehe und wende ... ich sehe nicht wie das ding längerfristig schutz bieten kann ...

einzig und alein dann, wenn überhaupt noch niemand keys in den fingern hält, kann das möglicherweise eine hürde darstellen...

das wäre der fall wenn man zwar die software downloaden kann, aber das allgemeine release erst noch bevorsteht ...

jedoch ist der ansatz auch in diesem fall keine alternative, da man hier lieber das ganze programm durch eine symetrische verschlüsselung wie AES sichert, und den key zu gegebener zeit veröffentlicht -> deutlich geringerer aufwand ...
 
ar08 hat gesagt.:
Nein. In etwa wie im Beispiel vorher - ein paar Grundrechenarten können zur Überprüfung ausreichen. Das Berechnen der Werte selbst kann durchwegs aufwändiger sein, aber das muss nur ein Mal beim Programmstart bzw. Eingeben des Keys passieren.
Ich meinte damit die Berechnung der Keys die dann auf der Verpackung stehen.
Diese Keys, die du natürlich ausrechnen musst, müssen alle Algos. erfolgreich durchlaufen, andererseits sollte nicht jeder x-beliebige Key funktionieren.

ar08 hat gesagt.:
Ja, aber das bringt dir nicht viel. Wie willst du diese Stellen patchen? Wenn du z.B. die folgende Stelle findest (in C++ Code):

if (a < b && c < crVal[50])
{
...weiterer Code...
}
a, b und c sind dabei Variablen, die das Programm zur korrekten Ausführung braucht. Dann kannst du, ohne einen gültigen Wert von crVal[50] zu kennen, nichts machen, außer den gesamten Code zu verstehen und daraus zu schließen, dass der Ausdruck "c < crVal[50]" nun entweder mit true oder false zu patchen wäre. Aber wenn nun alle paar 100 Zeilen eine solche Überprüfung steht, steigt der Aufwand dafür ins Unendliche.
Also ich obfuscate meinen Source ungern indem ich alle 100 Zeilen so ein Macro einfüge.

Außerdem ist die Annahme, dass der Cracker keinen gültigen Key kennt sinnfrei.
Wie +++ATH0 bereits erwähnt hat: RSA mit nem langen Key und dein Programm is praktisch nicht knackbar.
Du könntest dein Programm auch mit WinRar packen und ein Passwort setzen bei diesen Preconditions.
Solang kein Cracker das Passwort ist dein Programm sicher weil er das Rar-Archiv nicht entpacken kann.

MfG
Inliferty
 
Wenn man keinen gültigen Key hat, natürlich nur mit extremen Aufwand machbar.

Das ist es, worauf dieser Ansatz abzielen sollte.

Verstehe ich nicht. Einmal mit einem gültigen Key die Initialisierung durchlaufen lassen, dann laufendes Produkt dumpen und schon kann man seine nfo schreiben und deine Software als Warez-Release pre'n.

Okay. Es folgt der zweite Teil des Ansatzes:


1) Einige Werte im crVal-Array werden über einen Timer, der alle paar Sekunden triggert, kontinuierlich mutiert. Dies geschieht auf eine solche Art und Weise, so dass zu große Zeitdifferenzen zwischen dem letzten Timer-Event (was z.B. bei gedumpten crVal-Werten der Fall wäre) falsch berechnete Werte zur Folge haben. Was wiederum dazu führt, dass die im Programm verstreuten crVal-Überprüfungen eine fehlerhafte Exekution der Software verursachen.


2) Gleichzeitig ist die zeitliche Mutation jedoch auch notwendig (d.h. kann nicht einfach zentral rausgepatcht werden), weil innerhalb dieses Timers ebenfalls auch Operationen auf den crVal-Werten stattfinden, die das Programm auf der anderen Seite auch zur korrekten Ausführung benötigt. Beispielsweise erkennen die verstreuten Überprüfungen eine deaktivierte Timestamp-Mutation daran, dass sich die entsprechenden Werte des crVal-Arrays nicht ändern, obwohl der eine Teil des Programms nun z.B. später exekutiert werden müsste (alleine weil z.B. der User ein paar Sekunden braucht um von einem Dialogfenster zu einem anderen zu wechseln etc. - hier gibt es unzählige Möglichkeiten, den zeitlichen Ablauf eines Programms zu nutzen).

Außerdem vergleichen die verstreuten Überprüfungen der crVal-Werte ebenfalls die aktuelle Timestamp zurück (das ist jetzt in dem oben genannten Beispielcode natürlich nicht drinnen). Das kann wohl jedoch mit einer gewissen Automatik raus gepatcht werden, auch wenn das an mitunter tausenden Stellen im Programm passiert.


3) Es gibt keine allgemein gültigen Keys. Die Gültigkeit eines Keys ist an ein Merkmal der aktuellen Hardware, Software oder des Betriebssystems gebunden.


4) Das Merkmal, auf dessen Basis die Gültigkeit eines Keys beurteilt wird, muss ebenfalls vor dem Patchen geschützt werden. Dies geschieht dadurch, dass das besagte Merkmal sowohl als Grundlage für den Key verwendet wird, als auch für die tatsächliche Funktionsweise des Programms benötigt wird. (Ja, das gibt es.) Diese beiden Zugriffe auf das Merkmal - d.h. sowohl tatsächlich benötigte als auch solche, die mit den crVal-Werten zu tun haben, werden wieder per Automatismus hunderte Male im Programm verstreut. Ein zentrales Patchen wird dadurch auch hier verhindert. Ebenso ein automatisiertes Patchen, da jeweils entschieden werden muss, ob ein Teil des Codes tatsächlich benötigt wird oder nur zum Absichern des Merkmals verwendet wird. Das kann ein Automatismus nur schwer oder gar nicht leisten.
 
1+2) Dann dumped und ripped man die Funktionalität der Mutationen und des Timers einfach mit.

3) ... emuliert man eine gültige Maschine die man hat. (NtDeviceIoControl et cetera) [Dasselbe wie bei Schlüssel haben / nicht haben; gültige Maschine haben / nicht haben]

4) Wir embedden in unseren Warez-Release eben einen gültigen Key.

Resultat ist nur, dass in unserer Übersicht sich folgendes verändert hat:

Methode von ar08:
Wenn man den Key hat -> Unsicher. Mit durchschnittlichem Aufwand knackbar.
Wenn man den Key nicht hat -> Mit wirklich extremen Aufwand knackbar [?]

Methode mit Verschlüsselung:
Wenn man den Key hat -> Unsicher. Leicht knackbar.
Wenn man den Key nicht hat -> Sicher.

Ergo wird es eben nur wieder um einen Faktor X schwieriger. Irgendwann kommst du an eine Stelle, an der "Wenn man Key nicht hat" unmöglich wird, WENN bestimmte Merkmale deines Schutzes den Charakter einer sicheren Informationsverschlüsselung hat.
Wenn es soweit ist, fragt man sich jedoch, warum man nicht gleich vollverschlüsselt? Wozu dann der Aufwand.
 
3) ... emuliert man eine gültige Maschine die man hat. (NtDeviceIoControl et cetera) [Dasselbe wie bei Schlüssel haben / nicht haben; gültige Maschine haben / nicht haben]

Das dürfte aber nicht so einfach sein, wenn das Merkmal, das man emulieren muss, tatsächlich auch von der Software für die korrekte Funktionsweise benötigt wird. Wenn nun z.B. der Benutzername des aktuell am OS angemeldeten Benutzers als Grundlage für den Key verwendet wird, aber auch als Grundlage für den Zugriff auf den Ordner C:\Dokumente und Einstellungen\username, dann funktioniert eine einfache Read-Only-Emulation des Benutzernamens nicht, da dann ebenso der Zugriff auf den User-Ordner fehlschlägt, aus dem z.B. die Programm-Einstellungen geladen werden. Außer man nimmt den Aufwand in Kauf und emuliert den Zugriff zurück aufs File System auch wieder mit.
 
Klar. Die Variable heisst Aufwand. Du musst bedenken, dass geübte Reverse Engineerer immer dabei sind Funktionalität herauszufinden um dann den einfachsten Weg für das Knacken zu finden. Auf solche Modalitäten wird dann natürlich eingegangen.
Wenn man sehr viel Pech hat, macht man die Software durch seinen Schutz für den Endnutzer langsam, aufwendig und problemanfällig.
Das nächste Warez-Release dagegen ist möglicherweise je nachdem, schneller, unaufwendiger und nicht so problemanfällig.

Soweit ich mich erinnern kann hat Ubisoft bei einem seiner Spiele einen Crack von RELOADED benutzt um einen Bug zu fixen. Manchmal ist die raubkopierte Version einfach besser. Spätestens dann weiss man, dass man etwas falsch gemacht hat als Entwickler. :wink:
 
Zurück
Oben