Ein sicheres Lizenzsystem in AutoIt

  • Dieses Tutorial erklärt wie man mittels AutoIt und php ein sicheres Lizenzsystem erstellt das bei richtiger Verwendung auch Decompilen standhält.
    Anforderungen

    Schwierigkeitgrad: Fortgeschrittener/Profi
    Kenntnisse: AutoIt, php, sql

    Vorwort

    Unweigerlich taucht beim Programmieren mit AutoIt immer wieder die Frage auf, wie schütze ich mein Script vor den Augen Fremder. Es gibt verschiedene Gründe warum man dem entgegenwirken möchte. Der wichtigste ist wohl, dass man beim Anbieten kommerzieller Scripts nicht plötzlich auf einschlägigen, professionellen Hacker Foren wie z.B. ElitePvPers eine gecrackte Version seiner Arbeit finden möchte. Achtung Ironie.

    Doch wie schütze ich mein AutoIt Script denn nun so, dass niemand es einsehen oder verändern kann?
    Die Antwort - Garnicht.
    Wir können es unserem Gegenüber lediglich erschweren Zugriff auf unseren Code zu erhalten (mittels Packer/Crypter) oder diesen mittels Obfuscating unleserlich machen.
    Früher oder später wird irgendjemand aber mit großer Wahrscheinlichkeit Zugriff auf unseren Code erhalten. Und auch unleserlicher Code lässt sich bearbeiten oder gar zu einer leserlichen Form rückführen.
    Spätestens dann kann unser Login-System (z.B. mittels php+sql Datenbank) leicht ausgehebelt werden.

    Ich kann mit AutoIt also garkeine sicheren Scripte erstellen?
    Nur mittels AutoIt - Nein. Dafür ist AutoIt einfach nicht konzipiert.
    Doch es gibt einen Weg, den ich bisher in dieser Form noch in keinem mir bekannten AutoIt Script/Bot so vorgefunden habe. Zugegeben, auch dieser kommt nicht ganz ohne Probleme (auf die ich später eingehe) und bietet nur bei geschicktem Einsetzen einen guten Schutz. Dennoch halte ich ihn für weitaus sicherer wie das Packen/Crypten/Obfuscaten seines Codes.

    Auslagern wichtiger Programmlogik auf einen Server


    Durch das auslagern wichtiger Programmlogik auf einen Server, ohne die unser Script nicht funktioniert, erhalten wir ein System welches sicherstellt das unser Script nur mit gültiger Lizenz ausgeführt werden kann.
    Der Endbenutzer wird immer die Möglichkeit haben an unserem Script lokal zu werkeln um es nach seinen Wünschen zu verändern. Doch auf unseren Server hat er keinen Zugriff.
    Damit dieses System funktioniert und effizient ist, müssen wir allerdings einige Aspekte beachten.

    Das gilt es zu beachten.
    Es müssen essentielle Funktionen ausgelagert werden, ohne die unser Script nicht funktioniert.
    Es müssen nicht triviale Funktionen sein, damit diese nicht einfach rekonstruiert werden können.
    Die Funktionen dürfen keine statischen Antworten liefern, da diese mitgeschnitten und somit einfach ersetzt werden können.
    Die Anfrage an den Server dauert u.U. länger als die lokale Bearbeitung und sollte deshalb nicht an perfomance-relevanten Stellen eingebaut werden.
    Das Datenvolumen der übertragenen Daten sollte möglichst klein gehalten werden.

    Beachten wir diese Faktoren, machen wir es dem bösen Cracker sehr schwierig. Ohne gültige Lizenz wird es nur möglich unser Script zu verwenden, wenn wir die Funktionen auf dem Server lokal rekonstruieren. Den Aufwand dafür gilt es, wie eben gesagt, möglichst hoch zu gestalten.

    Welche Probleme gibt es bei diesem System?
    Ist unser Server nicht erreichbar funktioniert auch unser Script nicht.
    So haben z.B. viele Video Spiele mit Online Zwang dieses Problem. Die Nutzer sind nicht erfreut wenn ein DDoS Angriff auf die Login/Lizenz Server das ganze Spiel lahm legt. Das gleiche gilt für unser AutoIt Script.

    Genug geredet, ihr wollt ein Beispiel sehen?

    Beispiel


    In diesem Beispiel zeige ich euch ein vollwertiges, jedoch sehr einfaches, php Lizenzsystem in Verbindung mit dem oben genannten Prinzip des Auslagerns wichtiger Funktionen.
    Ich gehe dabei nicht auf die Funktionsweise einzelner Befehle ein und erkläre das ganze nicht à la ELI5. Ein Grundwissen sollte vorhanden sein.

    Dieses Beispiel ist, wie es der Name schon sagt, nur ein Beispiel und dient auch nur als solches. Das dargestellte AutoIt Script ist sehr einfach und kurz. Im Umkehrschluss bedeutet das, die Rekonstruktion der auslagerten Funktion kann nicht sehr aufwändig sein. Das ganze sollte zur Erklärung des Prinzips dennoch ausreichend sein.

    Wir werden nun ein kleines Script schreiben, welches sich auf codebot.de einloggt und das mit unserem Lizenzsystem verbinden.

    Licence.php
    Spoiler anzeigen

    PHP-Quellcode

    1. <?php
    2. define('SQL_HOST', 'localhost');
    3. define('SQL_PORT', '3306');
    4. define('SQL_DATABASE', 'phplicence');
    5. define('SQL_USER', 'phplicenceuser');
    6. define('SQL_PASSWORD', 'password');
    7. //Verbindet uns zur MySQL Datenbank und erstellt das PDO Objekt
    8. $PDO = connectMySQL();
    9. //Liest die Post Inputs aus und filtert sie
    10. $username = filter_input ( INPUT_POST, 'username', FILTER_SANITIZE_STRING );
    11. $password = filter_input ( INPUT_POST, 'password', FILTER_SANITIZE_STRING );
    12. $action = filter_input ( INPUT_POST, 'action', FILTER_SANITIZE_STRING );
    13. $data = filter_input ( INPUT_POST, 'data', FILTER_SANITIZE_SPECIAL_CHARS );
    14. //In diesem Beispiel haben wir kein Session System sondern prüfen den Login bei jeder Anfrage erneut
    15. if (checkLogin()){
    16. //Falls die Benutzerdaten korrekt waren und die Lizenz okay schauen wir welche action denn angefordert wurde
    17. //In dem Beispiel haben wir nur eine mögliche Action
    18. switch ($action){
    19. //Die getT wertet den erhaltenen Quelltext aus, liest den timestamp aus und echo'd ihn
    20. case 'getT':
    21. //Durch FILTER_SANITIZE_SPECIAL_CHARS wurden mögliche gefährliche Zeichen (XSS) gefiltert.
    22. //Das get_string_between ersetzt hier auf dem Server nun das eigentliche lokale StringBetween von AutoIt
    23. $temp = get_string_between($data, 'input type="hidden" name="t" value="', '"');
    24. echo $temp;
    25. break;
    26. }
    27. }
    28. /*
    29. * Source http://www.justin-cook.com/wp/2006/03/31/php-parse-a-string-between-two-strings/
    30. */
    31. function get_string_between($string, $start, $end){
    32. $string = " ".$string;
    33. $ini = strpos($string,$start);
    34. if ($ini == 0) return "";
    35. $ini += strlen($start);
    36. $len = strpos($string,$end,$ini) - $ini;
    37. return substr($string,$ini,$len);
    38. }
    39. function connectMySQL(){
    40. $driverOptions = array(
    41. \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"
    42. );
    43. return new \PDO('mysql:host='.SQL_HOST.';port='.SQL_PORT.';dbname='.SQL_DATABASE, SQL_USER, SQL_PASSWORD, $driverOptions);
    44. }
    45. function checkLogin(){
    46. global $PDO, $username, $password;
    47. $sql = "SELECT *
    48. FROM user
    49. WHERE username = ?";
    50. $statement =$PDO->prepare($sql);
    51. $statement->execute(array($username));
    52. $result = $statement->fetch(\PDO::FETCH_ASSOC);
    53. if (verifyPassword($password, $result['password'])){
    54. if ($result['isLicenced'] != 0){
    55. return true;
    56. } else {
    57. echo 'Not Licenced';
    58. return false;
    59. }
    60. } else {
    61. echo 'Login incorrect';
    62. return false;
    63. }
    64. }
    65. function verifyPassword($password, $hashedPassword){
    66. if (crypt($password, $hashedPassword) == $hashedPassword){
    67. return true;
    68. } return false;
    69. }


    Die Licence php verbindet sich mit unserer MySQL Datenbank und überprüft bei jeder Anfrage den Usernamen und das Passwort.
    Stimmen diese überein führt sie die angeforderte Action aus.

    In unserem Fall haben wir eine Action, nämlich getT (getTimestamp). Wir senden später in AutoIt den Quellcode der LoginSeite an unser php Script.
    Das php Script sucht in dem Quellcode nach dem Timestamp und gibt diesen per Echo aus. AutoIt liest den Timestamp hier wiederum aus und arbeitet mit diesem weiter.
    Sollten die Logindaten des Lizenzsystems allerdings falsch sein oder es ist keine gültige Lizenz vorhanden, wird ein Fehler ausgegeben.

    Hier nun das zugehörige AutoIt Script.

    LicenceTest.au3
    Spoiler anzeigen

    AutoIt Quelltext

    1. #include <WinHTTP.au3>
    2. $sLicenceUsername = InputBox("Licence System Login Data", "Please enter your Licence System Username")
    3. $sLicencePassword = InputBox("Licence System Login Data", "Please enter your Licence System Password", "", "*")
    4. $sCodeBotUsername = InputBox("Codebot.de Login Data", "Please enter your Codebot.de Username")
    5. $sCodeBotPassword = InputBox("Codebot.de Login Data", "Please enter your Codebot.de Password", "", "*")
    6. ;Create WinHTTP Connection to Licence Server
    7. $hLicenceSession = _WinHttpOpen()
    8. $hLicenceConnect = _WinHttpConnect($hLicenceSession, "127.0.0.1")
    9. ;Create WinHTTP Connection to CodeBot.de
    10. $hCodebotSession = _WinHttpOpen()
    11. $hCodebotConnect = _WinHttpConnect($hCodebotSession, "www.codebot.de")
    12. ;Requests the LoginPage of CodeBot.de
    13. $sRequest = _WinHttpSimpleRequest($hCodebotConnect, "GET", "/index.php/Login")
    14. ;Sends the SourceCode of the requested LoginPage to our Licence Server using the getT Action
    15. $t = _WinHttpSimpleRequest($hLicenceConnect, "POST", "/php Lizenz System/licence.php", Default, _
    16. 'username=' & $sLicenceUsername & '&password=' & $sLicencePassword & '&action=getT&data=' & $sRequest)
    17. ;If $t does not tell u login incorrect or Not Licenced we got the correct Timestamp from the Licence Server and are ready to login.
    18. If ($t = 'Login incorrect' Or $t = 'Not Licenced') Then
    19. MsgBox(0, "Error", $t)
    20. Else
    21. $sCodebotBody = _WinHttpSimpleRequest($hCodebotConnect, "POST", "/index.php/Login/", Default, _
    22. 'username=' & $sCodeBotUsername & '&action=login' & '&password=' & $sCodeBotPassword & '&useCookies=1&submitButton=Anmelden&url=http%3A%2F%2Fwww.codebot.de%2F&t='&$t)
    23. If StringInStr($sCodebotBody, 'Sie wurden erfolgreich angemeldet.') > 0 Then
    24. MsgBox(0, "Success", "Login successfull")
    25. Else
    26. MsgBox(0, "Error", "Login failed")
    27. EndIf


    Alle Anfragen werden per WinHttp durchgeführt.
    Wir erstellen eine WinHttp Verbindung zum Lizenzserver (dieser läuft zu Testzwecken lokal auf 127.0.0.1).
    Danach erstellen wir die eigentliche Verbindung zu Codebot.de, fragen dort nach dem Quellcode der Login Seite.
    Diesen schicken wir nun samt Lizenzusername und Lizenzpasswort an die licence.php per Post.
    Dort wird, wie eben schon erklärt, der Timestamp aus dem Quellcode ausgelesen und ausgegeben oder alternativ ein Fehler ausgegeben bei falschen Logindaten oder fehlender Lizenz.
    AutoIt überprüft nun, ob wir einen Fehler erhalten haben, falls nicht wird angenommen wir haben den korrekten Timestamp erhalten und loggen uns bei Codebot.de ein.

    Und das war eigentlich schon alles.

    Das wichtigste ist es, die richtigen Funktionen und Algorithmen auf den Server zu verlegen, sodass man diese lokal nicht einfach nachprogrammieren oder umgehen kann.
    Im Anhang findet ihr die beiden obigen Dateien sowie eine sql Datei zum Erstellen der zugehörigen Datenbank und eine admin.php mit der sich mittels get Parameter neue Benutzer hinzufügen lassen.

    Wichtig!
    Bitte beachtet, dass die admin.php mittels htaccess / htpasswd geschützt werden muss!
    Für den 'Live-Betrieb' dieses System muss außerdem noch ein Session System implementiert werden um sicherzustellen, damit ein Account nicht mehrfach gleichzeitig genutzt werden kann.

    Bei Fragen oder Anregungen einfach hier die Kommentarfunktion verwenden.

    mfg Wambo
    Dateien

    16.096 mal gelesen

Kommentare 5

  • Benutzer-Avatarbild

    Yothri -

    Leider ist daran garnichts sicher, das dekompilierst du, änderst nachher die if an der richtigen Stelle und dann hasts gecrackt. Nichts leichter als das.

    • Benutzer-Avatarbild

      Wambo -

      Scheinbar hast du den Artikel nicht verstanden. Logik muss ausgelagert werden. Cracken allein bringt dann nichts mehr, denn der fehlende Programmteil müsste nachprogrammiert werden. Ziel ist also nur den Aufwand zu vergrößern.

  • Benutzer-Avatarbild

    Wambo -

    Mir gerne auch. :)

  • Benutzer-Avatarbild

    SilverHazard -

    Fiddler kann die Pakete mitschneiden, aber die Logik liegt trotzdem für Fiddler unerreichbar auf dem Server. Wenn du dennoch der Meinung bist, das mit Fiddler cracken zu können, dann schreib mir gerne eine PN.

  • Benutzer-Avatarbild

    iCryptonic -

    Fiddler kanns cracken aber egal..