C/C++ Speicherinhalt direkt ausführen

katerkarlo

Grünschnabel
Hallo zusammen,

wie kann ich Programmcode, der sich bereits im Datenspeicher befindet, in einen Speicherbereich laden/kopieren, in dem dieser Code direkt ausgeführt wird?

Es geht um eine Art Kopierschutz, bei dem eine vorher künstlich verlängerte *.exe Datei von Platte in einen Puffer gelesen wird (bis zum Ende der "echten" *.exe).

Von diesem Puffer wird ein FileMapping im Speicher erzeugt, und ein Zeiger auf den Anfang des Mappings gesetzt.

Ich kann jetzt das Mapping bearbeiten, und dann z.B. eine saubere *.exe als neue Datei zurückschreiben, und diese ausführen.

Problem: Ich möchte die neue *.exe nicht zurückschreiben, sondern den Code im Mappingbereich direkt ausführen.

Ich habe (ganz grob) die bisherigen Schritte in Visual C++ unternommen:

CreateFile(hHandele, ...);
CreateFileMapping(...);
...
lpViewBuffer = ViewMapOfFile(...);

(LPVOID)lpViewBuffer zeigt auf den Anfang des Mappingbereichs, und soweit funktioniert alles.

Wie aber nun ausführen?

Hat jemand eine Ahnung wie sowas finktioniert?

Wäre sehr dankbar für kompetente Hilfe, da ich auch nach 2 tägiger Suche keine Lösung gefunden habe.
 
Ich würde es so machen:
Die richtige Startadresse in einen Funktionspointer zuweisen und die Funktion dann aufrufen
Ich hoffe es hilft weiter.

Gruß Byteblaster
 
Hallo Byteblaster,

das klingt ganz gut, aber wie finde ich die "richtige" Startadresse?

Hast Du vielleicht ein Codeschnipsel, mir fehlt im Moment leider völlig der Ansatz.
 
Hm, Assemblen würde ich sagen. Ob man ohne weiteres ne ganze EXE so ausführen kann weiß ich nicht, aber mit Codebröckchen kann man das sicher so machen, dass man einfach die Startadresse vom Code nimmt und mit "call" dahinspringt. Wenn man noch ein "ret" ans Ende des Codes setzt, zu dem man gesprungen ist, dann sollte es auch keine Probleme geben.
 
Hi,
an Assembler hatte ich auch schon gedacht, aber es muss auch anders gehen.

Denk z.B. mal an Diskless Clients, oder an sonstige Mini-PCs ohne Festplatte.

Oder an bestimmte Router oder Handhelds die ihr Betriebssystem inkl. aller zugehöriger Software aus einem EPROM holen, und direkt ausführen.

Sicher sind da Assembler Routinen mit im Spiel, aber ich meine, C++ und insbesondere Visual C++ stellt Funktionen hierfür bereit.

Die Idee mit dem Pointer auf Funktion ist eigentlich nicht schlecht, aber wie gesagt, ich finde da keinen vernünfigen Ansatz. Sicher, ich habe einen Pointer vom Typ LPCVOID auf den Anfang des Mappings, und kann auch auf den Inhalt zugreifen, aber nicht ausführen.

Die Grundfrage ist ja auch eigentlich im Basisbereich: Wie unterscheidet der Rechner, ob es sich um Datenspeicher handelt, oder um einen Call, und ob dieser Code ausgeführt werden soll(im Code-Speicher)?

Ich bin nur Gelegenheits C-Programmierer, stehe jetzt aber ziemlich unter Druck, eine Lösung zu finden.
 
Wieso? Jedes Computerprogramm besteht nur aus maschinenleslichen Assembleranweisungen. Du schreibst ja darüber, als ob es eine Umweg oder ne schlechte Alternative wäre. Und mit dem Inline-Assembler kann man doch unter C/C++ problemlos Assembler einbinden.
Prinzipiell dürfte es aber tatsächlich auch über einen Funktionszeiger laufen, ABER: Es ist ganz wichtig die richtige Aufrufkonvention zu wählen und umzusetzen, weil es da gravierende Unterschiede gibt (stdcall würde bspw. von der Funktion, die aufgerufen wird, erwarten, dass sie den Stack räumt).
 
Eben...die richtige Aufrufkonvention. Und wie sieht die aus?

MS beschreibt ja auch nicht genau, in welcher Form dieses Mapping im Speicher vorliegt. Wenn es einfach intern nur als "DATA" gekennzeichnet ist (was durchaus möglich ist), kann man sich dumm und dämlich probieren, es wird nichts passieren, oder sehe ich das falsch?

Was ich bisher habe(auszugsweise):

// Funktion

LPCVOID testfunc(HANDLE hFile, HANDLE hMapFile)
{

DWORD dwDesiredAccess = FILE_MAP_COPY;
DWORD dwFileOffsetHigh = 0;
DWORD dwFileOffsetLow = 0;
DWORD dwNumberOfBytesToMap = GetFileSize(hFile,NULL);

/*
LPCVOID lpViewBuffer = MapViewOfFile(hMapFile,
dwDesiredAccess,
dwFileOffsetHigh,
dwFileOffsetLow,
dwNumberOfBytesToMap);

*/

MapViewOfFile(hMapFile,
dwDesiredAccess,
dwFileOffsetHigh,
dwFileOffsetLow,
dwNumberOfBytesToMap);
return NULL;
};


// Zeiger
LPCVOID (*mp) (HANDLE,HANDLE) = testfunc;
(*mp) (hFile,hMapFile);


Läuft, aber passiert nix.
 
An welcher Stelle soll da auch was passieren? Du lädst die exe in den Speicher oder was macht der Code? Als nächstes muss irgendwie der Instruction Pointer (eip-Register) auf den Einstieg der exe. Würde gehen mit dem Assembler-call oder du setzt einen einfachen Zeiger auf diese Einstiegsadresse, interpretierst den Zeiger um als Funktion und rufst die Funktion auf, Konvention __cdecl.
Die Probleme sind nur folgende:
1. Dein Programm macht dann einfach in der exe weiter, die exe gehört dann zu deinem Programm, weil du den Code der exe als den Code deines Programmes verarbeitest, wenn du den eip darauf knallst.
2. ES FUNKTIONIERT NICHT. Es funktioniert nicht, weil jeder Prozess in Win32 einen eigenen virtuellen Speicherbereich erhält, der bei 0 anfängt. Darauf verlässt sich jedes Programm, jeder Speicheraufruf, den die exe ausführt ist falsch, weil sie ja IRGENDWO im virtuellen Speicherbereich deines Programms hängt und keinen eigenen Prozess erhält. Es funktioniert also nicht, zumindest nicht so einfach. Sowas funktioniert nur gut, mit einfachen algorithmischen Codebausteinen, die man zur Laufzeit berechnet und der Effizienz wegen einsetzt.

Des Rätsels Lösung also - und bei weitem einfacher als diesen Kram zurechtzubasteln: einfach doch die exe speichern und ausführen, temporär vielleicht, so dass es nicht weiter auffällt.
Ansonsten kannst du dich noch mit der Struktur der ausführbaren Dateien und der Prozessverarbeitung unter Windows beschäftigen oder mal schnell On-the-Fly die ganzen Speicherzugriffe in der exe ändern (weiß nicht, ob das nicht sogar über Tabellen ). Aber da - wie ein Kumpel von mir sagen würde - "machst du dich tot".
 
Also erstmal möcht ich Dir danken, das du dich so intensiv mit meinem Kram beschäftigst; in einem anderen "Expertenforum" kam nur dummes Geblubber, und ich hatte den Eindruck, die Leute wissen noch weniger als ich. Also echt super, danke nochmals.

Ja, im Prinzip habe ich ähnliche Überlegungen schon angestellt, die du mir auch schreibst:

Jeder Speicheraufruf der exe ist falsch, weil sie keinen eigenen Prozess hat.
Die Variante hatte ich auch schon, Fehlermeldung: ...verweist auf Speicher in 0x000...
CreateProcess() geht nicht, erwartet einen Dateinamen, CreateThread() erwartet einen laufenden Prozess.

(Wie wäre es eigentlich, wenn man temporär eine RAM-Disk anlegt, geht so was, oder nur "onboot"?)

Das FileMapping von MS macht nichts anderes, als die exe (VERMUTLICH auch noch als typ char in einen (?)Speicherbereich zu kopieren).

Ich wollte mich auch nicht in dieses FileMapping verbeissen, nur auf den ersten Blick machte es den Eindruck, als wäre es leichtes Spiel.

Für MASM Assembler fehlen mir leider die Kenntnisse, mit asm überhaupt habe ich zuletzt 1985 zu tun gehabt (Basiswissen Intel 8086/8088 und Atari 6502).
Aber wäre mir doch die sympathischste Lösung, das temporäre speichern gefällt mir nicht.

Sagen wir mal so: Ein versierter Anwender, der Basiswissen hat, käme schnell dahinter, und das darf nicht sein. Die echte exe darf nicht ungeschützt sein, da sie sensible Daten enthält. Die exe ist ein kompiliertes flash.swf, was die Sache noch etwas kompliziert, da Macromedia bekanntlich sich über Interna in Schweigen hüllt. Die exe macht ausserdem einen CRC-Check, muss also wirklich lupenrein sein. Ein Leer- oder anderes Zeichen irgendwo, und das Teil startet nicht mehr.

Also, ich habe hier noch Borland Turbo-Assembler 4.0(auch schon betagt, nützt das was?), und würde mich auch gern wieder mit asm beschäftigen.

Wenn du einen Ansatz in asm für mich hättest, könnte ich wohl auch mit Standard C/C++ arbeiten (ist mir ohnehin sympathischer).

Aber nochmal kurz zu den Diskless Clients, PDAs, Handys, Router und ähnliches Zeugs, wie machen die das? Ich meine, ein EPROM(oder ähnliche Chips mit "hardcoded Software") besteht doch einfach gesagt auch nur aus Speicher, der in einer bestimmtenStruktur vorliegt und belegt ist? Wie bringen die ihre executeables da rein, und wie führen sie sie aus?


Gruss
Jürgen
 
Ja aber einen laufenden Prozess hast du doch! Warum kannst oder willst du den nicht nutzen für die CreateThread() Funktion? Oder verstehe ich was nicht richtig?

Gruß Byteblaster
 
Zurück