Frage

Wie generiert eine virtuelle Maschine spontan nativen Maschinencode und führt ihn aus?

Angenommen, Sie können herausfinden, welche nativen Maschinen-Op-Codes Sie ausgeben möchten. Wie führen Sie sie dann tatsächlich aus?

Ist es etwas so Hackiges, wie die mnemonischen Anweisungen auf Binärcodes abzubilden, sie in einen char*-Zeiger zu stopfen und sie in eine Funktion umzuwandeln und auszuführen?

Oder würden Sie eine temporäre gemeinsam genutzte Bibliothek (.dll oder .so oder was auch immer) generieren und sie mit Standardfunktionen wie „ LoadLibrary ?

War es hilfreich?

Lösung

Du kannst das einfach machen Programm zähler Zeigen Sie auf den Code, den Sie ausführen möchten.Denken Sie daran, dass Daten Daten oder Code sein können.Auf x86 ist der Programmzähler das EIP-Register.Der IP-Teil von EIP steht für Instruction Pointer.Der JMP-Befehl wird aufgerufen, um zu einer Adresse zu springen.Nach dem Sprung enthält EIP diese Adresse.

Ist es etwas so Hackiges, wie die mnemonischen Anweisungen auf Binärcodes abzubilden, sie in einen char*-Zeiger zu stopfen und sie in eine Funktion umzuwandeln und auszuführen?

Ja.Dies ist eine Möglichkeit, dies zu tun.Der resultierende Code würde in a umgewandelt werden Zeiger auf Funktion in C.

Andere Tipps

Ist es etwas so Hackiges, wie die mnemonischen Anweisungen auf Binärcodes abzubilden, sie in einen char*-Zeiger zu stopfen und sie in eine Funktion umzuwandeln und auszuführen?

Ja, wenn Sie es in C oder C++ (oder etwas Ähnlichem) machen würden, würden Sie genau das tun.

Es sieht abgedroschen aus, aber das ist eigentlich ein Artefakt des Sprachdesigns.Denken Sie daran, dass der eigentliche Algorithmus, den Sie verwenden möchten, sehr einfach ist:Bestimmen Sie, welche Anweisungen Sie verwenden möchten, laden Sie sie in einen Puffer im Speicher und springen Sie zum Anfang dieses Puffers.

Wenn Sie dies jedoch wirklich versuchen, stellen Sie sicher, dass Sie die Aufrufkonvention richtig anwenden, wenn Sie zu Ihrem C-Programm zurückkehren.Ich denke, wenn ich Code generieren wollte, würde ich nach einer Bibliothek suchen, die diesen Aspekt für mich übernimmt.Nanojit war kürzlich in den Nachrichten;Du könntest dir das ansehen.

Jawohl.Sie erstellen einfach einen char* und führen ihn aus.Allerdings müssen Sie ein paar Details beachten.Das Zeichen* muss sich in einem ausführbaren Abschnitt des Speichers befinden und die richtige Ausrichtung haben.

Zusätzlich zu Nanojit können Sie sich auch LLVM ansehen, eine weitere Bibliothek, die verschiedene Programmdarstellungen bis hin zu einem Funktionszeiger kompilieren kann.Die Benutzeroberfläche ist sauber und der generierte Code ist tendenziell effizient.

Soweit ich weiß, kompiliert es alles im Speicher, da einige Heuristiken ausgeführt werden müssen, um den Code zu optimieren (d. h.:Inlining im Laufe der Zeit), aber Sie können einen Blick darauf werfen Gemeinsam genutzte Quell-Common-Language-Infrastruktur 2.0 Rotorfreigabe.Die gesamte Codebasis ist bis auf Jitter und GC identisch mit .NET.

Neben Rotor 2.0 können Sie sich auch den ansehen Virtuelle HotSpot-Maschine im OpenJDK.

Informationen zum Generieren einer DLL:Die dafür zusätzlich erforderlichen I/O-Vorgänge sowie die Verknüpfung und die Komplexität der Generierung des DLL-Formats würden dies viel komplizierter machen und vor allem die Leistung beeinträchtigen.Außerdem rufen Sie am Ende immer noch einen Funktionszeiger auf den geladenen Code auf, also ...Außerdem kann die JIT-Kompilierung jeweils einzeln erfolgen, und wenn Sie das möchten, müssen Sie viele kleine DLLs generieren.

Was die Anforderung „ausführbarer Abschnitt“ betrifft, kann der Aufruf von mprotect() auf POSIX-Systemen die Berechtigungen korrigieren (es gibt eine ähnliche API auf Win32).Sie müssen dies für ein großes Speichersegment tun, anstatt einmal pro Methode, da es sonst zu langsam wäre.

Auf einfachem x86 würden Sie das Problem nicht bemerken, auf x86 mit PAE oder 64-Bit-AMD64/Intel-64-Bit-Maschinen würden Sie einen Segfault erhalten.

Ist es etwas so Hacky wie die Zuordnung der mnemonischen Anweisungen zu binären Codes, in einen Zeichenzeiger und wirft ihn als Funktion und Ausführung?

Ja, das funktioniert.

Um dies in Windows zu tun, müssen Sie PAGE_EXECUTE_READWRITE auf den zugewiesenen Block setzen:

void (*MyFunc)() = (void (*)()) VirtualAlloc(NULL, sizeofblock,  MEM_COMMIT, PAGE_EXECUTE_READWRITE);

//Now fill up the block with executable code and issue-

MyFunc();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top