BigBasti's Blog About Me & my Digital Lifestyle

25Jan/124

ASP.NET MVC: HTML5 Elemente mit jQuery Fallback nutzen

Soo, nachdem ich die Überschrift mit all den hippen Begriffen vollgepackt habe die es in Sachen Web momentan so gibt möchte ich euch kurz erklären worum es in diesem Artikel gehen soll.

Ihr werdet sicher mitbekommen haben, dass HTML5 auf dem Vormarsch ist und auch wenn es immer noch nicht offiziell fertig ist findet man immer häufiger den HTML5-Header <!DOCTYPE html> auf diversen Seiten.

Eins der meiner Meinung nach nützlichsten Features die wir mit HTML5 erhalten sind die neuen Input-Typen. Denn bisher hatten wir keine Wahl und mussten type="text" benutzen!

Die Eingabefelder vom Typ Text konnten natürlich alles enthalten, sind aber nicht gerade Benutzerfreundlich wenn man etwas komplexere Daten eingeben soll wie zum Beispiel ein Datum.

In HTML5 wurden deswegen spezifische Typen für solche immer wieder einkehrende Eingaben eingeführt. Eine von ihnen ist &quot;Date&quot;:


Birthday: <input type="date" name="bday" />

Der große Vorteil hier ist, dass die Browser nun eine eigene Implementierung für diesen Typ von Eingabefeldern machen können. Falls der Browser nun also diesen neuen Eingabe Typ unterstützt blendet er automatisch einem (mehr oder weniger) schönen Date-Picker ein in dem man bequem das Datum wählen kann:

Ansicht des neuen Typen in verschiedenen Browsern

Ein weiterer großer Vorteil ist, dass auch die mobilen Browser wie z.B. auf dem iPhone diese neuen Elemente ebenfalls unterstützen und einen passenden Picker einblenden:

Date-Picker auf dem iPhone

Wie ihr in dem ersten Screenshot sehen könnt unterstützt der FireFox (zumindest zum Zeitpunkt des Screenshots) den neuen Typ nicht. In diesem Fall blendet er ein gewöhnliches Textfeld ein wo wir nun gezwungen sind das Datum auf die gewohnte (unbequeme) Weise einzutragen.

Übrigens, ich glaube ich muss euch nicht sagen warum der Internet Explorer hier nicht mit aufgeführt ist oder? ;-)

Und genau das ist das Problem um das es in diesem Blogpost geht. Wenn wir die tollen neuen Elemente nutzen gehen wir das Risiko ein, dass Nutzer die einen älteren Browser nutzen nicht in den Genuss einer bequemen Eingabe kommen.

jQuery Date-Picker

Wir könnten auch komplett auf das HTML5 Element verzichten und direkt alles mit jQuery machen, welches auch einen Date-Picker bietet, aber das ist auch nicht das gelbe vom Ei, denn dann wären die Mobilen Nutzer in Nachteil, da dort die Browser diese Elemente für gewöhnlich unterstützen und eine gewohnte Oberfläche für die Eingabe bieten.

Die Optimale Lösung ist offensichtlich eine Mischung beider Welten. Wenn der Benutzer die Seite mit einem kompatiblen Browser aufruft soll der Date-Picker des Browsers genutzt werden, wenn der Browser aber veraltet ist soll stattdessen der jQuery Fallback greifen und der JavaScript Date-Picker (siehe links) genutzt werden.

Zu unserem Glück macht uns ASP.NET MVC die Umsetzung dieses Plans sehr leicht, da es an den nötigen Stellen sehr einfach erweitert werden kann.

Schauen wir uns mal ein kleines Beispiel an. Wir haben eine Klasse Person, und wollen auch dessen Geburtstag speichern, hier wollen wir die tolle neue Funktionalität nutzen. Implementieren wir das Ganze jedoch erstmal wie gewohnt:


    public class Person
    {
        public int ID { get; set; }
        public String Name { get; set; }
        public DateTime Geburtstag { get; set; }
    }

Wenn wir die Model-Klasse haben können wir das MVC Scaffolding nutzen um für uns eine View zum Erstellen neuer Personen anzulegen:

MVC Scaffolding kommt uns zu Hilfe

Schauen wir uns nun doch mal an was da für uns tolles generiert wurde:


    <div class="editor-field">
        @Html.EditorFor(model => model.Geburtstag)
        @Html.ValidationMessageFor(model => model.Geburtstag)
    </div>

Auffällig hierbei ist, dass hier @Html.EditorFor genutzt wird und nicht etwa @Html.TextBoxFor! Der Hintergrund ist der, dass MVC bei der Generierung versuchen wird ein passendes Element für den angegebenen Datentyp (DateTime) zu bestimmen, aber da MVC standardmäßig nur den Typ Text kennt wird hier eigentlich immer ein Input-Element vom Typ text generiert.

Hier kommt uns die Erweiterbarkeit von MVC zu gute, denn wir können ganz einfach NuGet nutzen um uns die nötige Funktionalität zu verschaffen. Wir installieren das Packet MvcHtml5Templates.

Installation über NuGet

Neue Templates

Nachdem NuGet alles erledigt hat werdet ihr feststellen, dass ihr ein paar neue Dateien in eurem Views/Shared Verzeichnis habt (siehe Bild links). Und wie ihr schon an dem Namen erkennen könnt sind das die neuen Input-Typen aus HTML5.

Diese Templates machen im Grunde nichts anderes als die MVC-Eigenen zu überschreiben und versehen die mit dem passendem Type-Attribut.

Hier sind euch keine Grenzen gesetzt ihr könnt natürlich auch eire eigenen Templates definieren mit euren eigenen Typen. (Auch wenn man das eher selten benötigt)

Das Tolle: mehr müssen wir nicht machen. MVC wird nun zur Laufzeit statt einem Text ein Date Input-Element für uns anlegen. Beachtet, dass das nur geht wenn wir in der View die allgemeine Funktion @Html.EditorFor nutzen und keinen Spezifischen Typ angeben.

Schauen wir mal in den Sourcecode der zur Laufzeit für das Geburtstagsfeld generiert wird:


<input class="text-box single-line"
data-val="true"
data-val-required="Das Feld 'Geburtstag' ist erforderlich"
id="Geburtstag"
name="Geburtstag"
type="datetime"
value=""; />

Wie ihr seht wird nun der Korrekte Typ, nämlich datetime verwendet. Wenn wir die Seite nun also mit einem kompatiblen Browser aufrufen können wir ganz bequem das Datum wählen.

Leider ist der Opera Browser momentan wohl der einzige Desktop Browser der uns hier einen Benutzerfreundlichen Dialog einblendet (siehe erstes Bild oben), somit müssen wir dafür sorgen, dass die Benutzer mit anderen oder alten Browsern nicht benachteiligt werden.

JavaScript Magie

Auch für diese Problematik bringt MVC bereits alles mit was nötig ist sie zu lösen. Werfen wir doch mal einen Blick in unseren Scripts Ordner finden wir alle nötigen jQuery und jQuery UI Skripte, dazu kommt noch die modernizr Bibliothek die uns auch zu Gute kommen wird.

Die jQuery Bibliotheken liefern und die nötige Funktionalität die wir benötigen um diesen hübschen Date-Picker einzublenden.

Die modernizr Bibliothek dagegen hilft uns herauszufinden ob der Browser, den der Benutzer momentan verwendet die gewünschten HTML5 Features unterstützt.

Nun müssen wir also bei unseren Formularen prüfen, ob der Browser die nötigen Funktionen kennt und bei Bedarf die jQuery Klassen einbinden. Das Ganze ist dank der Einfachheit von Modernizr und jQuery ziemlich simpel.

Wechseln wir zu unserer View und fügen die Referenzen auf die nötigen Skripte und CSS Dateien ein:


<script src="@Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/modernizr-1.7.js")" type="text/javascript"></script>
<link href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />

Unten in der View fügen wir nun eine Modernizr Abfrage ein und prüfen, ob der Browser das DateTime-Feld unterstützt, und wenn nicht lassen wir jQuery das Ganze für uns regeln:


<script type="text/javascript">
    $(function () {
        if (!Modernizr.inputtypes.date) {
            $("input[type='datetime']").datepicker();
        }
    });
</script>

Mit dem Befehl $("input[type='datetime']").datepicker(); werden alle Input-Felder vom Typ DateTime durch den jQuery Picker ersetzt. Coole Sache!

Unser Browser kennt den Typ nicht :(

Unser Browser kennt den Typ nicht :(

Kleiner Hinweis am Rande: Das ist nicht wirklich best practice da die Skripte auch geladen werden wenn sie gar nicht benötigt werden (der Browser kennt das HTML5 Feld) ich habe das hier der Einfachheit geopfert.

Und das wars auch schon! Alle Browser die das Feld unterstützen blenden nun ihren Picker ein, ansonsten wird der jQuery Fallback genutzt.

Wir müssen uns auch nicht mit irgendwelchen UserAgent-Prüfungen herumschlagen und lassen das alles Modernizr erledigen, der das intern über JavaScript prüft und somit immer aktuell ist. Das heißt dass wenn irgendwann der IE plötzlich die neuen Typen kennt werden diese auch funktionieren!

Genauso könnt ihr auch bei all den anderen neuen HTML5 Typen vorgehen und euren Usern ein bestmögliches Bedienerlebnis bereiten ;-)

kick it on dotnet-kicks.de

5Aug/110

Java: SubjectDN eines X509Zertifikates zu OpenSSL kompatibel machen

Java stellt uns zum angenehmen Arbeiten mit X509-Zertifikaten die Klasse java.security.cert.X509Certificate zur Verfügung. Hier können wir uns sehr einfach über die methode .getSubjectDN().getName() den Distinguished Name des Zertifikats besorgen.

Wenn man in der Javawelt bleibt ist das auch alles ok und funktioniert Problemlos. Will man aber andere Programme wie zum Beispiel OpenSSL anbinden, bekommt man hier ein Problem, denn OpenSSL liefert einen anderen SubjectDN String als unsere Java Klasse.

Wobei mit anders meine ich, dass die Reihenfolge der ausgegebenen Parameter anders ist, hier ein Beispiel:

Ausgabe von OpenSSL (über die X509_NAME_oneline Methode):

/C=DE/ST=NRW/L=Bielefeld/O=ORG/OU=AB1/CN=130.122.146.121

Wogegen die Java-Klasse folgenden String liefert (.getSubjectDN().getName()) :

CN=130.122.146.121, OU=AB1, O=ORG, L=Bielefeld, ST=NRW, C=DE

Die Reihenfolge scheint genau umgekehrt zu sein und auch die Trenner sind anders, und wenn man den String nun als Auth-String benutzen will bekommt man ein Problem.

Leider bietet uns Java hier keine Möglichkeit den String anders zu sortieren, man kann zwar über die Methode getSubjectX500Principal.getName(String format) einen RFC als Parameter mitgeben, welcher die Sortierung etwas anpasst, aber teilweise noch komischere Ergebnisse liefert.

Hier bleibt einem nun leider nichts anderes übrig, als selbst einzugreifen und die Sortierung selbst vorzunehmen. Dazu habe ich eine kleine Klasse geschrieben die das für euch erledigt. Diese hat zwei Methoden, eine die einen OpenSSL Kompatiblen String ausgibt und eine bei der ihr die Reihenfolge der Parameter selbst bestimmen könnt:

 


/**
 * Teilt die Informationen aus dem X509Certificate.SubjectDN in die
 * einzelnen Bestandteile auf und macht diese einzeln verfügbar
 * @author sebastian gross blog.bigbasti.com
 */
public class CertificateDataSeperator {

    private String _C = "";
    private String _ST = "";
    private String _L = "";
    private String _O = "";
    private String _OU = "";
    private String _CN = "";
    private String _EMAILADRESS = "";

    /**
     * Erstellt eine neue instanz
     * @param cert Das Zwetifikat aus dem die Daten gelesen werden sollen
     * @param seperator Die Zeichenfolge ander die parameter
     *        getrennt werden sollen, bei Java ist Standard ", "
     */
    public CertificateDataSeperator(X509Certificate cert, String seperator){
        String [] subjectDNData;

        subjectDNData = cert.getSubjectDN().getName().split(seperator);

        seperateData(subjectDNData);
    }

    /**
     * Duchläuft das Array und ordnet die Informationen
     * @param data Array mit dem SubjectDN String
     */
    private void seperateData(String [] data){
        for(String s : data){
            if((s.toUpperCase()).startsWith("C=")){
                _C = s;
            }else if((s.toUpperCase()).startsWith("ST=")){
                _ST = s;
            }else if((s.toUpperCase()).startsWith("L=")){
                _L = s;
            }else if((s.toUpperCase()).startsWith("O=")){
                _O = s;
            }else if((s.toUpperCase()).startsWith("OU=")){
                _OU = s;
            }else if((s.toUpperCase()).startsWith("CN=")){
                _CN = s;
            }else if((s.toUpperCase()).startsWith("EMAILADRESS=")){
                _EMAILADRESS = s;
            }
        }
    }

    /**
     * Generiert einen angepassten SubjectDN String
     * @param params Die gewünschten Werte in der gewünschten Reihenfolge als Array
     * @param seperator Die Zeichenfolge, die zum Trennen der Parameter genutzt werden soll
     * @return Einen angepassten SubjectDN String
     */
    public String getNewDNString(String [] params, String seperator){
        StringBuilder sb = new StringBuilder();

        for(String s : params){
            if((s.toUpperCase()).equals("C")){
                sb.append(_C);
            }else if((s.toUpperCase()).equals("ST")){
                sb.append(_ST);
            }else if((s.toUpperCase()).equals("L")){
                sb.append(_L);
            }else if((s.toUpperCase()).equals("O")){
                sb.append(_O);
            }else if((s.toUpperCase()).equals("OU")){
                sb.append(_OU);
            }else if((s.toUpperCase()).equals("CN")){
                sb.append(_CN);
            }else if((s.toUpperCase()).equals("EMAILADRESS")){
                sb.append(_EMAILADRESS);
            }

            if(!s.equals(params[params.length-1])){
                sb.append(seperator);
            }
        }

        return sb.toString();
    }

    /**
     * Erzeugt einen DN String in dem Format, wie ihn auch die
     * X509_NAME_oneline Methode von OpenSSL generiert, dies ist
     * auch das Format, welches von dem Exim Email Server genutzt wird.
     * Das Forman ist wiefolgt: /C=$/ST=$/L=$/O=$/OU=$/CN=$
     * @return OpenSSL
     */
    public String getOpenSSLCompatibleDNString(){
        StringBuilder sb = new StringBuilder();

        sb.append("/").append(_C).append("/").append(_ST).append("/").append(_L).append("/")
          .append(_O).append("/").append(_OU).append("/").append(_CN);

        //EMAILADRESS Ist ein optionales Feld und könnte nicht gesetzt sein
        if(_EMAILADRESS != null){
            sb.append("/").append(_EMAILADRESS);
        }

        return sb.toString();
    }

    public String getC() {
        return _C;
    }

    public String getCN() {
        return _CN;
    }

    public String getEMAILADRESS() {
        return _EMAILADRESS;
    }

    public String getL() {
        return _L;
    }

    public String getO() {
        return _O;
    }

    public String getOU() {
        return _OU;
    }

    public String getST() {
        return _ST;
    }
}

Mit dieser kleinen Klasse ist es sehr einfach einen OpenSSL kompatiblen SubjectDN zu erhalten:


X509Certificate myCert = session.getClientCertificate();
CertificateDataSeperator sep = new CertificateDataSeperator(myCert, ", ");
String dn = sep.getOpenSSLCompatibleDNString();

Wenn man selbst die Reihenfolge der parameter bestimmen will kann man das z.B. so machen:


X509Certificate myCert = session.getClientCertificate();
String [] myParams = new String[]{"O", "CN", "L"};
CertificateDataSeperator sep = new CertificateDataSeperator(myCert, ", ");
String dn = sep.getNewDNString(myParams, "|");

Nun soll erst O, dann CN und zum Schluss L ausgegeben, jeweils von einem | (pipe) getrennt.

Das Ganze lässt sich natürlich je nach verwendeten optionalen SSL Parametern noch beliebig erweitern, und ist eine einfache und schnelle Methode um den SubjectDN neu zu sortieren.

5Jan/111

Fehler: Web Services testen unter NetBeans 6.9.1 (mit Glassfish 3)

Gestern habe ich ziemlich viel Zeit damit verbracht einen ziemlich nervigen Bug in NetBeans 9.6.1 zu umgehen, der auftritt, wenn man WebServices testen möchte.

Wenn ihr einen eigenen WebService anlegt wie zum beispiel in diesem NetBeans Tutorial beschrieben und diesen anschließend mit den Glassfish-eigenen Testern testen wollt werdet ihr diesen Fehler hier sehen:

Service Testen schlägt fehl

Service Testen schlägt fehl

Wie es sich nun herausstellte machen wir als User keinen Fehler, sondern NetBeans, denn NetBeans generiert für uns eine Falsche URL, die er dann dementsprechend nicht aufrufen kann und uns diesen Fehler anzeigt.

Interessant an dieser Stelle ist auch, dass dieser Fehler nur in Verbindung mit Stateless WebServices auftritt. Denn wenn man die @Stateless Annotation aus dem Code entfernt scheint es doch zu gehen.

Da man aber im Normalfall alle Services stateless sind, müssen wir uns die passende URL selber basteln. Die korrekte URL ist nämlich so aufgebaut:

http://localhost:8080/[ServiceName]/[ServiceKlasse]?Tester
in meinem obigen Fall wäre es dann

http://localhost:8080/myServiceService/myService?Tester

Die korrekte URL findet ihr übrigens auch auf der Glassfish Konsole im Bereich Anwendungen->[Anwendung]->[Euer WebService]->Endpunkt Anzeigen - hier stehen alle wichtigen URLs (WSDL, Tester, Service)

Das ist natürlich etwas blöd, da diese Praktische Funktion von NetBeans die sehr einfach mit nur einem Rechtsklick erreichbar ist nicht funktioniert, aber gut was solls, schreiben wir die URLs halt selbst ;)

Dieses Problem tritt bei der 7.0 Beta von NetBeans übrigens nicht mehr auf.

7Dez/104

C#: Threads mit Parametern Starten

Wenn ihr auch mal mit Threads gearbeitet habt habt ihr sicherlich auch schon festgestellt, dass es zu Problemen kommt, wenn man einen Thread starten möchte und diesem auch noch Parameter unterjubeln will.

Ein normaler(einfacher) Threadstart sieht ja folgendermaßen aus:


public class test {
    public test() {
        Auto a = new Auto();

        Thread t = new Thread(new ThreadStart(a.Fahre));
    }
}

public class Auto {
    public void Fahre(){
        //...
    }
}

Aber was ist wenn wir nun dem Auto auch sagen sollen wie weit es fahren soll? Also so:


public class test {
    public test() {
        Auto a = new Auto();

        Thread t = new Thread(new ThreadStart(a.Fahre(100)));
    }
}

public class Auto {
    public void Fahre(){
        //...
    }

    public void Fahre(int wieWeit) {
        //...
    }
}

Leider geht das nicht so einfach, da ThreadStart einen Methodennamen erwartet. Hier müssen wir also anders ansetzen. Eine Möglichkeit dieses Problem zu lösen bzw. zu umgehen ist es die Klasse Auto etwas zu modifizieren und die Parameter, die wir eigentlich über den Methodenaufruf übergeben wollten über den Konstruktor zu übergeben (oder über Properties zu setzen). Somit wäre die Fahre Methode wieder frei von Parametern und könnte problemlos über ThreadStart aufgerufen werden:


public class test {
    public test() {
        Auto a = new Auto(100);

        Thread t = new Thread(new ThreadStart(a.Fahre));
    }
}

public class Auto {
    private int wieWeit;

    public Auto(int wieWeit) {
        this.wieWeit = wieWeit;
    }

    public void Fahre(){
        //... hier kann man mit dem Wert
        // von wieWeit arbeiten
    }
}

Aber diese "Lösung" ist natürlich auch nicht das Gelbe vom Ei. Deswegen habe ich noch ein wenig gegoogelt und habe eine sehr schöne und zugleich einfache Lösung entdeckt:


    public class test {
        public test() {
            Auto a = new Auto();

            ThreadStart start = delegate { a.Fahre(100); };
            Thread t = new Thread(new ThreadStart(start));
        }
    }

    public class Auto {

        public void Fahre(int wieWeit) {
            //...
        }
    }

Hier machen wir von den Anonymen Methoden Gebrauch (siehe Zeile 5) und packen die in ein Delegate, das wir dann dem ThreadStart übergeben. Hier können wir auch bequem unseren Parameter mit angeben und müssen somit auch nicht an der Klasse selbst Änderungen vornehmen.

Kleiner Nachtrag noch:
Maximilian hat mich grad noch an das ParameterizedThreadStart Delegate aufmerksam gemacht, das habe ich noch unbewusst ausgelassen :) . Dieses bietet ebenfalls eine angenehme Möglichkeit Parameter an Threads zu übergeben, hier auch dazu ein kleines Beispiel:


public class test {
    public test() {
        Auto a = new Auto();

        Thread t = new Thread(new ParameterizedThreadStart(a.Fahre));
        t.Start(100);
    }
}

public class Auto {

    public  void Fahre(object wieWeit) {
        //...
    }
}

Man beachte hierbei, dass der Typ des Parameters nun Object ist (Zeile 12) deswegen muss vor der Verwendung noch ein Cast stattfinden. Außerdem könnte man Probleme bekommen, wenn man Überladungen benutzen will.

Das ganze ist natürlich nichts weltbewegendes, aber da ich es noch nicht kannte habe ich es hier mal mit aufgenommen.
kick it on dotnet-kicks.de

11Aug/093

Codeklau & wie man eigenen Code schützen kann Teil 1

In dieser Reihe möchte ich darüber schreiben welche Probleme die Arbeit mit modernen Programmiersprachen mit sich bringt und wie man diese möglichst eindämmen und gering halten kann.

In dem ersten Teil werde ich darauf eingehen, wie und warum es möglich ist Code aus fertigen Applikationen zu extrahieren.

Das größte Problem, das jeder Closed-Source Programmierer hat, ist es den erstellten Code nicht für andere einsichtbar zu halten damit dieser nicht geklaut oder ohne Einwilligung oder Lizenzzahlungen weiterverwendet werden kann!

Aber wie ist es überhaupt möglich Code zu klauen wenn mann nur die fertige Applikation hat?

Zuerst sollte man sagen, dass es keinen 100%igen Schutz gibt! Alles kann geknackt oder modifiziert werden. Alle Firmen, die das gegenteil versprechen sind einfach nur unprofessionell. Denn alle Schutzmechanismen die es gibt sorgen lediglich dafür, dass man mehr Aufwand aufbringen muss, um diese wieder zu umgehen.

Früher war Codeklau noch sehr harte Arbeit, denn früher waren alle Anwendungen kompiliert, wurden also beim Erstellen direkt in Maschinencode gewandelt! Diesen Maschinencode wieder in lesbaren Quelltext zu wandeln ist sogut wie unmöglich, was man aber machen kann ist es diesen zu "Deassimblieren" (engl. Disassamble). Bei diesem Vorgang wird der vorliegende Native Code (Maschinencode) in ein für den Menschen lesbaren Assembler Code umgewandelt.

Was man hier noch wissen sollte, ist dass früher (vor langer langer Zeit) alles in Assembler programmiert wurde. Assembler ist eine Sprache, die es dem Programmierer Erleichtert Code zu schreiben, dabei werden Befehle benutzt die der Prozessor, auf dem später der Code ausgeführt werden soll versteht. Somit muss man sich nicht mit Nullen und Einsen herumschlagen sondern hat was, was man auch einigermaßen lesen kann.

5623_2Grafik 1: So könnte ein Programm nach dem Disassamble-Vorgang aussehen

Hier findet ihr ein kleines Beispiel wie sich Assembler von einer Hochsprache wie zb. C++ unterscheidet!

Mit diesem erzeugten Assembler Code kann man nun weiter "arbeiten" und versuchen den Ablauf des Programms zu verstehen und diesen dann auch eventuell zu kopieren, zu klauen! Das ist natürlich je nach Größe extrem aufwendig und langwierig.

Übrigens: genauso gehen die so genannten "Cracker" vor wenn sie versuchen bestimmte Sicherheitmechanismen von Programmen oder Spielen zu deaktivieren. Sie suchen nach diesen Ereignissen in dem Assembler Code und versuchen diese umzuleiten oder zu löschen, sodass die "Gecrackte" Software dann anschließend zb. ohne gültige Lizenz oder ein Spiel ohne die Original CD im Laufwerk benutzt werden kann! Wer darüber mehr wissen will sollte einen Blick in die "Hacker-Bibel von Cyberdemon98" werfen.

Natürlich kann man mit diesem Vorgehen nicht wirklich Code "klauen" sondern mehr versuchen zu verstehen wie ein Programm arbeitet um dann zb. andere Programme darauf abzustimmen ("Schnittstellen" schafften). Diesen Vorgang nennt man dann reverse Engeneering (deut. Umgekehrtes entwickeln).

Ein berühmtes Beispiel dafür ist der Instant Messaging Dienst ICQ, dieses Unternehmen hat keinerlei Spezifikationen über den Dienst oder das Protokoll veröffentlicht. Alle ICQ-Clients wie QIP, Miranda oder andere basieren komplett auf Reverse Engeneering! Deswegen kommt es auch oft, dass man sich gegenseitig keine Dateien schicken kann oder die Status-Nachricht eines Freundes lesen kann weil er einen anderen Client verwendet. Dies liegt einfach daran dass die Entwickler "raten" müssen wie diese Funktionen funktionieren und Kompabilitäten nur schwer geschaffen werden können! Dadurch geht ICQ sicher, dass nur ihr eigener Client perfekt funktioniert und alle Features beherrscht!

c-flow

Grafik 2: Diese Schritte durchläuft C++ Code während der Compilierung

Diese Codevariante, die so genannten unmanaged-code hervorbringt, der aus Maschinencode besteht erstellen die "alten" Programmiersprachen wie Delphi, C, VB6 und C++. Die Obere Grafik zeigt, dass nach der Kompilierung des Quelltextes, dieser noch weitere Schritte durchläuft und schließlich als Binäre Datei vorliegt, die nur auf einem bestimmten CPU-Typ und Betriebssystem läuft!

Die neueren Programmiersprachen wie etwa Microsofts .NET (Worunter auch C#, VB.NET fällt) oder Java verfolgen einen komplett anderen Ansatz der managed code erzeugt und förmlich zum Codeklauen einlädt!

20011114_1xGrafik 3: Compilierung von Managedcode Programmen (.NET & Java)

Die Sprachen, die managed Code erzeugen, erzeugen nämlich keinen Maschinencode sondern so genannte Assemblys welche eine Art Vorkompilierte Programme sind die nicht lauffähig sind.

Grafik 3 beschreibt im Oberen Teil, den Kompilierungs Prozess, der ziemlich einfach gestrickt ist. Der Code wird garnicht "Richtig" kompiliert sondern nur für die spätere Ausführung vorbereitet.

Warum ist das so? Nun heutzutage müssen Programme laufen, und nicht nur auf dem PC auf dem Sie geschrieben wurden sondern auch auf anderen und sogar auf anderen Betriebssystemen. Das ganze nennt sich dann Plattformunabhängigkeit!

Java Programm zb. können auf allen gängigen Betriebssystemen ausgeführt werden. Egal ob Windows, Solaris, Mac OS oder Linux Java Programme funktionieren! Und damit das möglich ist dürfen die Programme nicht kompiliert werden!

Denn wenn ein Programm kompiliert wird wird es in Maschinencode umgewandelt. Und da jede Prozessorarchitektur einen eigenen Maschinencode hat und jedes Betriebssystem auch anders aufgebaut ist kann ein kompiliertes Programm immer nur auf dem System ausgeführt werden für das es kompiliert wurde!

Um dieses Problem zu umgehen werden Java Programme nur Vorkompiliert (zu so genannten Assemblys) und dann wenn die gestartet werden (egal auf welchem Betriebssystem) werden sie erst "richtig" kompiliert, für das System auf dem sie gerade gestartet werden!

Warum ist das gut? Naja, so kann man ein Programm schreiben, und es ohne daran viel zu machen auf allen Systemen benutzen. Leider hat das System auch viele Schattenseiten, denn um ein solches vorkompiliertes Programm ausführen zu können muss eine Virtuelle Maschine installiert sein, die unser vorkompiliertes Programm "zu ende kompiliert" im Falle von Java ist es die JVM (Java Virtual Machine) diese kompiliert das Programm passend zum Betriebssystem und sorgt für dessen korrekte Ausführung.

Desweiteren sind diese Programme natürlich auch langsamer als die Nativen, denn zb. die Java Programme müssen vor deren Start erst kompiliert werden und laufen in einer Virtuellen Maschine, was natürlich auch Geschwindigkeitseinbußen. (vergleichbar mit einem Virtuell ausgeführten Betriebssystem durch VMWare und co)

Aber nun schweife ich schon wieder ab! Was wichtig ist, ist dass die Managedcode Programme nicht in Maschinencode kompiliert werden. Der Zustand in dem sie dann verweilen macht es uns sehr leicht das Programm wieder zurück in Quelltext zu verwandeln und diesen dann zu Klauen!

Dieser Vorgang, bei dem eine Kompilierte Datei wieder in lesbaren Quelltext verwandelt wird nennt man Dekompilierung. Anders als beim Disassambling wird hierbei der Original Quelltext den der Programmierer geschrieben hat fast perfekt wiederhergestellt!

Davon sind alle managedcode Sprachen betroffen, da sie alle nach dem Prinzip aus Bild 3 arbeiten! (zb. Java, C#, VB.NET)

Für jede Sprache gibt es auch den passenden Decompiler, der den Original Quellentext in Sekunden herausspuckt! Viele dieser Decompiler sind hochkomplexe Programme und deswegen auch nicht kostenlos! Besonders wenns an das dekompilieren von Nativen Programmen geht wird man keine kostenlosen Programme finden die brauchbare Ergebnisse liefern!

Um Java Programme (.jar-Dateien) zu dekompilieren empfehle ich den JD Java Compiler, dieser ist kostenlos und arbeitet sehr zuverlässig!

screenshot1Bild 4: Der Java Decompiler in Action

Natürlich muss man auf so etwas wie Kommentare und Ordnungen verzichten, da diese bei dem Kompilierungs Prozess automatisch aus dem Quelltext gelöscht werden, da der Prozessor damit nix anfangen kann!

Um .NET Programme oder DLLs zu dekompilieren, wobei hier disassimbliren besser passt kann ich das Tool .NET Reflector von Redgate empfehlen, es ist einfach zu benutzen und funktioniert perfekt!

Bild 5: Arbeiten mit dem .NET Reflector

Das Gute hierdran ist, dass man sogar in die .NET System Prozesse schauen kann um diese besser zu verstehen! Dieses Programm ist ebenfalls kostenlos nach einer Registrierung zu haben!

Wer das ganze mal ausprobieren will kann das gerne ja mal machen. Sucht euch einfach mal ein einfaches Java Programm, dabei ist es egal ob es ein Desktop Java Programm ist ober ein Mobile Programm aus dem J2ME. zb. den Opera Mini und schaut euch mal dessen Innereien an.

Wenn ihr mal ein .NET Programm dekompilieren wollt kann ich für den Einstieg eins der Programme empfehlen, die ich hier im Blog veröffentlicht habe. (Schaut zb. in dem Letzten Beitrag. Ladet die Beispiel Datei herunter und entpackt den Ordner und geht in den Ordner TreeViewDemo\bin\debug\ dort müsstet ihr eine .exe Datei finden an der ihr euch austoben könnt!)

Als Ergänzung will ich noch sagen, dass ein Programm immer in managedcode UND in unmanagedcode kompiliert werden kann und somit manchmal nicht (so einfach) dekompiliert werden kann!

Wie man seinen Code schützen kann werde ich dann in dem zweiten Teil behandeln, da der hier ja schon ein bissl zuu lang geworden ist!

Interessiert dich dieses Thema? Möchtest du hier mehr Beiträge darüber lesen? Schreib ein Kommentar was dir gefallen hat oder was nicht.

21Apr/092

YouTube Ländersperre umgehen

bild-2Seit einiger Zeit hat YouTube auch Filme und Serien in sein Sortiment aufgenonnen, die kostenlos angeschaut werden können. Diese werden mit kurzen Werbeeinblendungen finanziert.

Dieser Dienst ist auch für Deutsche Besucher freigeschaltet allerdings können nicht alle Inhalte wiedergegeben werden. Versucht man zum Beispiel die Serie "Alf" zu öffnen, wird eine Fehlermeldung eingeblendet "This video is not available in your country."

bild-3Wie ich eben durch herumexperementieren herausgefunden habe, ist diese Sperre aber sehr leicht zu umgehen. Dazu benötigt man lediglich ein Kleines Tool, dass euch zu einem VPN in den USA verbindet. Zu empfehlen ist das Tool Hotspot Shield. Dieses Programm gibts es sowohl für Windows als auch für Mac, dazu ist es auch noch sehr leicht zu bedienen!

Ist es einmal gestartet genückt ein klick um sich mit dem Amerikanischen Netzwerk zu verbinden. Nun müssen wir nurnoch die gewünschte Episode aufrufen.

STOPP: Wie ihr sicher feststellen werdet arbeitet das System sehr langsam, weswegen sich dieser Dienst nicht zur Wiedergabe von solchen Inhalten anbietet.

Aber die YouTube Programmierer haben uns eine tolle Hilfe eingebaut, wennauch unfreiwillig, es wird nämlich das Land geprüft aus dem die Verbindung aufgebaut wird, aber nur einmal, und nur beim öffnen der Seite mit dem Stream!

Da heißt, ist die Seite einmal offen und man sieht den Flashplayer auf dem das video laufen soll muss man die VPN Verbindung beenden. Nun puffert Youtube das Video ganz normal über eure eigene schnelle Leitung und man kann das Video Ruckelfrei genießen!

bild-4Übrigens: das System funktioniert auch bei dem beliebten Dienst hulu.com, welches ebenfalls nur für Bürger der USA freigeschaltet ist!

Viel Spaß beim ausprobieren!

   
Get Adobe Flash playerPlugin by wpburn.com wordpress themes