LaZaRuS Anti-Cracking Tips V2.0


  1. Was sind die Intentionen für dieses Werk
  2. Wie denkt ein Cracker ?
  3. Überbrücken
  4. Präventionen, die man schnell und einfach programmieren kann
  5. Die imaginäre Anwendung Win-Dummy als Beispiel für alle Fehler, die ein Programmierer machen kann
  6. Dinge, die schwer zu programmieren/cracken sind, die ich nicht in meiner kleinen Geschichte hab unterbringen können, oder die ich mir gerade ausgedacht habe (Ob sie funktionieren ist eine andere Sache):
  7. Dinge, von deren Wirkung Sharewareprogrammierer so überzeugt sind, das sie sie immer wieder benutzen, obwohl sie den Crack in keinem Fall erschweren
  8. Visual Basic Programme
  9. Beispiele
  10. Glossar
  11. Greetings


Was sind die Intentionen für dieses Werk:
Ich bin selbst Shareware Programmierer und möchte allen anderen Sharewareprogrammieren Tips geben, wie sie ihre Werke besser schützen können. Ich habe wirklich sehr gute Sharewareprogramme gesehen, die jedoch so einfach zu cracken waren, daß die Programmierer den richtigen Registrierungscode gleich in die Anleitung schreiben könnten. Damit so etwas nicht erneut passiert, versuche ich hier ein möglichst weites Feld von Tips abzudecken, um Sharewareprogramme besser zu schützen. Einige Passagen stammen aus Anleitungen von Fravia+ Webseite, die ich mehr oder weniger frei übersetze.

Wie denkt ein Cracker ?
Um gute Schutzalgorhythmen zu schreiben, sollte man möglichst viel über die Vorgehensweise von Crackern wissen.
Es gibt zwei Arten von Crackern. Die ersten wollen möglichst viele Programme cracken, die zweiten wollen Wissen über Funktionen, die Programme schützen erlernen und mit anderen Gleichgesinnten austauschen. Ich gehe nur auf die zweiten ein.
Wenn ein Cracker ein Programm cracken will, macht er das aus zwei Motivationen heraus: Entweder ist ein Programm besonders gut, oder das Programm ist (auf den ersten Blick) sehr gut und trickreich geschützt. (Das stammt z.B. von Fravia+ Seite.)
Wenn ein (idealer) Cracker die Arbeit beginnt, sollte er so anfangen: Während das Programm im Hintergrund in Assembler zerlegt wird, durchforstet man das Programm nach Anhaltspunkten. Dann startet man das Programm erneut und schaut auf welche Windows Registry oder Dateien das Programm zugreift. So jetzt beginnt man mit dem Suchen nach Anhaltspunkten im Assemblercode und beginnt die Datei zu patchen. Neustart des Programms. Wenn es jetzt registriert ist, dann war es nicht sonderlich geschützt. Ansonsten lädt man das Programm in einen Debugger, geht in den Screen, in dem man den Reg-Code eingeben kann und setzt einen Breakpoint auf die Funktion, die die eingegebenen Werte in den Speicher lädt. Dort geht man dann jede Assembleranweisung einzeln durch, bis man auf den fertigen Code trifft.

Überbrücken
Ich werde öfter von Überbrücken reden. Was meine ich damit eigentlich ?

Bei Abfragen der Systemzeit ob Prüfzeit schon abgelaufen, niemals so was machen:

Systemzeit prüfen
Wenn abgelaufen, dann aussteigen
Sonst weitermachen

In Assembler sieht das (ungefähr) so aus:
GetSystemDate    ; Systemzeit prüfen
?????????????    ; Installationsdatum aus Datei lesen
cmp eax, 10      ; Mit 10 hex vergleichen
jl XXXX          ; Wenn kleiner, dann Springe nach Adresse XXXX
Steigeaus        ; und raus

man muss in einem Hex-Editor nur noch ein Byte ändern (in "immer springen" ASM:jmp), um das Ende der Prüfphase niemals zu erreichen.Besser zwischen Zeile 2 und 3 irgendwelchen Müll mit vielen Sprüngen einfügen, um den Cracker zu verwirren.
Anmerkung: Sprünge in Assembler entstehen im seltensten Falle durch Sprünge im Quellcode, sondern durch if-Abfragen.

Analog gilt dies für Seriennummern berechnen. Das sieht meistens so aus:

CALL XXXX        ;ruft Berechnung der Seriennummer auf und vergleicht
                  diese mit der Eingegebenen. Wenn richtig, dann Rückgabe-
                  wert 1, sonst 0
TEST EAX,EAX     ;wenn 1
je XXXX          ;dann springe zu "richtige Nummer-weiter im Programm"
RAUS             ;sonst Raus

Auch ist hier nur eine Änderung von einem Byte nötig. Sonst gilt: Hier ist klar, daß die Seriennummer in der mit CALL aufgerufenen Prozedur generiert wird. Also rein und auslesen. So sieht es in 80% aller SW-Programme aus und die Programmierer könnten die richtige Seriennummer in solchen Fällen gleich in die Hilfedatei schreiben.
Viel mehr Mühe macht das Auslesen aus dem RAM auch nicht. Mein persönlicher Rekord für solch ein Abfrage war 48 SEKUNDEN und ich bin noch ein (fortgeschrittener) Anfänger. Man sollte zwischen dem CALL und dem TEST viele Dinge reinprogrammieren, die nichts mit der Generierung zu tun haben.

Präventionen, die man schnell und einfach programmieren kann:

Man sollte wenigstens ein Minimum an Ahnung haben, wie das Programm, das man geschrieben hat auf "Low-Level" Ebene funktioniert. Wenn man bloss die Entwicklungsumgebungen und RAD Tools sieht, kann man es eigentlich gleich vergessen, Software effizient zu schützen (ausser man ist wirklich clever und ein sehr guter Programmierer).

Als erstes möchte ich sagen, daß jedes Programm das den Quellcode der Sharewareversion beinhaltet auch zu Cracken ist. Das kann ich sagen, da man vor Debugger und Disassembler nichts (wirklich gar nichts) verstecken kann. Wenn man lang genug sucht, wird man auch fündig. Man kann also das Cracken nicht verhindern, sondern nur so lange wie möglich herauszögern und hoffen, daß der Cracker das Interesse verliert. Die folgenden Tips sind meiner Meinung nach nicht unnützlich, um das zu erreichen.

Zuerst eine generelle Warnung. Benutzen sie niemals kommerzielle Programme, die ihr Programm schützen sollen. Diese sind zumeist sauschlecht und sowieso alle schon gecrackt. Das gleiche gilt für EXE-Packer, die die EXE-Datei erst
in den RAM laden und dort entschlüsseln. Damit ist es wie mit Fernsehwerbung. Während man entpackt holt man sich was zu essen. Deshalb störts nicht wirklich.

Fangen wir mit den kleineren, allgemeineren Dingen an, die man mit minimalem  Programmieraufwand bewerkstelligen kann.
Zuerst sollte man niemals Funktionen oder Prozeduren aus DLL-Dateien importieren, die schon am Namen erkennen lassen, was sie bewerkstelligen sollen. Bekannte Beispiele, wie man Prozeduren nicht nennen sollte sind z.B. die Firma Ulead, die ihren Prozeduren traditionell z.B. IsFullVersion nennt. Raten sie mal, was diese Prozedur testet ;-). (Auch IsValidSerial gehört zu meinen Favoriten)

Analog kann man das für die Namen der Einträge in der Windows-Registry oder INI-Dateien anwenden. Es gibt ein Tuningtool (Name wird hier nicht genannt), das liest aus der Windows-Registry einen Wert mit dem Namen IsRegistered aus.
Wenn dieser Wert 0 ist, startet das Programm als Shareware, ist der Wert jedoch 1, dann besitzt man die Vollversion.

Ohne zu denken haben auch die Programmierer von Pixel 3D programmiert. Zu erst einmal Glückwunsch. Zuerst dachte ich, daß sie alles richtig gemacht hätten, um mir das Leben schwer zu machen. Dann habe ich mir was neues ausgedacht (habe ich auch noch nie irgendwo gelesen). Ich löschte einfach alle Eintragungen für Pixel 3D in der Windows-Registry und überbrückte die daraufhin auftretenden Fehlermeldungen. Dann hatte ich die Vollversion. Will sagen: Wenn irgendwas passiert, das gar nicht sein dürfte, muß das Programm immer als Sharewareversion starten. Der ehrliche Kunde kann das Programm ja mit seinem Schlüssel erneut registrieren. (Ein gutes Beispiel dafür ist Microangelo).

Was ich für ziemlich scheiße halte, aber durchaus ein adäquates Mittel gegen Cracker ist, ist das Löschen von wichtigen Dateien, wenn irgendwas merkwürdiges auftritt. Man sollte um eine Neuinstallation nicht herumkommen. Ähnliches gilt für einen Systemneustart. Das sollte man allerdings nur tun, wenn man absolut überzeugt ist, dass der entsprechende Programmteil
100% funktioniert, da man sonst ehrliche Kunden verärgern könnte.

Wenn sie eine Hilfedatei schreiben, sollten sie nichts erwähnen, was auch nur halbwegs einem Cracker helfen könnte. Nicht mal
irgendeinen Hinweis auf den Code (10 Ziffern/Buchstaben...). Am schlimmsten war bisher bei einer Cheatsammlung (Das geht nur bei viel früheren Versionen, deshalb erwähne ich es hier). In der Hilfedatei stand, daß der Code in der Form 11111-2222-333 (oder so ähnlich) eingegeben werden muss. Nicht nur das die Form gegeben war, der Programmierer hat auch noch einen anderen kapitalen Fehler begangen: Wenn man als Namen 0 eingibt, lautet das Password 00000-0000-000. Es scheint, daß die Berechnung des Passwords nur auf Multipliktionen beruht und da ein Glied 0 ist, weiß man was da passiert ist. Dies gilt übrigens auch noch für einige andere Programme. In der Hilfedatei sollte man wenn überhaupt, dann falsche Informationen über das Passwort geben.
Beispiel: Name des Programms weis ich nicht mehr. "Sie bekommen die Datei keyfile.dat zugesandt, um das Programm zu registrieren." Hab ich zuerst auch gedacht, wurde aber stutzig, als im ASM-Code kein solcher String zu finden war, wo der Programmierer doch auch sonst alle wichtigen Strings "hardgecodet" hat. Am Ende stellte sich heraus, das keyfile.dat ein Trick war, und der richtige keyfile anders hies.
Ein anderes Beispiel ist ein CrackMe, das jemand aus unserer Gruppe (greets Shadow) programmiert hat. Wenn man die Strings durchsucht findet man shadow.key und xxx.123. Beide Strings sehen aus, wie potentielle Keyfiles, der richtige keyfile heisst aber ganz anders.

Vermeiden sie auch (wichtige) Strings "hardzucoden". Dies ist immer der erste Anhaltspunkt, wenn man ein Programm crackt. Viel besser ist es, wenn man Strings aus ASCII-Zeichen zusammensetzt. Bsp.: char(65)+char(66)...
Besonders tödlich sind deshalb MessageBoxes und Textfelder in Nag-Screens. Das Spiel kann man jedoch umdrehen und die wichtigen Strings verbergen und dafür die gleichen Strings (wirklich richtige Strings) an anderer unwichtigen Stelle mit einer kleinen Abfrage, die nie erfüllt werden kann in das Programm einbauen, so das der Cracker von einem völlig falschen
Ansatzpunkt ausgeht. Auch lustig ist, wenn man (echte) Strings einbaut, die so auch vom Compiler eingebaut werden könnten (z.B. GetWindowText, ShowWindow, 7ABE1F90). Manche Disassembler schaffen es dann nicht mehr diese
Strings als Strings vom Programmierer einzuordnen, sondern versuchen verzweifelt die Strings in den Programmablauf als Befehler einzubauen, was dazu führt, daß der Disassembler abstürzt. Die Stringstips gelten nicht für Visual Basic, d a    V B   d i e    S t r i n g s    s o    a b s p e i c h e r t (nämlich mit ASCII 00 zwischen den Zeichen) und man sie dann nicht mehr findet (in herkömmlichen Disassemblern. Es gibt auch welche für VB, den hab ich aber noch nicht)

Die imaginäre Anwendung Win-Dummy

Soweit zur allgemeinen Benennung. Der nächste Abschnitt befasst sich damit, wie man das Ausspionieren der richtigen Registrierungsnummer erschweren kann.Ich kreiere eine absolut imaginäre Anwendung, die alle Fehler enthält, die
ein Programmierer machen kann. Nennen wir sie Win-Dummy. Sie verhält sich so, wie man es von einem Sharewareprogramm gewöhnt ist: Nagscreen, Zeitlimit,Registrierungscode,Einschränkungen...

Fangen wir mit dem an, was man sieht, wenn das Programm startet. Bei sehr vielen Sharewareprogrammen startet man das Programm ganz hoffnungsvoll und erblickt dann *PENG* einen Nag-Screen. Ums mal mit den Worten einer Jeans-
Werbung auszudrücken: "Bad idea, bad idea". Wenn man mal davon ausgeht, daß das Programm mit einer Seriennummer/Keyfile... zur Vollversion aufrüsten kann, dann muss irgendwo eine Abfrage für diesen Nag-Screen stehen, die man überbrücken kann. (Man identifiziert sie meistens mit Strings wie "Noch XX Tage Zeit". Viel schwerer zu cracken- aber auch speicherintensiver- sind BMP-Dateien, die man mit eigenen Routinen reinlädt. Verwendet man die vordefinierten API Befehle kann man es auch gleich lassen. Dieser Tip ist jedoch zu schwer zu realisieren für ein Sharewareprogramm. Das dabei der Cracker den Nagscreen nicht mehr ertragen muss, ist dabei noch das geringere übel. Viel schlimmer ist die Tatsache, daß eine Abfrage geschehen muss, ob die Version registriert ist. Das muss man aus einer Datei auslesen (INI/CFG/DAT/Windows Registry...). Dort ist entweder

etwas wie IsRegistered=0 bzw. IsRegistered=1
oder
der Benutzername und die daraus resultierende Seriennummer

gespeichert:

Um das recht schnell rauszukriegen gibt es zwei Freeware-Tools, die eigentlich für Programmierer gedacht sind. Vielleicht fragen sie sich, worauf ich hinaus will. Ganz einfach, entweder ist der Nag-Screen ziemlich einfach zu überbrücken oder man zeigt dem potentiellen Cracker, wo bzw. wie der richtige Code berechnet wird.

Wenn man schon einen Nagscreen benutzt, dann meistens, um dem User anzuzeigen, wie lange man das Programm noch testen darf. Mal davon abgesehen, daß die Zeitabfrage einfach zu überbrücken ist, wenn man die vorgefertigten
Funktionen wie GetSystemDate benutzt, sollte man diese Funktion nicht benutzen. Der User kann das Systemdatum ja nach Herzenslust verstellen. Um dies wenigstens einzuschränken, sollte man das Datum des letzten Programmstarts verschlüsselt speichern und bei irgendwelchen Merkwürdigkeiten (z.B.aktuelles Datum das Programm beenden.
Eine viel effektivere Anti-Cracker-Methode, um das Datum auszulesen, ist eine der Dateien System.dat oder Bootlog.txt. Bei jedem Systemstart werden diese Dateien (normalerweise) aktualisiert und beinhalten so das neue Datum. Ausserdem kommt da niemals ein Cracker drauf, das auszuprobieren. (Hab auch noch keinen Programmierer gesehen, der das gemacht hat)
Schlechtes Beispiel: Ich habe vor einigen Tagen eine Anwendung gecrackt, deren Testphase niemals abläuft, wenn man folgendes tut: Zeit 10 Jahre vor; Programm installieren; Zeit 10 Jahre zurück und schon hat man ca. 3600 Tage, um das Programm zu testen. Bis dahin sollte eine neue Version draussen sein ;-).

Wenn wir den Nagscreen endlich überwunden haben, dann steht in vielen Programmen, die unregistriert sind (meistens im Fenstertitel) UNREGISTRIERT. Da bedankt sich jeder Cracker. Wieder ein Ausgangspunkt für einen Crack mehr.
Wenn man so etwas schon macht, dann sollte man wenigstens nicht innerhalb der gleichen Prozedur noch den Fenstertitel verändern. So zeigt man nämlich die Prozedur an, die es zu überbrücken gilt. In manchen Programmen (ich glaube
z.B. WinRar) genügt es das Ändern des Fenstertitels zu überbrücken und schon hat man eine registrierte Version. (Einwurf: Gerade fällt mir ein: Gibt es vielleicht Programme, die den Programmstatus am Fenstertitel festmachen ?
Wenn ja, dann verdienen die Programmierer ihr Geld nicht !) Das selbe gilt für den Text, der in der Copyrightsbox steht (Registriert von...).

Wenn wir uns ein wenig in Win-Dummy umsehen, dann bemerken wir, das es extrem in seinen Funktionen limitiert ist. Das erkennt man teils daran, das manche Menüs und Buttons "grau" sind und nach Drücken auf andere Buttons eine
Messagebox erscheint, die mir mitteilt, das diese Funktion nur in der Vollversion vorhanden ist.

Einwurf: Definieren sie alle Menüs dynamisch, während das Programm startet.
             Bereits definierte Menüs kann man mit einem Ressource-Workshop leicht
             verändern (Menüpunkte aktivieren...).

Das "ausgrauen" von Menüs ist prinzipiell schon mal schlecht. Irgendwo im Programm muss der Code stehen, der das macht. Dort steht der Win-API Befehl EnableMenuItem und der Name des Menüs, den man aus dem Programm her kennt. Schwerer zu finden ist ein Menü, dessen Namen man nicht kennt. (Aufpassen auf Hilfedatei) Das komplette nicht-anzeigen von Menüpunkten ist deshalb um einiges sicherer. Was ich von MessageBoxes halte, sagte ich ja weiter oben bereits.

Jetzt wenden wir uns dem Ausspionieren des Registrierungscodes zu. Das erste Problem, das hierbei auftauchen sollte ist: Wo zur Hölle muss ich den Code eingeben ?

Am besten ist es, wenn man eine verstecktes Eingabefenster programmiert, daß nur auf Tastendruck erscheint. Diese Tastenkombination könnte etwas ausgefallenes wie [CTRL]+[ALT]+[ENTF] ;-) sein. Besser ist jedoch wenn man
als Kombination [CTRL]+[D] wählt (Ich gehe nicht weiter darauf ein, es hat aber was mit dem Debugger zu tun.).

Jetzt kommen zwei meiner Lieblingstricks, die ich bei meinen CrackMes gerne benutze. Zuerst sollte man die Eingabefelder falsch herum bennenen (Feld für Name heisst "Hier Code eingeben" und anders herum). Da muss man erst mal draufkommen. Dies setzt natürlich voraus, daß keine Einschränkungen für das Textfeld vorhanden sind (max 10 Zeichen/nur Ziffern...).
Mein zweiter Lieblingstrick ist, daß man zwei Eingabefelder für Namen und Code programmiert und darunter einen OK-Button setzt. Den Code checkt man bei jeder Änderung der Textfelder (dann darf natürlich keine MessageBox kommen, wenn der Code falsch ist.). Wenn man den OK-Button drückt, ist der Code IMMER falsch und es erscheint IMMER die "Falscher Code-Box"  (natürlich ASCII(65)+ASCII(66)...).

Aber warum ist man auf Eingabefelder beschränkt ? Etwas komplett neues und definitiv extrem schwer zu crackendes Verfahren zur Kalkulation eines Codes ist nicht ein Eingabefeld zu erzeugen, in das man den Code eingibt, sondern eine 10x10-Matrix aus Checkboxes zu erschaffen, bei der jede Kombination markiert/unmarkiert genau einem Namen zuzuordnen ist. Auch andere Eingabefelder (ComboBox/ListBox...) sind dazu zu gebrauchen (Phantasie ist gefragt).

Zur Codeberechnung:
Zuerst muss man Variablen deklarieren. Wenn das geschieht reserviert das Programm im Speicher je nach Typ der Variablen Platz und dahinter beginnt der Speicherplatz der nächsten Variablen. Also die Variablen für Name, Code und richtigen Code so weit wie nur möglich von einander weg deklarieren. Als schlechtes Beispiel kann ich hier ein Programm von mir nennen. Ich war bei einem Freund (auch Cracker). Er startet den Debugger, dann mein Programm und fängt an zu lachen. Dann zeigt er mir, daß Name, eingegebener und richtiger Code keine 100 Bytes voneinander entfernt im Speicher liegen.

Man sollte niemals die komplette Registrierungsnummer auf einmal berechnen. Besser ist es sie in zwei oder mehr Teile zu zerlegen und dann einzeln mit den entsprechenden Teilen des eingegebenen Codes zu vergleichen. Die Registrierungsnummer sollte man 1000 mal einlesen (hat auch was mit dem Debugger zu tun) und die Berechnung des Codes auch 20-30 mal durchlaufen lassen. Dabei gilt: Je komplexer die mathematischen Operationen sind, die man benutzt, um den Code zu berechnen, desto weniger wahrscheinlich ist es, daß der Cracker bemerkt, daß er sich in einer riesigen Schleife befindet. Man
sollte eh jede Menge Müll und unnötige Mache-Nichts-Funktionen während der Codeberechnung aufrufen, die den Cracker verwirren. Zumindestens ein Key-Generator wird dadurch absolut unwahrscheinlich. Ebenfalls sollte man die Schleifen möglichst gross machen, damit der Cracker nicht merkt, das er sich in einer Schleife befindet und einfach einen Breakpoint dahintersetzt.

Lustig ist in diesem Zusammenhang auch die "Fake"-Serial Berechnung. Dazu bastelt man zur echten Prozedur nochmals eine hinzu, die eine falsche Nummer ausrechnet. Wenn der Cracker diese im RAM sieht und nicht mitdenkt, wird er
denken, daß er die richtige Nummer gefunden hat und verzweifelt an der "Falscher Code"-Meldung.

(Ein bißchen) Schwer zu cracken ist auch eine Codeberechnung, die nicht mit Werten rechnet, sondern mit Zeigern auf Speicheradressen.

Wenn man schon eine MessageBox mit "echten" Strings verwendet, dann sollte man den Code zweimal checken. Einmal mit Box und einmal ohne. ACHTUNG: Nicht zweimal die gleiche Prozedur aufrufen, sondern zwei verschiedene.

Ist die Falsche Code-Meldung erschienen, dann sollte das Programm zwei Sekunden keine Eingabe zulassen. Das verhindert das Rausfinden von Codes durch Brute Force Verfahren. Brute Force heist "brutale Gewalt" und bedeutet, man hat ein kleines Programm, das ganz schnell alle Zeichenkombinationen als Code ausprobiert. Es gibt solche Programme, die können mehrere tausend Codes pro Sekunden prüfen, aber nur wenn das Zielprogramm mitspielt.

Dummheit ist natürlich, wenn man die richtige Seriennummer in die KEY/DAT/INI/CFG... Datei schreibt, statt der eingegebenen. Dann muss man nur einmal die Abfrage überbrücken und schon hat man die richtige Seriennummer für jeden beliebigen Namen (siehe Goldwave 3.24 in V4.02 hat der Programmierer es jedoch bemerkt ;-)). Auch nicht gerade von Intelligenz zeugt die Routine von Hex Workshop 2.54. Wenn man da einmal die Routine überbrückt, erzeugt HW einen gültigen Keyfile. (Habe den Programmierern geschrieben, aber nie eine Antwort erhalten :(   ).

Wenn der Code berechnet ist, sollte man alle Variablen, die der Codeberechnung dienen auf 0 (Integer) und (leer) (String) setzen, damit das durchsuchen des RAM verhindert wird.
 
 

Dinge, die schwer zu programmieren/cracken sind, die ich nicht in meiner kleinen Geschichte hab unterbringen können, oder die ich mir gerade ausgedacht habe (Ob sie funktionieren ist eine andere Sache):


 






Die folgenden Dinge sind zum Teil schwer zu programmieren oder schwer zu cracken. Manche sind jedoch zu überladen für ein Sharewareprogramm und eignen sich mehr für den Einsatz in kommerziellen Programmen.

1. Wenn man einen Prüfsummencheck durchführt und eine Fehlermeldung ausgibt, ist der meistens einfacher zu cracken, als das eigentliche Programm. Viel lustiger ist es, eine EXE und eine DLL Datei zu programmieren, die sich gegenseitig überprüfen und ohne Fehlermeldung aussteigen, wenn etwas nicht stimmt.

2. Wäre es möglich, den Namen der Datei, in der die Informationen gespeichert sind aus der richtigen Registrierungsnummer zu erstellen und dann aus der Windows-Registry darauf zu verweisen ? Das hätte den Vorteil, das zu Beginn niemand wüsste, wie der Name der Datei ist (nicht mal das Programm selbst).

3. Was ich in meinem nächsten CrackMe mache: Das Eingabefeld hat die gleiche Farbe, wie das Hintergrundfenster und besitzt keinen Rahmen. Dann kann man es nicht mehr erkennen. Das eingegebene Passwort wird überprüft, sobald sich im Eingabefeld etwas ändert.

4. Irgendwo im Programm Strings einbauen, die identisch mit den "Falscher Code"/"Danke" Strings sind, aber eigentlich nichts damit zu tun haben.

5. Möglichst einen Punkt am Ende des Passworts verwenden, da diese im Debugger schwer zu erkennen sind. Man sieht norwalerweise das Passwort so:

OFFSET      HEX-CODE DES PASSWORTS         PWD IN ASCII
XXXX:XXXX   00 00 00 00 00 00 00 00        ........
XXXX:XXXX   65 66 67 68 69 70 71 2D        ABCDEFG.
XXXX:XXXX   00 00 00 00 00 00 00 00        ........

Wer im Freudentaumel nur einen flüchtigen Blick darauf wirft, denkt, das der Punkt hinter G nicht mehr zum Password gehört, sondern nur als Platzhalter für ASCII 00 gilt, wie die anderen Punkte.

6. Wenn man schon "-" benutzt, um das Password zu unterteilen, dann sollte man explizit nach den Strichen fragen, und nicht das gesamte Passwort mit Strichen berechnen. Außerdem ist eine regelmäßige Strichesetzung (XXX-XXX-XXX) einfacher zu cracken, als z.B.X-XXXXX-XXX.

7.Auch noch nirgendwo gelesen. Normalerweise sieht die Abfrage für einen Nag-Screen so aus: C++-Code

int a=0;
a=PasswortVerifizieren();
if (a==1) NagScreen();

wenn man aber schreibt:
int a=0;
int b=0;
CheckPassword();         //Rückgabewert b muss 1 sein, sonst wurde Prozedur übergangen
if (b==0) then PasswortCheckWurdeUebergangen();
if (a==1) then ShowNag();
(Alternativ ginge auch (sogar besser): if ((a==1)||(b==0))      // für alle nicht C++ler || bedeutet oder)

Prozedur :
CheckPassword():
{
Code, um das Passwort zu verifizieren; wenn falsch a=1;
b=1;
}

Jetzt kann man nicht mehr hergehen, und den gesamten Call übergehen. Natürlich ist es weiterhin möglich, die Bedingung der PassWortWurdeUebergangen Routine zu ändern, aber wer sagt denn, dass man nur mit einer Kontrollvariablen und ohne Prozedurverschachtelungen programmiert. (Bischen Phantasie bitte)

8. Ein Cracker geht immer vom idealen Programmierer aus: Nur Prozeduren, lokale Variablen... Zumindest beim Passwortcheck und anderen solchen Dingen sollte man vollkommen ohne Prozeduren, sondern mit Copy/Paste im Quellcode arbeiten. Das bedeutet, wenn man das Passwort schon zweimal überprüft, dann ohne Prozedur. Beispiel: Wenn man eine Prozedur 1000 mal aufruft, genügt meistens schon eine Änderung von max. 8 Bytes, um den Aufruf zu übergehen. Wird der gleiche Code aber 1000 mal hintereinander aufgerufen, muss man (wenn man Pech hat) 1000*8 Bytes ändern und das macht keiner.

9. Wenn man Delphi oder C++ Builder programmiert und die vorgefertigten Komponenten benutzt (z.B.Label) kann man ruhig Dinge wie "Unregistriert" als Anfangstext verwenden, da diese Strings verschlüsselt in die EXE-Datei kompiliert werden.

10. Die Informationen, ob das Programm registriert ist, sollte man in die Haupt EXE-Datei schreiben. Weis nicht, wie das geht, weis nur, daß es geht. Siehe: Visual Help Pro.

11. Wenn die Registriernummer auch noch von der Hardwarekonfiguration (Intel/AMD oder anderer CPU Hersteller?/ 16/32.. MB RAM?/ Festplatte C: größer 4 GB?) abhängt, ist alles aus. So kann man das Verbreiten von Codes über das Internet verhindern. Nachteil: Kunden müssen bei Änderung der Konfiguration neue Codes beantragen. Nicht so toll finde ich auch die Methode, die die Programmierer von Visual Help Pro gewählt haben. Da hängt der Registrierungscode vom Monat der Registrierung ab.

12. Man sollte prüfen, ob der Name Sonderzeichen enthält, da kein normaler Name so lauten kann: LaZaRuS [hf] - ED!SON - +wAj. - _mammon - ][ce usw. Bei - muss man vorsichtig sein, da es sich um einen Doppelnamen handeln könnte: Karl-Heinz.

13. Absolute Sicherheit kann es nur geben, wenn in der Sharewareversion Programmteil fehlen (DLL-Dateien), die die wichtigen Funktionen enthalten. Beispiel: Audio Grabber 1.40. Die EXE-Datei ist bei SW und Vollversion die gleiche. Nur fehlt in der SW-Version die DLL AudioFull.dll (oder so ähnlich). In der SW Version ist nur die Datei AudioFree.dll (oder so ähnlich) enthalten. Diese SW findet man dann aber auf Warez-Seiten.

14. Man könnte checken, ob Fenster geöffnet sind, in denen folgende Strings vorkommen "W32Dasm", "IDA", "Smart Check", "WinSight". Wenn es solche gibt, dann sieht nach Crack Versuch aus."

15. Es gibt spezielle Codefolgen, die bringen gnadenlos jeden Disassembler zum Absturz. Die kenne ich jedoch nicht, also müssen sie selbst nachforschen, wenn sie dies in ihre Programme implementieren wollen.

16. Man kann feststellen, ob ein Debugger geladen ist. Geht über einen Interrupt (13?). Darüber weis ich jedoch auch nichts genaues. Oliver Buschjost (http://software.webset.de/buschjost) benutzt in seinem Programm MP3 TO EXE 2.0 solch einen Debugger Check (von Marquee) der einen mit den Worten "You wouldn't see this if there wasn't a debugger running in the background" oder so ähnlich begrüsst.
 
 


Dinge, von deren Wirkung Sharewareprogrammierer so überzeugt sind, das sie sie immer wieder benutzen, obwohl sie den Crack in keinem Fall erschweren


 






Hier sind Dinge, die ich immer wieder in Sharewareprogrammen sehe. Die Programmierer glauben wohl, das sie unserer "Gilde" die Arbeit damit erschweren. Das stimmt aber in keinem Fall. Statt die folgenden Massnahmen zu implementieren sollte man mehr Zeit auf die oben genannten verwenden.

1. Manche Leute glauben, das es schwer ist Seriennummern rauszukriegen, wenn man keine MessageBox "Wrong Serial" bringt. Sie zeigen stattdessen nur eine, wenn das Programm korrekt registriert wurde. Das ist jedoch genausoviel wert. Irgendwo muss ja etwas stehen wie:

CALL XXXXXX    ;; Berechne RegCode und vergleiche mit eingegebenem
TEST EAX, EAX  ;; RegCode korrekt ?
JE 1234        ;; Wenn ja, dann springe
...            ;; Sonst weiter im Programm

1234: ????     ;; Zeige hier MessageBox "Thank you" an

Wenn ich also keine "Falscher Code" Box finde, dann suche ich nach "Thank..." (englische Programme) oder "Danke.." (deutsche Programme). Für was sollten die Phrasen sonst stehen ?

2. Es gibt Programmierer, die glauben ein ellenlanger (30+ Zeichen) RegCode wäre schwerer zu knacken, als ein kurzer (-15). Diese denken jedoch nur an Brute Force Verfahren und nicht an die "wahre Kunst". Wenn die Routine so aussieht.

CALL XXXXXX    ;; Berechne RegCode und vergleiche mit eingegebenem
TEST EAX, EAX  ;; RegCode korrekt ?
JE 1234        ;; Wenn ja, dann springe

und man den Code in irgendeinem Register (oder nahe der Position des eingegebenen Namens) auslesen kann, könnten sie auch einen RegCode aus 100 Zeichen bestehen lassen.

3. Das gleiche gilt für das Verwenden von "-". Es nützt gar nichts, wenn man den RegCode irgendwo im RAM auslesen kann. Besser ist sowas:
if (3. Zeichen des Codes "-") then
if (6. Zeichen des Codes "-") then
if (9. Zeichen des Codes "-") then
Beginne Code Berechnung
 

Visual Basic Programme
Zuerst dachte man VB Programme sind schwerer zu cracken, als "richtige" Programme. Ich schreibe "richtige" Programme, weil VB keine echten EXE Dateien erzeugt. Stattdessen ist VB eine Interpretersprache, die Befehle an die Runtime Module VBRUNXXX.DLL schickt, die die DLL dann ausführt. Da es mittlerweile aber sehr gute Decompiler für Visual Basic EXEs gibt, ist auch VB Cracken kein Problem mehr.Wenn ich im Vorgänger dieses Dokuments noch schrieb, das die Tips nicht für VB Programme gelten, so muss ich heute sagen, dass die Tips auch voll für VB gelten.
Ein weiterer Ansatz VB zu cracken hat Razzia in einem Tutorial beschrieben. Mit einer leicht modifizierten VBRUNXXX.DLL erscheint nach einer falschen RegCode Eingabe nicht die "Falscher Code" MessageBox, sondern eine MessageBox mit der korrekten Serial. (Ich lache immer noch jedes mal, wenn ich das sehe).
btw: Das funktioniert auch, wenn der Programmierer keine MessageBox erscheinen lässt, da nicht die "Falscher Code" Box "missbraucht" wird, sondern eine (so gut wie ungenutzte) Routine, die irgendwo in der VBRUNXXX.DLL schlummert.
 

Beispiele:

Soft-Ice (den verbreitetsten Debugger) feststellen:
Diesen Beispiel-Code für C++ habe ich kürzlich gefunden:

//////////////////////////////////////////////////////////////////////
//
// MeltICE - SoftICE '95 version 3 detection - Made by David Eriksson
// ==================================================================
//
// Disclaimer
// ~~~~~~~~~~
// I take no responsibility for the authenticity of this information,
// or the results of the use or misuse of the source code.
//
// SoftICE is a trademark of NuMega Technologies, Inc.
//
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

//////////////////////////////////////////////////////////////////////
//
// See if SoftICE version 3.x for Windows 95 is loaded
//

BOOL IsSoftIce95Loaded()
{
 HANDLE hFile;

 // "\\.\SICE" without escape stuff
 hFile = CreateFile( "\\\\.\\SICE",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);

 if( hFile != INVALID_HANDLE_VALUE )
 {
  CloseHandle(hFile);
  return TRUE;
 }

 return FALSE;
}

//////////////////////////////////////////////////////////////////////
//
// See if SoftICE version 3.x for Windows NT is loaded
//
BOOL IsSoftIceNTLoaded()
{
 HANDLE hFile;

 // "\\.\NTICE" without escape stuff
 hFile = CreateFile( "\\\\.\\NTICE",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);

 if( hFile != INVALID_HANDLE_VALUE )
 {
  CloseHandle(hFile);
  return TRUE;
 }

 return FALSE;
}

//////////////////////////////////////////////////////////////////////
//
// Example code for calling these functions
//
int main(void)
{
 if( IsSoftIce95Loaded() )
  printf("SoftICE for Windows 95 is active!\n");
 else if( IsSoftIceNTLoaded() )
  printf("SoftICE for Windows NT is active!\n");
 else
  printf("Can't find SoftICE with this method!\n");

 return 0;
}

Final words
~~~~~~~~~~~
Hopefully this will make shareware developers a little bit easier
about the safety of their software. I would appreciate if I got
credit whenever you use the information provided here - and maybe a
copy of your software...
(You don't

Good luck with your development!

- David Eriksson (david@2goodsoft.com), August 12, 1997
 

Ok, ich würde vorschlagen keine Fehlermeldung auszugeben, wenn SICE festgestellt werden kann. Die folgende Methode ist viel effektiver, wenn es darum geht Registrierungscodes zu schützen (aber nutzlos, wenn es um Date-Checks oder Nag-Screens geht). Man sollte eine Variable (int fake) deklarieren, der man den Wert 1 zuweist, wenn SICE nicht gefunden werden kann. Wird SICE jedoch gefunden, weist man ihr den Wert 2 zu. Dann fügt man irgendwo in der Routine, in der der korrekte Registrierungscode berechnet wird die Zeile

regcode = regcode * fake;

ein. Dann wird eine Registrierungsnummer berechnet, die nur gilt, wenn SICE geladen ist, und der Cracker wird sich doch sehr wundern, warum das Programm nicht registriert ist, wenn er das nächste Mal das Programm startet, ohne dass SICE geladen ist. Wenn er das Programm nach dem "erfolgreichen" Cracken wieder deinstalliert, ohne den Code erneut zu testen und diesen stattdessen sofort auf seine Internet Page lädt ensteht überhaupt kein Schaden für den Shareware Autor, da die Registrierungsnummer für den "normalen" Anwender keine Gültigkeit hat.

Mein "uncrackbares" CrackMe:

Hier ist das Prinzip eines CrackMes, das ich programmiert habe. Es ist höllisch schwer zu cracken, für einen ehrlichen Anwender dennoch leicht zu registrieren. Da das Programm zu umfangreich ist, erläutere ich nur die Funktionsweise.
 

  1. Natürlich verwendet es den Melt Ice Trick von oben
  2. Alle Strings sind weichgecoded z.B.: String smiley=String(char(58))+String(char(41)); für :)
  3. Wenn eine Datei namens Hell.key (einziger Hardgecodeder String) gefunden wird, dann kommt eine Fehlermeldung "Corrupted Keyfile". Dies soll den Cracker auf die absolut funktionslose Datei Hell.key aufmerksam machen.
  4. In der Registerbox ist das Eingabefeld schreibgeschützt, bis man [CTRL]+[D] drückt, ausserdem sieht es aus, wie ein ganz normales Textfeld (man kann es nicht vom Hintergrundfenster unterscheiden)
  5. Es gibt noch zwei Eingabefelder, die sich jedoch überlappen, so das man sie für eines hält. Das erste macht ca. 90% der Gesamtbreite aus, das zweite 10%. In jedes Textfeld muss eine Seriennummer eingetragen werden.
  6. Der Name wird auf folgende Zeichen untersucht: 0..9 / [ ] _ + ^ $  | @
  7. An belanglosen Stellen habe ich Strings hardgecoded, die genau so lauten wie die Fehlermeldung, aber mit dieser nichts zu tun haben
  8. Das Programm testet, ob aktive Fenster mit deren Titel "W32Dasm" oder "Interactive Disassembler" enthält .Wenn ja, dann fake = 2
  9. Die erste Seriennummer muss "..." am Ende haben, die zweite "."
  10. Um das Programm zu registrieren muss eine Datei mit dem Namen der ersten Seriennummer ohne "...", dafür aber mit ".key" vorhanden sein. Dort werden die Informationen gespeichert. Auf diese Datei verweist ein Eintrag in einer INI-Datei, der bei korrekter Registrierung angelegt wird.
  11. Schwäche 1: Kein Test, ob Datei verändert worden ist
  12. Schwäche 2: benutzte Windows-Funktionen wie MessageBox oder GetPrivateProfileString (INI-Dateien)
  13. Schwäche 3: Man kann das Programm über den OK-Button registrieren: Besser wäre immer dann zu prüfen, wenn sich etwas in den Eingabefeldern verändert
Was soll ich sagen: Bisher hat's noch keiner geschafft  :-)

Glossar:
Breakpoint   - Ein Breakpoint ist ein "Lesezeichen" im Debugger, mit dem man
               ein Programm debuggt. Wenn solch ein Lesezeichen erreicht ist, dann
               öffnet sich der sonst im Hintergrund laufende Debugger selbstständig
               und man kann Änderungen im Programm (im RAM) vornehmen. BP lassen
               sich auf Speicheradressen, Windows API-Funktionen, Hardwareschnitt-
               stellenaktivität (für Hardware-Dongles)... setzen.
CrackMe      - Ein CrackMe ist ein Beispielprogramm, das von Crackern geschrieben
               ist, um andere Cracker zu beschäfigen und vor eine Aufgabe zu stellen,
               die von Sharewareprogrammen nicht mehr gefordert werden, oder sich
               in einem speziellen Gebiet weiterbilden wollen.
Debugger     - Ein Debugger ist ein Programm, mit dem man ein Programm in seinem
               Ablauf beeinflussen kann. Man kann dort Assembleranweisungen ändern
               oder den Ram nach Werten durchsuchen. Eigentlich kann man mit einem Debugger
               alles im RAM tun, was man will, nur endet das manchmal mit einem Reset.
Disassembler - Ein Programm, das ausführbare Dateien in Assemblerinstruktionen zer-
               legt.
Hardcoden    - Das Definieren eines Strings auf folgende Weise String hallo="Hallo".
               Gegenteil weichcoden: String hallo=char(72)+char(97)+char(108)+char(108)
               +char(111) (Das muss man halt für die verschiedenen Sprachen anpassen)
KeyGenerator - Kleines Programm, mit dem auf Namen basierende Registrierungscodes für
               Sharewareprogramme erstellen kann. (Hab im Urlaub meinen ersten programmiert:
               10 Stunden/25 Seiten kommentierter Assembler Code nur um am Ende festzustellen,
               das mein genereller Ansatz für einen KeyGenerator falsch war (hätte ich nur
               vorher was darüber gelesen). Es hätten auch 1 Stunde und 15 Zeilen
               kommentierter Code gereicht:(. Ich habs aber trotzdem geschafft :)

Greetings:
Thanx/Greetz and Gratitude to Fravia+, tKC, ED!SON, Sandman, DaVinci, Eternal Bliss, +wAj, Shadow, Jordan - The Black Wizard, Razzia

The hole document was coded by LaZaRuS [hf]
last changed 13.03.1999

Anmerkungen/Korrekturen/(konstruktive) Kritik/Anfügungen an lazarus666@gnwmail.com
Bitte mailt mir. Keine Antwort ist schlimmer, als eine schlechte. (Ausser ihr wollt mich beleidigen, dann spart euch die Mail)
Wenn irgendein Cracker/Reverser das liest und glaubt manche Dinge besser zu wissen, bitte ich auch um eine Mail.
Wenn irgendjemand glaubt ich sollte seine Programme (kein VB oder DOS) mal testen und spezielle Tips geben, dann mailt mir aber vorsicht ich werde mich natürlich bei dem entsprechenden Programmierer mit Angabe der ersten Mailadresse rückversichern. Bitte mailt mir auch, was ich cracken soll, da ich keine Lust habe nach Einschränkungen zu suchen, die nach 37 Programmstarts im 60. Untermenü entstehen.
 

Bitte dieses Dokument so weit wie möglich verbreiten. Es ist ausdrücklich gestattet es überall zu veröffentlichen. (Bitte unverändert) Wenn ich es in 6 Monaten irgendwo auf einer WebPage sehe, dann glaube ich, das die Arbeit dieses Dokument zu schreiben sich ausgezahlt hat.