C++/ASM DLL Funktion modifizieren

Hey Leute,
ich versuche schon längere Zeit (immer mal wieder) eine Funktion (z.B. SetCursorPos/PostMessage) aus einer DLL (in diesem Fall user32.dll) zu importieren (während der Laufzeit) und diese dann mit eigenen Assemblerbefehlen zu verändern.
Schema:

DllAufruf
Funktion aus DLL importieren
Assembler Code ausführen (z.B. 10 Bytes lang)
Funktionsstartpunkt + 10 Bytes ausführen (die ersten 10 Bytes der Originalfunktion ignorieren)

Dazu habe ich mir http://www.hackerboard.de/code-kitchen/40292-c-asm-gewisse-stelle-anspringen.html angeschaut, aber es funktioniert bei mir trotzdem nicht.

Soweit bin ich bis jetzt:

Code:
typedef  BOOL (WINAPI *ggSCP) (int x,int y) ;
void SetCurs(int x, int y)
{
    
hInst = LoadLibrary(TEXT("C:\\Windows\\System32\\user32.dll"));

           
                ggSCP DLLFuncSCP = ggSCP(GetProcAddress(hInst, "SetCursorPos")); 
                FreeLibrary(hInst);
                hInst = NULL;
           
 
                
                
    __asm 
  {
     mov  edi, edi
     push ebp
      mov  ebp, esp
      add DLLFuncSCP, 5
      jmp [DLLFuncSCP]
   }
         
}

Jedoch kommt des öfteren (je nach Codevarianten) eine Access Violation oder " Run-Time Check Failure #0 - The value of ESP was not properly saved ....." wenn ich die Funktion aufrufe!

Wäre nett, wenn jemand helfen könnte :)
Mfg Raisem
 
Ich vermute, dass es daran liegt, dass Du die Dll zu früh freigibst. Den SetCursorPos-Function Pointer erhälst Du durch GetProcAddress(...), gibst die Dll aber sofort wieder frei (FreeLibrary(...)). Ich schätze, dass Du die Funktion deshalb nicht mehr aufrufen kannst (--> versuchen).

s. auch http://msdn.microsoft.com/en-us/library/h4ff11tc(v=vs.80).aspx:
"Processes explicitly linking to a DLL call the FreeLibrary function when the DLL module is no longer needed."

Aber meine Zeit unter C++ und Dlls sind schon länger vorbei, da ist C# halt Luxus...
 
Ich kann sie aber gar nicht später freigeben :/ Im Assemblercode springe ich ja zur Funktion -> ich erreiche nichtmehr die Aufrufe nach dem asm code ..
EDIT: Bzw. soll das in der MSDN heißen, dass ich FreeLibrary gar nicht brauche, da das Programm das sowieso von selbst macht?
 
Zuletzt bearbeitet:
Du musst die auch nicht freigeben ;). Wenn das Program die DLL eher nutzt, wird sie nicht wirklich "entladen" (nur der Referenzcounter dekrementiert). Falls Du trozdem eine "korrekte" Art sucht, um an die Basisadresse der DLL zu kommen: GetModuleHandle.

Zum wesentlichen:
Debugging ist bei Hooks und anderen "low-level" Späßen eigentlich eine Pflicht. 10 Minuten OllyDbg sparen 1 Stunde "Fehler durch Anschauen im Source finden" suche ;)

Mögliche Fehlerursachen aus dem Source:
1: unbedingt Callingconventions beachten, sonst bringt man den Stack durcheinander:
http://code.entersources.com/f/Inside-Calling-Conventions_2_4776_0.aspx
http://www.3rd-evolution.de/docs/windows/callconv/
(keine Ahnung, welchen Compiler Du verwendest und welche Konvention dieser per Default einsetzt)

2. Stackframe nicht kaputt machen
zuerst wird bei der Funktionsausführung der Stackframe Deiner "SetCur" Funktion eingerichtet. Also üblicherweise
Code:
push ebp
mov ebp,esp
sub esp, X
dann schaut der Stack in etwa so aus:
Code:
...
lokale_variable2
lokale_variable1
alter_EBP_Wert
Rücksprungadresse_des_Aufrufers_von_SetCur
ParamX
ParamY
(nicht vergessen, dass bei einem Funktionsaufruf die Rücksprungadresse auf dem Stack landet ;) )
Das sollte der Compiler von alleine generieren. Erst jetzt kommt der von Dir eingegebener Code zur geltung:
Es wird die Adresse ermittelt und ein wenig Code (_ASM Abschnitt) ausgeführt. Nun schaut der Stack so aus:
Code:
jungster_EBP_Wert
...
lokale_variable2
lokale_variable1
alter_EBP_Wert
Rücksprungadresse_des_Aufrufers_von_SetCur
ParamX
ParamY

und wenn Du mittels JMP in den Code springst, weiß der API-Code nichts davon, dass Du den Code irgendwie manipuliert hast und deswegen der Stack nicht mehr stimmt ;). Der Aufruf wird abgearbeitet und am Ende kommt sowas wie:
Code:
POP EBP
RETN 8

Da der Stack so ausschaut wie oben, wird erstmal durch POP der EBP Wert geholt, wie er zum Zeitpunkt des JMPs zur Codstelle war.
Und dann wird versucht zu RETurnen - dazu wird die nächste Wert auf dem Stack als Adresse benutzt (in dem Fall ist es der Wert einer lokalen Variable aus Deiner Funktion SetCur).

D.h entweder benutzt Du einen CALL und lässt die API erstmal in Deine SetCur Funktion zurückkehren oder Du fummelst ein wenig rum und richtest den Stackframe vor dem JMP so her, wie er sein sollte (Pi mal Daumen):
zuerst:
Code:
mov esp, ebp  ; ESP Wert vor Ausführung Deines Codes
pop ebp         ; EBP Wert vor Ausführung Deines Codes
das sollte den Stackframe wieder herrichten.
und erst jetzt Dein eigentlicher ASM-Inlinecode:
Code:
push ebp
bla


PS: mir ist klar, dass ich den Code dupliziere, da der Stackframewiederherstellungsabschnitt größtenteils durch nachfolgenden Code wieder zückgängig gemacht wird, aber so sollte es imho ersichtlicher sein.
Für den konkreten Fall dürfte es ausreichen, wenn Du nur Deinen Asm Code modifizierst:
Code:
      mov  esp, ebp  ;nur ESP wiederherstellen
      add DLLFuncSCP, 5
      jmp [DLLFuncSCP]
 
Geupdateter Code... Funktioniert aber immer noch nicht so super (Access Violation..) : (Sehr stark am verlinkten Post orientiert)


typedef BOOL (WINAPI *ggSCP) (int x,int y) ;
void SetCurs(int x, int y)
{

hInst = LoadLibrary(TEXT("user32.dll"));


int blubb = (int)GetProcAddress(hInst, "SetCursorPos");
blubb+=7;

__asm
{

mov EDI, EDI
push EBP
mov EBP, ESP

push DWORD PTR SS:[EBP+8]
push DWORD PTR SS:[EBP+12]
push blubb
add ESP,4

jmp DWORD PTR SS:[ESP-4]
}


Wäre nett, falls noch wer Vorschläge bringen könnte :)
 
kleine Anmerkung: habe den obigen Post editiert und den Vorschlag mit dem Call erstmal entfernt, da ein Call ja die Rücksprungadresse ablegt und der Stackframe damit ebenfalls zersört wäre.
Die Frage ist nun, ob Du unbedingt in die SetCur zurückkehren möchtest oder die Rückkehr zum Aufrufer der SetCur auch akzeptabel ist.
Im ersten Fall müsste man vor Deinem _asm Part dann noch die Rücksprungadresse bestimmen und manuell auf dem Stack ablegen. Und das dürfte nicht ganz so einfach gehen (hier müsste man entweder mit Labels arbeiten und deren Adresse bestimmen können oder über inline ASM die aktuelle Adresse bestimmen und dann ausrechnen, wieviele Bytes zwischen dieser Adresse und der gewünschten liegen).
Bsp:
Code:
_asm:
call delta
delta:
pop eax  <--- hier ist nun die Adresse von delta
add eax, XYZ <--- Anzahl an Bytes zwischen Delta und gewünschter Rückkehradresse

Im zweiten Fall sind die obigen Vorschläge zur Stackherrichtung ausreichend.
 
Oh, den letzten Post von mir hab ich abgeschickt, bevor ich deinen gelesen hab ;) (nur 1 Minute Unterschied), ich werds gleich mal ausprobieren :) Vielen dank schonmal für die ausführlichen Erklärungen ! :wink:

EDIT:

Also das hab ich zwar verstanden, was du geschrieben hast, aber die direkte Umsetzung funktioniert trotzdem nicht so :/

Code:
void SetCurs(int x, int y)
{
hInst = LoadLibrary(TEXT("C:\\Windows\\System32\\user32.dll"));    
                //ggSCP DLLFuncSCP = ggSCP(GetProcAddress(hInst, "SetCursorPos")); 
int DLLFuncSCP = (int)(GetProcAddress(hInst, "SetCursorPos"));                          
    __asm 
  {
     mov  edi, edi // <-- die ersten 5 Bytes der Funktion
     push ebp // und gleichzeitig auch die von dir vorgeschlagene Änderung 
     mov  esp, ebp  //<-----
   
      jmp [DLLFuncSCP]
   }
         
}
Das spuckt weiterhin Fehler aus ... Wo baue ich denn die Parameter rein? Direkt vor das JMP hätte ich gedacht, das funktioniert dann leider trotzdem nicht :( Hier noch ein paar Zusatzinformationen:


Mein eigentliches Ziel ist es, den Schutz von Gameguard zu umgehen (versuche das schon länger, bräuchte es zwar eigentlich nichtmehr, aber ist gut für mein ego, wenn ich das schaffe :) ). Es gibt ein Tutorial diesen Gameguard zu umgehen, das mehrfach gepostet wird, aber ich schätze mal man darf nicht auf andere Foren verweisen... Dort wird dieser Code verwendet: (Der Ersteller hat das Tutorial auf das Spiel Flyff von Gpotato bezogen, es geht aber mit allen Spielen, die Gameguard verwenden). Dieser Code wird erzeugt und als DLL verpackt:

Code:
#include <windows.h>

HINSTANCE hInst; 
DWORD DLLFunc; 
HWND hFlyff;
HWND hWnd;


__declspec(naked) BOOL WINAPI __stdcall myPostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
   __asm
   {
      mov  edi, edi
      push ebp
      mov  ebp, esp
      jmp [DLLFunc]
   }
}

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpvReason*/)
{
    switch (dwReason)
    {
        
        case DLL_PROCESS_ATTACH:
        {
               if (DLLFunc == NULL) {
                hInst = LoadLibrary("user32.dll");
                DLLFunc = (DWORD)GetProcAddress(hInst, "PostMessageA") + 5; 
                }
               if (hFlyff == NULL) {
                hFlyff = ::FindWindow(NULL, "FLYFF");
                }
        }
        break;

        case DLL_THREAD_ATTACH:
            {
               if (DLLFunc == NULL) {
                hInst = LoadLibrary("user32.dll");
                DLLFunc = (DWORD)GetProcAddress(hInst, "PostMessageA") + 5; 
                }
               if (hFlyff == NULL) {
                hFlyff = ::FindWindow(NULL, "FLYFF");
                }
            }
        break;
        case DLL_THREAD_DETACH:
            {
                if (hInst != NULL) {
               // Un-Load DLL
               ::FreeLibrary(hInst);
               hInst = NULL;
            } 
            }
        break;
        case DLL_PROCESS_DETACH:
        {
                if (hInst != NULL) {
               // Un-Load DLL
               ::FreeLibrary(hInst);
               hInst = NULL;
            } 
        }
        break;
    }
    return TRUE;
}

Jedoch funktioniert dieser Code bei mir nicht (ganz nebenbei: ich verwende Visual Studio Express (C++) 2008 ) und außerhalb wollte ich keine DLL ;)
Also habe ich nur die Grundidee übernommen (und Codeschnipsel) um das neu nachzubauen :) (was ja leider nicht funktioniert :( )

Sorry falls ich irgendwie nicht verstanden hab, was ihr versucht habt zu erklären, aber bin auf dem Zweig der Assemblerprogrammierung und des Debuggings absoluter Neuling :)

Mfg Rai
 
Zuletzt bearbeitet:
Sorry, hätte ich dazuschreiben sollen:
meine Vorschläge beziehen sich immer auf die Abarbeitung vor deinem eigentlichen Code.


Also so:
Code:
 __asm 
  {
;Stackherstellung:
mov esp, ebp  ; ESP Wert vor Ausführung Deines Codes
pop ebp         ; EBP Wert vor Ausführung Deines Codes

;Dein eigentlicher Code
     mov  edi, edi
     push ebp
      mov  ebp, esp
      add DLLFuncSCP, 5
      jmp [DLLFuncSCP]
   }
Alternativ:
dein Code komplett modifiziert:
Code:
      mov edi, edi
      mov  esp, ebp  ;nur ESP wiederherstellen

      add DLLFuncSCP, 5
      jmp [DLLFuncSCP]
Btw: das MOV EDI,EDI am Anfang der API-Funktionen ist nur ein Dummy (quasi ein Ersatz für NOPs) und kann weggelassen werden.

Zudem schau dir den Link mit calling Conventions nochmal an. Der wesentliche Unterschied zwischen deinem Code und dem aus Tutorial:
im Tutorial tut die Funktion erstmal nichts und wird zudem direkt als STDCALL deklariert.

PS:
Jedoch funktioniert dieser Code bei mir nicht (ganz nebenbei: ich verwende Visual Studio Express (C++) 2008 ) und außerhalb wollte ich keine DLL
Ich tippe stark darauf, dass die DLL in den Prozess injiziert wird, weil sie dann im Kontext der Anwendung läuft und viel leichter die APIs hooken kann ;)
Also wirst du nicht um DLLs herumkommen (ohne gehts zwar auch, aber nicht mit reinem C/C++ und schon gar nicht ohne viel inline ASM bzw viel rumprobieren und Debuggen ;) )

Und wie gesagt, das A und O bei solchen Sachen ist der Umgang mit dem Debugger. Solange man nicht weiß, an welcher Stelle es genau scheitert (Stimmt die Rücksprungadresse nicht oder hat man bloß irgendwo die Variablenwerte vertauscht?) wird das Herumprobieren im Quellcode nicht wirklich etwas bringen ;)
 
Funktioniert soweit (so wie du's geschrieben hast). Vielen Dank bis hierhin schonmal :) Wieso sollte es mit pur c++ /asm nur sehr schwierig gehen? (funktioniert ja :P )

Hab die Funktion
Code:
void SetCurs(int x, int y)

bisschen umgeändert (wegen Runtime Errors bla ..) in:

Code:
    BOOL WINAPI SetCurs(int x, int y)



Mal ein anderer Ansatz, zu dem ich gerne wüsste, was ihr davon haltet:

{[(Gameguard überschreibt/blockiert die ersten 5 Bytes von bestimmten Funktionen (was ich ja zu umgehen versuche, indem ich den inline ASM verwende und einfach später einsteige). Was wäre denn, wenn ich die user32.dll einfach kopieren würde und dann in den Ordner meines Projekts packen würde? )]} <- Probier ich mal aus :)

Mfg Raisem
 
Funktioniert soweit (so wie du's geschrieben hast). Vielen Dank bis hierhin schonmal :) Wieso sollte es mit pur c++ /asm nur sehr schwierig gehen? (funktioniert ja :P )
Ich meinte es eigentlich im Kontext der DLL-losen Injektion in die andere Anwendung. Denn du möchtest diese Modifizierung bestimmt nicht nur in deinem eigenen Programm haben, sondern in der von Gameguard geschützten :wink:.
Das funktioniert (grob gesagt) folgendermaßen:
du schreibst den Code, der bestimmte WinAPI Aufrufe (also die kernel32/user32 DLL Funktionen) modifiziert.
Nun haben moderne Betriebssysteme schon lange eine Speichertrennung im Userspace(Stichworte Ring0 und Ring3). Heißt im Klartext: solange es sich nicht um Treiber handelt, hat jedes Programm 4GB RAM[0] für sich und kann durch modifizieren einer Systemfunktion nicht gleich die anderen Programme kaputtmachen[1].

D.h wenn du erstmal in deinem Programm den Code von SetCursorPos oder anderen Funktionen änderst, gilt das erstmal nur für dein Programm. D.h du musst deinen Code in den Speicherblock der anderen Anwendung bringen.

Am einfachsten geht das mit einer DLL. Denn diese kann man vom anderen Programm einfach laden lassen und schon kann der Code ausgeführt werden. Beim Laden der DLL wird das Betriebssystem automatisch alle nötigen Initialisierungsschritte für die DLL (Imports, Exports, das richtige Laden in den Speicher, Relocations) durchführen.

Ein anderer Weg ist es, den Code direkt in die andere Anwendung zu schreiben. Dafür gibt es mehrere Ansätze und der üblichste wäre "WriteProcessMemory" (kernel32) Funktion.
Bloß bekommt man hier keinerlei Hilfe vom Betriebssystem und muss alles selber machen. Das fängt schon mal damit an, dass man die Größe des Codeblocks ermitteln muss (afaik nicht in sauberem C/C++ umsetzbar :wink: )
Da der Code zudem Adressunabhängig sein sollte, alle Bibliothekfunktionen die man nutzt, erstmal tabu sind.
Das Gleiche gilt für WinAPIs. Möchte man trotzdem STDLIBs oder WinAPIs nutzen, muss man dafür sorgen, dass die Anwendung (in die man Code injiziert) diese lädt und entsprechend Adressen der Funktionen in dieser Anwendung herausfinden und im Code anpassen.

Ohne viel inline Asm + compilerspezifischen Code/Flags und größeren Debugsessions wird das nicht umsetzbar sein :wink:
Bei einer DLL hat man, wie gesagt, großteil der Probleme gar nicht.

[0] 2^32 Bytes = 4GB für 32 Bit Systeme. Für 64-bit entsprechend mehr
[1] Es geht auch ohne Treiber, allerdings muss der Benutzer, der das Programm ausführt, entsprechende Rechte haben und das Programm dafür vorgesehene Funktionen (OpenProcess, WriteProcessMemory, SetThreadContext oder CreateRemoteThread) nutzen.


Mal ein anderer Ansatz, zu dem ich gerne wüsste, was ihr davon haltet:

{[(Gameguard überschreibt/blockiert die ersten 5 Bytes von bestimmten Funktionen (was ich ja zu umgehen versuche, indem ich den inline ASM verwende und einfach später einsteige). Was wäre denn, wenn ich die user32.dll einfach kopieren würde und dann in den Ordner meines Projekts packen würde? )]} <- Probier ich mal aus :)
Das wird so nichts :)
Soweit ich weiß wird eine DLL, die von irgendeiner Anwendung genutzt wird, normalerweise vom System nur einmal geladen.
Jede weitere Anwendung bekommt quasi ein "Sichtfenster" darauf (somit ist die DLL im RAM tatsächlich nur 1 mal vorhanden). Erst wenn man anfängt, die DLL zu modifizieren, bekommt die modifizierende Anwendung eine Kopie der DLL im eigenen Speicher (das ganze wird von Windows transparent gemacht, so dass es "unsichtbar" abläuft). Kurzum: eine Systemdll im Ordner der Anwendung wird gar nicht geladen.
Lösung: Umbenennen der DLL (z.B nach "us3r32.dll" oder einen anderen, gleich langen und einmaligen Namen wählen). Dann umbenennen der "user32.dll" Strings in der Exe selbst zu diesem Namen (man sollte sowohl ASCII wie UNICODE Strings abarbeiten).
Problem: sofern die Exe geschützt ist, wird der Schutz rummeckern wegen Patch/Modifizierung des Codes. Zudem verschlüsseln die meisten Protectoren den Code sowie die Imports der Exe und laden diese später selbst nach (dynamisch). Somit wird Gameguard (wenn überhaupt funktionierend) die neue "us3r32.dll" auch "schützen".

Alternativ bastelt man halt einen Loader, der die DLL in die Anwenung bringt und dabei die vorhande ersetzt. Dazu muss er zuerst herausfinden, an welcher Adresse sich die User32.DLL in der Anwendung befindet, die eigene DLL exakt an diese Stelle laden und zugleich alle Initialisierungsschritte durchführen. Da kann man gleich den richtigen DLL-Code patchen :)
 
Zurück
Oben