Selbstmodifizierende Prorgamme



  • @0x0ERROR
    Bei compilierten Sprachen hast du immer das Problem, dass der Source-Code nicht mehr vorliegt, und auch der Compiler nicht greifbar ist. Und selbst wenn du beides hast, kannst du nicht einfach so den laufenden Prozess ändern.

    Bei interpretierten Sprachen hast du normalerweise das Problem dass die Sprache kein Werkzeug zur Verfügung stellt aus dem Programm heraus das laufende Programm zu ändern -- auch wenn es theoretisch relativ einfach wäre.

    Selbstmodifizierende Programme werden normalerweise - zumindest teilweise - in Assembler geschrieben. Bzw. manchmal die Stücke die "eingefügt" bzw. geändert werden direkt 1:1 in Maschinensprache.
    In C bzw. C++ kann man z.T. Inline-Assembler verwenden.

    Wenn du darüber aber so wenig weisst, dass du hier fragen musst wie schwer es ist, dann würde ich sagen: ziemlich schwer. Guck dir mal x86 Assembler an und wie der in Maschinensprache übersetzt wird. Dann solltest du eine bessere Vorstellung davon bekommen wie schwer oder einfach es ist.



  • @knivil
    Wenn man die nötigen Grundlagen hat, und sich ausreichend mit einem Thema auskennt, dann ist fast nichts besonders schwer.
    Selbstmodifizierende Programme zu schreiben gehört auf jeden Fall in diese Gruppe.

    Nur wenn man die nötigen Grundlagen nicht hat, dann ist die Frage wie viel einem noch fehlt, und wie steil die Lernkurve ist.
    Und für jmd. der C, C++ oder eine ähnliche Sprache kann, sonst aber nicht viel Ahnung von der Funktionsweise von Computern hat, halte ich es für einigermassen schwierig.


  • Mod

    Das Thema wird noch zusätzlich sehr stark erschwert durch Schutzmechanismen wie ausführ- bzw. schreibgeschützte Speicherseiten. Das heißt, man kann auf modernen Systemen nicht einfach den Programmcode ändern. Gleichzeitig kann man auch nicht (ohne tiefergehende Kenntnisse) einfach eine Funktion in den dynamischen Speicher memcpy'en und dort ausführen. Und ganz kompliziert wird es, wenn die Funktion nicht positionsunabhängig ist (was bei fertig gelinkten Programmen leicht der Fall sein kann), dann kann man's eigentlich gleich vergessen.

    Der moderne PC ist immer weniger eine Von-Neumann-Maschine, die alten Hackertricks funktionieren nicht mehr 😞 .

    Ich habe jedenfalls gerade nach einer halben Stunde aufgegeben, ein Beispiel zu basteln, mein PC ist zu resistent.





  • "Selbstmodifizierendes" Programm ist auch eine etwas komische Beschreibung. Ein Programm braucht sich selbst so gut wie nie zu modifizieren (außer vielleicht irgendwelche Malware). Aber es gibt durchaus Fälle, wo es Sinn macht, ausführbaren Code dynamisch zu generieren.



  • Ein selbstmodifizierendes Programm zu schreiben geht schnell, aber ein sinnvolles zu schreiben ist wieder ein anderes Thema.

    Das hatte ich irgendwann einmal woanders gepostet:

    #include <iostream>
    #include <sys/mman.h>
    
    int foo()
    {
      return 39;
    }
    
    int main()
    {
      using namespace std;
      cout << foo() << endl;
    
      const int pageSize=4096;
      mprotect(reinterpret_cast<char*>(reinterpret_cast<size_t>(foo)/pageSize*pageSize),pageSize,PROT_READ|PROT_WRITE|PROT_EXEC);
      char* fooFunc=reinterpret_cast<char*>(foo);
      for (int i=0;i<50;i++)
      {
        if (fooFunc[i]==39)
        {
          fooFunc[i]=42;
          break;
        }
      }
    
      cout << foo() << endl;
    }
    

    Dass es funktioniert, kann natürlich niemand garantieren. Insbesondere wenn da noch eine andere 39 vorkommt (z.B. als Teil einer Instruktion), können lustige Sachen passieren. Außerdem sollte man ohne Optimierungen kompilieren, sonst macht der Inliner und die pure/const-Analyse einen Strich durch die Rechnung.
    Wenn es klappt, gibt das Programm

    `39

    42`
    aus.



  • Athar schrieb:

    Ein selbstmodifizierendes Programm zu schreiben geht schnell, aber ein sinnvolles zu schreiben ist wieder ein anderes Thema.

    Ich glaube der Satz gilt immer noch wenn man sinnvolles durch garantiert korrektes ersetzt.



  • In Prolog fuege ich einfach Praedikate hinzu oder loesche welche. 🙂

    und sich ausreichend mit einem Thema auskennt, dann ist fast nichts besonders schwer.

    Im Softwarebereich, ja.



  • knivil schrieb:

    In Prolog fuege ich einfach Praedikate hinzu oder loesche welche. 🙂

    In Forth und Lisp verwischen sich mir auch die Unterschiede zwischen Laufzeit und Compilezeit. In Perl kann man supi Quelltest zu Funktionen machen und ins laufende Programm stopfen und auch wieder rausmachen. .Net hat doch da auch sowas wie Expression Trees.

    Beim 64-er schreibe ich einfach eine einzufügende Zeile auf den Bildschirm und ein goto 50 drunter, setze der Cursor auf die obere Zeile, pushe zweimal die Eingabetaste in den Tastaturpuffer und halte das Programm an.
    (Siehe 64'er-Magazin 12/84)
    Oh, ich hab's schon damals gemacht. 🤡



  • Habe mir jetzt auch ein kleines Programm gebastelt welches sich selbst
    modifizieren/kompilieren kann. Jetzt muss ich aber immer den Quellcode
    in dem Programm mitschleppen. Gibt es vlt. eine Libarie um Quines zu erzeugen?

    0x0ERROR



  • 0x0ERROR schrieb:

    Gibt es vlt. eine Libarie um Quines zu erzeugen?

    Ändere doch die Sprache dahingehend, daß es einfacher ist.

    Hier mal was zum Anlehnen: http://www.dangermouse.net/esoteric/hq9plusplus.html

    Und /proc/config.gz



  • Ich würde dies lieber mit C++ machen, vorallem weil HQ9++ 5 Befehle
    zur verfügung hat. Hat jemand eine solche Libarie?

    0x0ERROR



  • 0x0ERROR schrieb:

    Ich würde dies lieber mit C++ machen, vorallem weil HQ9++ 5 Befehle
    zur verfügung hat. Hat jemand eine soclche Libarie?

    0x0ERROR

    Falls Du trollst:
    Sei nicht penentrant.

    Falls nicht, lies gleich mal "Gödel Escher Bach" und dann überlege die Frage nochmal.



  • Ich meine ein Programm, welches aus einem vorhandenen Quellcode
    einen einzeiligen String erzeugt. Diesen String will ich dann im Programm
    weiterverarbeiten.

    0x0ERROR



  • Habe jetzt folgenden Code, der aber nicht funktioniert:

    #include <iostream>
    #include <ostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    ofstream datei_out;
    ifstream datei_in;
    string name = "quine.cpp";
    char *inhalt = "";
    void quine(string name) {
    	datei_in.open(name.c_str(),ios_base::in);
    	while(!datei_in.eof()) {
    		datei_in.getline(inhalt,1000);
    		}
    	datei_out.open(name.c_str(),ios_base::out);
    	datei_out << inhalt << endl;
    }
    int main() {
    quine("main.cpp");
    return 0;
    }
    

    0x0ERROR


  • Mod

    0x0ERROR schrieb:

    Habe jetzt folgenden Code, der aber nicht funktioniert:

    Wenn du mit den Grundlagen von C++ strauchelst, dann wird das nichts mit selbstmodifizierendem Code. Der Code enthält einen schweren technischen Fehler (wohin zeigt inhalt?); mindestens drei schwere Logikfehler (die Leselogik ist dreifach falsch); einen schweren Programmierfehler (Dateien werden gleichzeitig mehrfach geöffnet); einen vermutlichen Programmierfehler (name?); und zahlreiche Programmierfehler, die nur darauf warten, dass sie noch passieren (globale Variablen, char-Arrays, fehlende Fehlerprüfungen), oder schon die oben genannten Fehler indirekt verursacht oder begünstigt haben.

    Zusätzlich warst du nicht in der Lage, diese Anfängerfehler selbstständig zu vermeiden oder mit einem Debugger zu analysieren (das wäre sehr einfach gewesen) oder wenigstens soweit zu erforschen, dass du mehr dazu sagen konntest als "funktioniert nicht". Vergiss selbstmodifizierenden Code, lern Grundlagen. In 5-6 Monaten kannst du dir das Thema noch einmal angucken. Wenn du gut bist, dann bekommst du es zu der Zeit dann auch alleine hin.



  • Ich kenne mich nur mit dem Dateilesen nicht aus. Ein kleines
    selbstveränderndes Programm habe ich schon programmiert.

    0x0ERROR



  • volkard schrieb:

    Beim 64-er schreibe ich einfach eine einzufügende Zeile auf den Bildschirm und ein goto 50 drunter, setze der Cursor auf die obere Zeile, pushe zweimal die Eingabetaste in den Tastaturpuffer und halte das Programm an.
    (Siehe 64'er-Magazin 12/84)
    Oh, ich hab's schon damals gemacht. 🤡

    Hehe, kenn ich!

    Lass mich raten:
    Um vom Benutzer eingegebene mathematische Formeln auswerten zu können?



  • Jockelx schrieb:

    volkard schrieb:

    Beim 64-er schreibe ich einfach eine einzufügende Zeile auf den Bildschirm und ein goto 50 drunter, setze der Cursor auf die obere Zeile, pushe zweimal die Eingabetaste in den Tastaturpuffer und halte das Programm an.
    (Siehe 64'er-Magazin 12/84)
    Oh, ich hab's schon damals gemacht. 🤡

    Hehe, kenn ich!

    Lass mich raten:
    Um vom Benutzer eingegebene mathematische Formeln auswerten zu können?

    Uih, das ist lange her. Wenn ich mich recht erinnere: Das Spiel "Kaiser" (in Basic geschrieben) ließ sich nach Abbruch LISTen, aber der Speicher war so verPOKEt, daß sonst wenig damit anzufangen war, insbesondere kein Abspeichern. Aber das Listing konnte ich wegschreiben. Und wie das zu einem Programm machen? Um Zeile 60000 eine Routine, die Zeile für Zeile liest und per programmiertem Direktmodus ins eigene Programm einfügt. Tadaaa!



  • Uii, Kaiser!!
    Sehr schön, wenn nach dem dritten oder vierten Krieg nicht immer ein out-of-memory Error gekommen wäre.

    Egal, genug Nostalgie!


Anmelden zum Antworten