Tutorials - Speicherzugriff Tutorial Teil 1

Sprachenübersicht/Programmierung/C / C++/ C#/Security

Speicherzugriff Tutorial Teil 1

Diese Seite wurde 15534 mal aufgerufen.

Dieser Artikel wurde in einem Wikiweb System geschrieben, das heißt, Sie können die Artikel jederzeit editieren, wenn Sie einen Fehler gefunden haben, oder etwas hinzufügen wollen.

Editieren Versionen Linkpartnerschaft Bottom Printversion

Keywords: C++, Speicherzugriff, Buffer, Memory, Memoryscanner, Trainer programmieren, auf Speicher von anderen Programmen zugreifen, Speicher verändern, Tutorial, manipulieren, Arbeitsspeicher, Cheattools, Tutorial, Anleitung, Programmieren, entwickeln

Abbildung

Inhaltsverzeichnis



Vorwort Top



Orginal von Thomas Nitschke aka namespace.

In diesem Tutorial wirst du lernen, wie man den Speicher von
anderen Programmen lesen oder schreiben kann.
Als erstes brauchen wir ein geeignetes Programm, das als Opfer
dient. Ich empfehle dieses kurze Konsolen-Programm:

Code:


#include <iostream>
#include <windows.h>

using namespace std;

int i = 15;
int main(void)
{
    cout << i << "\t" << &i << endl;
    Sleep(10000);
    cout << i << "\t" << &i << endl;
    Sleep(10000);
    return 0;
}



Das Programm erstellt eine globale Integer-Variable mit dem Wert 15.
Zuerst wird der Wert sowie die Speicheradresse ausgegeben, danach
wartet das Programm 10 Sekunden, um das ganze noch mal zu wiederholen.
Während des ersten Sleep-Aufrufs soll unser Memorytool gestartet
werden, welches den Wert von "i" verändern soll.

Bevor wir mit dem Programmieren des eigentlichen Tools beginnen,
müssen wir erstmal die Adresse wissen, auf der die int-Variable
liegt. Also einfach mal das Opfer-Prog. ausführen. Auf meinem
Rechner erhalte ich die Speicheradresse: 0x00409040. Auf deinem
Rechner kann diese komplett anders aussehen.
Außerdem sollten wir den Fensternamen der Opferproggs kennen.
Str+Alt+Entf drücken und das Prog in der Liste suchen.
Ich habe das Prog. einfach "Opfer" genannt.
So, das waren auch schon die beiden Informationen, die wir brauchen.

Die ersten Schritte Top



Hier ist der erste(!) Code für das Memorytool:

Code:


#include <windows.h>
#include <iostream>

using namespace std;

int main(void)
{
    HWND hWnd;

    hWnd = FindWindow(0,"Opfer");
    if(!hWnd)
        return 0;

    return 0;
}



Der Code sucht das Fenster des Opferprog. und bricht ab, falls
es nicht gefunden werden kann.
Doch wofür brauchen wir überhaupt ein Handle auf das Fenster?
Ganz einfach: über das Fenster kommen wir an den ID des Prozesses!
Den brauchen wir auch später, um ein Handle auf den Prozess zu bekommen.
Erst dann können wir auf den Speicher zugreifen. Aber eins nach dem
anderen. Hier der erweiterte Code:

Code:


int main(void)
{
    HWND hWnd;
    DWORD procid;

    hWnd = FindWindow(0,"Opfer");
    if(!hWnd)
        return 0;

    GetWindowThreadProcessId(hWnd, &procid);

    return 0;
}



Die Funktion GetWindowThreadProcessId() will als 1.Parameter das
Fenster-Handle der Opfer-Anwendung. Als 2.Parameter wird ein Pointer
auf ein DWORD übergeben, in dem dann die ID des Threads gespeichert
wird.

Mit der ID ausgerüstet, können wir schließlich ein Handle auf den
Prozess öffnen:

Code:


int main(void)
{
    HWND hWnd;
    HANDLE hproc;
    DWORD procid;

    hWnd = FindWindow(0,"Opfer");
    if(!hWnd)
        return 0;

    GetWindowThreadProcessId(hWnd, &procid);

    hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);

    CloseHandle(hproc);//<-- Wichtig!
    return 0;
}



Mit PROCESS_ALL_ACCESS legen wir fest, daß wir sowohl lesen als auch
schreiben können. Der 2.Parameter muß auf FALSE gesetzt werden.
Als 3.Parameter übergeben wir die gerade ermittelte ID.
Da es sich um ein Windows-Handle handelt, müssen wir es, wenn es nicht
mehr gebraucht wird, wieder mit CloseHandle() freigeben.

Jetzt können wir endlich auf den Speicher zugreifen. *phu*
Für diesen Zweck gibt es ReadProcessMemory() und WriteProcessMemory().
Wenn wir aus dem Speicher lesen wollen, brauchen wir natürlich einen
Puffer der diese Daten aufnimmt. Da wir ja wissen, daß wir eine int-
Variable lesen wollen, ist dieser natürlich auch von Typ int:
int buffer = 0;
Als zweites brauchen wir eine Variable,e die die Speicheradresse
aufnimmt: unsigned adress = 0x00409040; "unsigned" deshalb, weil
es ja keine negativen Adressen gibt. Daher muß diese Variable nie
einen negativen Wert aufnehmen. Durch unsigned wird auch automatisch
der maximale Wert für eine positive Zahl größer.
Hier der neue Code:

Code:


int main(void)
{
    HWND hWnd;
    HANDLE hproc;
    DWORD procid;

    unsigned adress = 0x00409040;
    int buffer = 0;

    hWnd = FindWindow(0,"Opfer");
    if(!hWnd)
        return 0;

    GetWindowThreadProcessId(hWnd, &procid);

    hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);

    CloseHandle(hproc);//<-- Wichtig!
    return 0;
}



So, als erstes wollen wir jetzt mal den Speicher der Opfer-Anwendung
lesen:
ReadProcessMemory(hproc,(LPCVOID)adress, &buffer,sizeof(buffer),&rw);

Der erste Parameter ist unser Handle, der zweite
ist ein const void*-Pointer, auf die Adress-Variabel, der dritte
ist ein Pointer auf den Aufnahmepuffer, im vierten wird die
Größe des Puffers übergeben, während im fünften Para. ein Pointer
auf ein DWORD übergeben wird. Das DWORD enthält nach dem Lesen die
Anzahl der gelesenen Bytes. So unnütz diese Variable hier auch
erscheinen mag, sie muß auf jeden fall vorhanden sein.

Zugriff auf ein Programm Top



Code:


int main(void)
{
    HWND hWnd;
    HANDLE hproc;
    DWORD procid;
    DWORD rw = 0;

    unsigned adress = 0x00409040;
    int buffer = 0;

    hWnd = FindWindow(0,"Opfer");
    if(!hWnd)
        return 0;

    GetWindowThreadProcessId(hWnd, &procid);

    hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);

    if(ReadProcessMemory(hproc,(LPCVOID)adress,&buffer,
                    sizeof(buffer),&rw))
    {
        cout << "Lesen erfolgreich\n";
        cout << buffer;
    }

    CloseHandle(hproc);//<-- Wichtig!
    return 0;
}



Jetzt können wir einfach mal einen Test machen.
1.Opferanwendung starten
2.Sofort danach das Memorytool aufrufen.

Wenn alles glatt geht, müßte in der Konsole dann
Lesen erfolgreich
15
stehen.

So, jetzt wollen wir auch den Speicher verändern.
Dazu brauchen wir keine neuen Variable, auch die
Parameter der WriteProcessMemory()-Funktion sind dieselben
wie die der Read-Funktion. Lediglich der Pointer auf die
Zieladresse ist jetzt nicht mehr const.
Aus diesen Gründen spare ich mir hier mal Erläuterungen und lasse
den Code für sich sprechen:

Wir verändern Werte Top



Code:


int main(void)
{
    HWND hWnd;
    HANDLE hproc;
    DWORD procid;
    DWORD rw = 0;

    unsigned adress = 0x00409040;
    int buffer = 0;

    hWnd = FindWindow(0,"Opfer");
    if(!hWnd)
        return 0;

    GetWindowThreadProcessId(hWnd, &procid);

    hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);

    if(ReadProcessMemory(hproc,(LPCVOID)adress,&buffer,
                    sizeof(buffer),&rw))
    {
        cout << "Lesen erfolgreich\n";
        cout << buffer << endl;
    }
    buffer++;

    if(WriteProcessMemory(hproc,(LPVOID)adress,&buffer,
                    sizeof(buffer),&rw))
    {
        cout << "Schreiben erfolgreich\n";
    }

    CloseHandle(hproc);//<-- Wichtig!
    return 0;
}



Wenn du jetzt den Test nochmal wiederholst, gibt dir das Opfer-Prog
folgende Zeilen aus:

15 0xXXXXXXXXX
16 0xXXXXXXXXX

Ausgabe des Memorytools:

Lesen erfolgreich
15
Schreiben erfolgreich

Ich hoffe, ich konnte dir einigermaßen anschaulich erklären, wie man
auf fremden Speicher zugreifen kann. Fragen, Kritik oder gefundene
Fehler bitte an spam@codecreator.net mailen.

Have Fun!
Thomas

Gibt es noch irgendwelche Fragen, oder wollen Sie über den Artikel diskutieren?

Editieren Versionen Linkpartnerschaft Top Printversion

Haben Sie einen Fehler gefunden? Dann klicken Sie doch auf Editieren, und beheben den Fehler, keine Angst, Sie können nichts zerstören, das Tutorial kann wiederhergestellt werden

Sprachenübersicht/Programmierung/C / C++/ C#/Security/Speicherzugriff Tutorial Teil 1