Inhalt
Vorwort Viele kleine Programme stellen nur gegen eine kleine "Spende" den gesamten Funktionsumfang zur Verfügung. Für diese Programme wird ein kompakter Kopierschutz benötigt, der nur die einfachsten Dinge beinhaltet:
So weit es geht wird natürlich Visual Basic 2010 verwendet, alternativ geht auch jedes andere VB, dass mit .Net läuft. Im Web-Backend greife ich auf PHP zurück, aber der Code ist so kurz, dass er sich sehr schnell nach ASP etc. portieren lässt. Sollten Sie jetzt noch Fragen oder andere Bedenken haben, scrollen Sie nach unten zu den FAQ. Ich möchte Sie bitten, den Text gründlich zu lesen, da viele Features und Sicherheitslücken durch Copy & Paste unbeachtet bleiben und der Kopierschutz sehr flexibel gestaltet wurde und einige Anpassungen an das Einsatzgebiet erfordert. Außerdem sollte dieser Workshop nicht mit dem bereits bestehenden Workshop für einen Kopierschutz verwechselt werden, da sich dieser auf klasisches Visual Basic und einen rein Clientseitigen Schutz sowie andere Ansätze wie Produkt-IDs verfolgt, während hier das Programm direkt beim Verschlüsseln identifiziert wird. Vorbereitungen Auf ihrem lokalen PC sollte eine Visual Basic .Net-IDE oder zumindest ein passender Compiler installiert sein. Für das Web-Backend können Sie - falls Sie wie hier gezeigt PHP verwenden - mit dem Windows-Editor auskommen, Notepad++ oder Alternativen sind natürlich komfortabler. Um das Backend testen zu können, empfiehlt es sich, einen PHP- und MySQL-fähigen Webserver zu installieren, z.B. WAMPP. Sollten Sie statt PHP und MySQL auf ASP setzen genügt eine VB- oder C#-IDE und der MS SQL Server. Funktionsweise Der Kopierschutz wird im Wesentlichen wie folgt funktionieren: Beim ersten Start:
Computer-ID ermitteln Der Sinn eines Kopierschutzes ist im Wesentlichen in diesen beiden Punkten enthalten:
Um das Programm an einen Computer zu binden, erzeugt man eine Computer-ID und speichert diese Verschlüsselt ab. In diesem Kapitel zeige ich, wie man die ID erzeugt. Damit die IDs eine einheitliche Länge haben, speichert man sie am besten als Hash-Werte, bekannt sind die Verfahren MD5 und SHA1, ich verwende hier der einfachheit halber die Standartfunktion von .Net, Object.GetHashCode(). Doch vorher ncoh eine kleine Hilfsfunktion, die Hashwerte in Hexadezimalzahlen umwandelt und auf eine einheitliche Länge bringt, damit Visual Basic keine Nullen abschneidet und den Hash somit (zer)stört: Function Hex(ByVal I As Integer) As String Dim S As String S = Conversion.Hex(I) While S.Length < 8 S &= "0" End While Return S End Function Die Funktion, die den Hash erzeugt, muss nicht wie die hier gezeigt aussehen, es macht es Hackern schwerer, wenn jedes Programm andere Haswerte erzeugt. Außerdem muss man immer abwägen, ob das Programm beispielsweise auf einem multilingualen System verwendet wird, was die Prüfung von InstalledUICulture, die hier durchgeführt wird natürlich sinnlos und Fehleranfällig macht. Function GetHash() As String Dim H As String = "" H &= Hex(My.Computer.Info.InstalledUICulture.GetHashCode) H &= Hex(My.Computer.FileSystem.GetDriveInfo(Environ("SYSTEMDRIVE")).TotalSize.GetHashCode) H &= Hex(My.Computer.Info.OSFullName.GetHashCode) H &= Hex(My.Computer.Info.OSPlatform.GetHashCode) H &= Hex(My.Computer.Info.OSVersion.GetHashCode) H &= Hex(My.Computer.Info.TotalPhysicalMemory.GetHashCode) H &= Hex(My.Computer.Mouse.WheelExists.GetHashCode) H &= Hex(My.User.Name.GetHashCode) H &= Hex(My.User.IsAuthenticated.GetHashCode) H &= Hex(My.User.CurrentPrincipal.Identity.Name.GetHashCode) H &= Hex(Environ("PROCESSOR_ARCHITECTURE").GetHashCode) H &= Hex(Environ("SYSTEMROOT").GetHashCode) H &= Hex(Environ("NUMBER_OF_PROCESSORS").GetHashCode) H &= Hex(My.Computer.Registry.LocalMachine.OpenSubKey( _ "HARDWARE\DESCRIPTION\System\CentralProcessor\0\").GetValue("~MHZ").GetHashCode) H &= Hex(My.Computer.Registry.LocalMachine.OpenSubKey( _ "HARDWARE\DESCRIPTION\System\BIOS\").GetValue("SystemManufacturer").GetHashCode) H &= Hex(H.GetHashCode) Return (LCase(H)) End Function Diese Funktion prüft die Systemsprache, das Systemlaufwerk, die Betriebssystemversion, den Speicher, das Mausrädchen, den Benutzer, den Prozessor sowie das BIOS. Zur zusätzlichen Sicherheit wird auch von der ID selbst ein Hash erzeugt und angehängt, um Manipulationen aufzuspüren. Sie sollten diese Funktion wie schon gesagt je nach verwendungszweck einschränken, da sich insbesondere der Arbeitspeicher ändern kann. Eine andere Möglichkeit wäre, ein Toleranzsystem wie bei Windows einzuführen, dazu später mehr. Mein PC bekommt beispielsweise bei einer leicht modifizierten Funktion die ID bbe3f9c759b801ffff8b9f09cdb89ab64b8683bbf5b000019b723ae519b723ae58781314 c10dbdc0cdcab78e746d36f76fe2aba7c200000000000000000000, die nicht so schnell auf einem anderen Computer zu finden sein wird. ID verschlüsselt speichern Nachdem Sie die ID erzeugt haben müssen Sie diese natürlich auch speichern, um herauszufinden, ob das Programm kopiert wurde. Dies muss verschlüsselt geschehen, damit die Datei nicht bearbeitet werden kann. Ich habe einen einfache Algorithmus entwickelt, der als Schlüssel einen Teil des Programms benutzt. Das hat den Vorteil, das ID-Dateien des einen Programms nicht einfach einem anderen Untergeschoben werden können. Sub Generate() Dim P() As Byte, C As String, X() As Byte, Z As Integer P = My.Computer.FileSystem.ReadAllBytes(Application.ExecutablePath) ReDim X(KeyLen() \ 8) C = GetHash() Z = 0 For I As Integer = 0 To 127 X(Z) = P(I) Xor Asc(C(I)) Z += 1 Randomize() For J As Integer = Z To Z + P(I + 128) X(J) = CInt(Rnd() * 254) Next Z += P(I + 128) Next My.Computer.FileSystem.WriteAllBytes(Application.StartupPath & "\nanticop.y", X, False) End Sub Ich habe dieses Verfahren nBlow getauft, da die Daten aufgeblasen werden. Der Dateiname kommt von dem Namen eines Kopierschutzes, der auf dieser Technik basiert, nAntiCopy. Bei der Verschlüsselung passiert folgendes:
/}Ýxè‡ÍÅéí•ÖX5ìŠLoEµz ¶-ž¥-ô÷Šò‰ÂÌ([ë¤iÂsDç)ËÝ&‡§¢ oY•dänTÀmãúleM ""»Þ|8JFNòµX×9§#ËØ ÞÖ¨´ùh.¥ †óÐvÉ6,OÅéSEÜùc-£·3OD¶Ö¾!Þh+¸ÀÂÍ(!ÔÆîëASõ3e‹<¹Dˆ@üÆR)«Á-vª?7…-¡5v£= \;jãQ«*¸Û.z|¬©xqK›}šf1üé¿;ÇYj›ÃFB{6ý/î6¶¸Xú:7v9²"…µc3¾¹çèwŒ¹Ü¡41\$£² y»oSW/3ñùÅ_‹ ªÛÎNöûžce-E Ô´ëcXZâŠ-]õWá¦Ø³ú¾ØH7bçsêáÏ¿4ºq"ò{‹-°Üaiˆ®5|ÌCœ¡ÚS¬È©Y‰¬ÙxVÈðdµq ¹w(9rFµÖØNqrk¢ÄtÐjÁ»}¹Ý>¦ý°"(9 .à·ÒRS.›¤ÅªF²"b‹<¹Dˆ@üÆR)«Á-vª?7…-¡5v£=\;jãQ«*¸Û.z|¬©xqK›}šf1üé¿;ÇYj›ÃFB{6ý/î 6¶¸Xú:ÇÏ1fÞff8b¾¹çèwŒ¹Ü¡41\$£² y»oSW/3ñùÅ_‹ ªÛÎNöûžce-E Ô´ëcXZâŠ-]õWá¦Ø³ú¾ØH7bçsêáÏ¿4ºq"ò{‹-°Üaiˆ® Ó-ØÞ!PFë.ùN×™dIï#³{áåÚ ç/„»]ÒÐb\jÏ[|\0$© àj3QÒ -Œ¾!Àz±PU›öÄl3ØjÕ%´ûð¢ Æd Ô±zDý·C1LœÁÚyL8ùÛ´=båíÊ@ò§ò<Tã™wSÊðûzÜ•9f¢ý0y»ÚpDH~,djcd›yÓ¼0¦b89 ¾¹çèwŒ¹Ü¡41\$£² y»oSW/3ñùÅ_‹ ªÛÎNöûžce-E Ô´ëcXZâŠ-]õWá¦Ø³ú¾ØH7bçsêáÏ¿4ºq"ò{‹-°Üaiˆ® Ó-ØÞ!PFë.ùN×™dIï#³{áå Úç/„»]ÒÐb\jÏ[|\0$© àj3QÒ -Œ¾!Àz±PU›öÄl3ØjÕ%´ûð¢ Æd Ô±zDý·C1LœaÏb64I,R£Ó‚¦Ü½A3†{2b8683bbÍÝlÉ|°ìˆ•È‡R4¿òiHšÄ ]®Ìe-ÕÉQ·½áö#èªð8!VÞwü²0Œç°7´û„Ëò¶2DL"‡† 9°¥^Z+Ý ÖÌæTËUX%.ólQ®¥Âß¼ñ ÂnÅ¥èr‰\ @ÈßóY9ŸÈæ¨<lÌÄ‹•9<ݪ©Ç€Iˆ°xl!ßö7㵨ü·Ê}•ílÉÛ@÷0 ‚íp ˆ2¸Ì÷œ'ÕK"-Ê`>ý$2xƒ:fjÀƒ› `ªPÅhãñ1m@ãŽ÷ïIÛO*Ç")¬ïªQŒæaEÑìw*X¯îŽ^ä3¿Œ9¯ È71)~öw¡›·ñ„=5™o("BÝ[¤ò;ºfSodÕ\±û´^×6'êËÎCÞÓ¶|Î#´ðÃòa|õÏ[Ÿ1è(¨ ¾:4b²žôNÜpa;™ êÆùö¬;w;íŽs¡ï$úµ'ЋJt3ð´ ¦çÁwÏýüP±ê'Ó¶ÚqWŸ bFÔ¤0OžÛ tCï *ºp5"b00dæÓZÕf•^bvˬí´Üض˜RŠÞý¸ó0010‹<¹Dˆ@üÆR)«Á-vª?7…-¡5v£=\;jãQ«*¸Û.z|¬© xqK›}šf1üé¿;ÇYj›ÃFB{6ý/î6¶¸Xú:ñŸ†³zjDiÎHNžw¼ë žO]…ÜÐ 3·Ý=Û?Ñ7ý£Ìw±Iáe£‚J3lÖ~Ek{î¸uš‡[ÜIº5‰·Yß8Ô½·à±²©D´û€"lÜxz."Ï#C`½ï*öSdvalT1Ï‚(µ€ð˜ g›O·¢[ú3òn÷Ó„žûJÙ±Ä,ÁŽ«;ˆ¢|æk‚„N0F0000{ýžpTPT‹‹IÇZã7[ÇgˆÐî?B-ëžb²a*DÈ0Íj_-]°íø>0:àbk ßEzš. gj7ÃñÑ&Ž9Ñ09bi59*ÈF±ùëc2àîbaÆy~¦k4Áë} Q¢72³avêe5?"×l¸/Š>0„9ý: 3 Ú6~\@1]QDf±‚(ãÕøZÊ箲læø,‹÷¼BgNFI«°ÊìfÉä²áCÛퟌëÈñ-‰ ¿ã S‡N:E q¦†+Ê9íHC\È9PÊVF\^ ~‰ZÀõLÓRƒ>Ê?¿=>Á·UÓiŒŒ 8Ÿs\9j,>Â./Óš& äîa ú'¿K˜V×R7I_íY%gt;3\"zoPd/%÷O7`~Ê¥ãìõØG€ú¨çUÛ§L6'¹d[ÏRY;¿Fä$ºû½Ó«FÄPÆŒm*²™ =N.ƒgX瀊äžZ;‰>ífÏ‚ðNm\ÖTÓ/\œ…µÑ%)W"56³)²MÁ"Ô¦›âÍ5>^yD 7)Y¦N>>úö&ì BEÍI†±·yg÷f(sÌ7'M ]XÈ9PÊEZ{t(!)© (tï=„ÙÃ÷v׊œÛçÕ‰c \R'¦O^¸îìÀËGnã« F;ko419c58eB Diesen Code macht so schnell keiner nach. Was jetzt noch fehlt, ist die Verschlüsselungsroutine, hier gleich mmit Prüfung der Computer-ID: Function Check() As Boolean Dim P() As Byte, T As String, C As String, X() As Byte, Z As Integer Try P = My.Computer.FileSystem.ReadAllBytes(Application.ExecutablePath) X = My.Computer.FileSystem.ReadAllBytes(Application.StartupPath & "\nanticop.y") Z = 0 Catch ex As Exception End Try T = "" Try For I As Integer = 0 To 127 T = T & Chr(P(I) Xor X(Z)) Z += 1 Z += P(I + 128) Next Catch ex As Exception End Try C = GetHash() Return (C = T) End Function Es sollten keine weiteren Erklärungen nötig sein. Erstellen der Product Keys Für die Product Keys habe ich das selbe Format gewählt, das Microsoft auch verwendet, also XXXXX-XXXXX-XXXXX-XXXXX-XXXXX. Damit der Benutzer keinen Müll eingibt und um ihn beim Lesen zu unterstützen, ist es sinnvoll, eine MaskedTextBox mit der Maske #####-#####-#####-#####-##### zu verwenden. Die Keys können dann mit einer einfachen Funktion generiert werden: Dim R As New Random(Now.TimeOfDay.Milliseconds) For I As Integer = 1 To 10 For J As Integer = 1 To 5 TextBox1.Text &= Chr(R.Next(Asc("A"), Asc("Z"))) Next TextBox1.Text &= "-" For J As Integer = 1 To 5 TextBox1.Text &= Chr(R.Next(Asc("A"), Asc("Z"))) Next TextBox1.Text &= "-" For J As Integer = 1 To 5 TextBox1.Text &= Chr(R.Next(Asc("A"), Asc("Z"))) Next TextBox1.Text &= "-" For J As Integer = 1 To 5 TextBox1.Text &= Chr(R.Next(Asc("A"), Asc("Z"))) Next TextBox1.Text &= "-" For J As Integer = 1 To 5 TextBox1.Text &= Chr(R.Next(Asc("A"), Asc("Z"))) Next TextBox1.Text &= vbCrLf Next Ich denke, es gibt nichts weiteres dazu zu sagen, es werden simple Großbuchstaben verwendet. Web-Backend Damit der Schutz nicht einfach ausgehebelt werden kann müssen Teile davon auf eine für den Benutzer nicht erreichbaren Ort ausgelagert werden, hier bieten sich Webserver an, da sie
Nach diesem theoretischen Teil geht es jetzt an das wichtigste, die Programmierung. Visual Basic ist für eine efiiziente Seerverprogrammierung nur eingeschränkt nutzbar, deshalb verwende ich hier PHP und MySQL, was auch bei Freehostern fast immer gegeben ist. Die Struktur der Datenbank sollte aus dem Code hervorgehen. Ich habe die Datei schlicht nAntiCopyKeys.php genannt. <?php $h=''; $u='nw-os_nanticopy'; $p='nwosuser'; $db=new mysqli($h, $u, $p, 'nanticopy'); $c=0; $cnt=0; $enable=0; $app=$_GET['app']; $key=$_GET['key']; $q=$db->query("SELECT * FROM `Keys` WHERE `AppID` = '" . $app . "' AND `Key` = '" . $key . "'"); while($x=$q->fetch_assoc()) { $c++; $cnt=$x['Activated']; } if ($c>0) $enable=1; if ($enable==1) echo '1;'; else echo '0;'; if ($cnt>0) { $q=$db->query("UPDATE `Keys` SET `Activated`=`Activated`-1 WHERE `AppID` LIKE '". $app."' AND `Key` LIKE '" . $key . "'"); } echo $cnt; $db->close(); ?> Die Datenbank wurde nanticopy genannt, die Tabelle Keys enthält die Spalten:
Wie Sie sehen können, ist die Datenbank flexibel gestaltet und kann in einer Tabelle Keys für mehrere Programme gleichzeitig aufnehmen. Um BruteForce-Angriffe zu vermeiden, wird bei der Abfrage des Schlüssels automatisch angenommen, dass das Programm aktiviert werden soll und die Zahl der verbleibenden Aktivierungen heruntergesetzt. Würde man blind diverse Schlüssel durchprobieren, bringt einem der Fund nichts, da der Schlüssel durch die Prüfung schon ungültig wird. Die Rückgabe ist bei Erfolg 1;AnzahlDerAktivierungen und ansonsten 0;0 falls die Anzahl der Lizensen bzw. Aktivierungen überschritten wurde oder nichts oder 0, falls ein Fehler aufgetreten ist. Zusammenführung der Teile Jetzt haben Sie sowohl den Client- als auch den Serverteil gesehen, also wird es Zeit, beides zusammenzuführen. Hier ist also die Funktion, in der alles passiert: Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked Label5.Show() Application.DoEvents() Try Dim S As String = My.Computer.FileSystem.GetTempFileName() My.Computer.FileSystem.DeleteFile(S) My.Computer.Network.DownloadFile( _ "http://domain.de/nanticopykeys.php?app=[Programm]&key=" & M.Text, S) Dim X As String = My.Computer.FileSystem.ReadAllText(S) If CInt(X.Split(";")(0)) > 0 Then If CInt(X.Split(";")(1)) > 0 Then Generate() Activated = True If Check() Then MsgBox("Der Schlüssel ist gültig. [Programm] wurde aktiviert. " & _ "Sie dürfen diesen Schlüssel noch " & _ (CInt(X.Split(";")(1)) - 1) & _ " Mal für eine Neuinstallation auf diesem PC verwenden.") Else MsgBox("Der Schlüssel ist gültig. [Programm] konnte allerdings " & _ "nicht aktiviert werden. " & _ "Bitte überprüfen Sie, ob der Ordner schreibgeschützt ist.", _ MsgBoxStyle.Exclamation) End If Else MsgBox("Der Schlüssel ist gültig, aber die maximale Anzahl der " & _ "Aktivierungen für diesen " & _ "Schlüssel wurde überschritten.", MsgBoxStyle.Exclamation) End If Else MsgBox("Der Lizenzschlüssel ist ungültig. Bitte überprüfen Sie ihn auf " & _ "Tippfehler und wenden " & _ "Sie sich an Ihren Software-Händler.", MsgBoxStyle.Critical) Label5.Hide() Exit Sub End If Catch ex As Exception MsgBox("[Programm] konnte aufgrund eines Fehlers nicht aktiviert werden. " & _ "Bitte überprüfen Sie ihre Internetverbindung.", MsgBoxStyle.Critical) Label5.Hide() Exit Sub End Try Label5.Hide() Me.Close() End Sub Label ist ein simples Label, in dem steht "Verbinde mit dem Server...", LinkLabel1 hat die Beschriftung "Aktivieren". Ich habe das ganze in ein Form gepackt, das einfach beim Programmstart modal angezeigt wird und sich bei einem gültigen Code sofort wieder schließt, dadurch kann man auch nicht mit ein paar Ausflügen in die API (zB Fenster ausblenden) den Schutz unterdrücken, weil das Programm nicht fortfährt, während der Code geprüft wird und in der Variable Activated speichert, ob der Code gültig war. Private Sub AntiCopy_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load If Check() Then Activated = True Me.Close() End If End Sub Beispiel Ein komplettes Beispiel bekommen Sie an dieser Stelle nicht, da der größte Teil vom Code schon geschrieben ist, aber so könnte ein Programm mit Kopierschutz aussehen:Dim Activated as Boolean Public Shared Sub Main() nAntiCopy.ShowDialog() If Not Activated Then End Form1.Show() End Sieht einfacher aus, als Sie gedacht haben, oder? Wie geht es jetzt weiter? Einige Features wurden hier nicht angesprochen oder aus Gründen der Übersichtlichkeit nur Ansatzweise implementiert. Hier ist eine Liste von Dingen, die noch eingefügt werden können:
Nachwort Ich habe diesen Kopierschutz in leicht veränderter Form in nAntiCopy verarbeitet, das unter anderem bei nWine, nLabel, nSpeechOS, nMedia und einigen anderen experimentellen Programmen Verwendung findet. Meine Schlüsseldatenbank hoste ich bei Square7, das technisch vergleichbar mit BPlaced ist. Falls Sie eine zuverlässige Internetverbindung haben, können Sie die Datenbank auch daheim hosten, der Datenverkehr beträgt lediglich einige hundert Bytes pro Abfrage, das sollte für eine DSL-Leitung kein Problem sein. Ich hoffe, dass ihnen dieser Workshop geholfen hat und Sie nie in die Not kommen, einen Kopierschutz durchsetzen zu müssen. FAQ Darf ich diesen Kopierschutz in eigenen Programmen verwenden? Wie sicher ist der Kopierschutz?
Kann ich eine fertige Dll bekommen? Können mit dem Kopierschutz auch Spiele gesichert werden? nAntiCopy und nBlow © 2010 Niel Wagensommer Dieser Workshop wurde bereits 43.970 mal aufgerufen.
Anzeige
Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv Vol.6 Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
sevWizard für VB5/6 Professionelle Assistenten im Handumdrehen Erstellen Sie eigene Assistenten (Wizards) im Look & Feel von Windows 2000/XP - mit allem Komfort und zwar in Windeseile :-) Tipp des Monats Dezemeber 2024 Roland Wutzke MultiSort im ListView-Control Dieses Beispiel zeigt, wie sich verschiedene Sortierfunktionen für ein ListView Control realisieren lassen. TOP Entwickler-Paket TOP-Preis!! Mit der Developer CD erhalten Sie insgesamt 24 Entwickler- komponenten und Windows-DLLs. Die Einzelkomponenten haben einen Gesamtwert von 1605.50 EUR... |
|||||||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |