WriteProcessMemory()



  • Moin, Moin...

    Ich möchte in den Speicherbereich eines Prozesses hineinschreiben bzw. auslesen. Nun benötigt die Funktion WriteProcessMemory() die Base Address des Prozesses. Woher bekomme ich diese Basisadresse?

    Danke im voraus...



  • Das mußt du doch wissen. Wenn du die Adresse garnicht weißt, dann brauchst du die Funktion auch nicht.



  • @MyTurn:

    Wenn ich mit einem Programm den Speicherbereich eines ANDEREN Prozesses bearbeiten möchte(so ähnliche wie Spieletrainer), kenne ich die Adresse nicht automatisch sondern muss sie erst ermitteln, oder etwa nicht?



  • Versuch mal www.codecreator.net, da steht in kleines Tutorial zu dem Thema



  • @Kane:

    Danke für den Link. Das dortige Beispiel arbeitet aber mit einer Adresse, die vom Benutzer eingegeben werden muss.

    Ich möchte jedoch die Basisadresse des Programms automatisch ermitteln lassen. Es muss doch eine API-Funktion geben, die mir die Basisadresse eines laufenden Prozesses(auch eines fremden) ermittelt.

    Ciao...



  • Wenn du die Prozess-ID kennst, kannst du mit CreateToolhelp32Snapshot einiges herausfinden.



  • Hm ok, hier ist eines meiner noch unveröffnetlichen Tutorials:

    Speichertutorial Teil 2 by Thomas Nitschke
    www.codecreator.net
    master@codecreator.net
    Copyright Thomas Nitschke

    Dies ist eine Fortsetzung des ersten "Wie lese ich
    Speicher von fremden Programmen"-Tutorial.
    Viele Leute haben mich gefragt wie man denn den
    Speicherbereich eines Programmes heraus finden
    oder zumindest eingrenzen kann.
    Ich werde hier eine (und mir einzig bekannte)
    Methode vorstellen.
    Als Basis dient dieser etwas abgeänderte
    Code aus dem letzten Tutorial:

    #include <windows.h>
    #include <iostream.h>
    
    typedef unsigned int uint;
    HANDLE hproc;
    DWORD procid;
    
    int main(void)
    {
       HWND hWnd;
    
       hWnd = FindWindow(0,"Opfer");
       if(!hWnd)
           return 0;
    
       GetWindowThreadProcessId(hWnd, &procid);
    
       hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);
    
       CloseHandle(hproc);//<-- Wichtig!
       return 0;
    }
    

    Außerdem benötigen wir wieder unser Opfer-Prog.

    Da ich das Ermitteln des Speicherbereiches nicht auch
    noch in die main() reinquetschen will, schreiben wir
    die Funktion GetMemMinMax():

    #include <windows.h>
    #include <iostream.h>
    
    typedef unsigned int uint;
    HANDLE hproc;
    DWORD procid;
    void GetMemMinMax(void);
    
    int main(void)
    {
       HWND hWnd;
    
       hWnd = FindWindow(0,"Opfer");
       if(!hWnd)
           return 0;
    
       GetWindowThreadProcessId(hWnd, &procid);
       hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);
       GetMemMinMax();
       CloseHandle(hproc);//<-- Wichtig!
       return 0;
    }
    
    void GetMemMinMax(void)
    {
       //hier speicherbereich bestimmen
    }
    

    Infos über den Speicherbereich erhalten wir mit der
    Funktion VirtualQueryEx(). Sie braucht als Parameter
    das Processhandle, die Adresse,
    einen Pointer auf die MEMORY_BASIC_INFORMATION-Struktur,
    und die Größe dieser Struktur.
    Die MEMORY_BASIC_INFORMATION-Struktur sieht so aus:

    struct _MEMORY_BASIC_INFORMATION {
        PVOID BaseAddress;
        PVOID AllocationBase;
        DWORD AllocationProtect;
        DWORD RegionSize;
        DWORD State;
        DWORD Protect;
        DWORD Type;
    } MEMORY_BASIC_INFORMATION;
    

    BaseAdress speichert die Anfangsadresse der
    Speicherregion während RegionSize die Größe dieser
    Speicherregion speichert. Der Bereich geht also
    von BaseAdress bis BaseAdress+RegionSize.
    Alles was wir jetzt machen ist in einer
    Schleife immer mit VirtualQueryEx() uns
    a) die Größe des Speicherbereichs zuholen
    b) Prüfen ob er zu dem Programm gehört
    c) Beim nächtsten Bereich weitermachen
    Als Code sähe das ungefährt so aus:

    MEMORY_BASIC_INFORMATION mbi;
    unsigned int adress = 0x400000;
    do
    {
       VirtualQueryEx(hproc,(void*)adress,
       &mbi,sizeof(MEMORY_BASIC_INFORMATION));
    
       adress += mbi.RegionSize;
    } while(adress < 0x80000000);
    

    Jetzt müssen wir nur noch überprüfen ob der
    Speicherbereich zu unserem Programm gehört und ob er
    mit Dingen "gefüllt" ist die wir brauchen.
    Es kann nämlich auch sein, das wir auf den
    Speicher stoßen in dem der Programmcode unseres
    Zielprogs liegt! Für Virencoder sicherlich
    interessant, aber wir begnügen uns jetzt mal
    mit dem Verändern der Werte.
    Um zu überprüfen ob das "unser" Speicher ist,
    müssen wir uns die State-Variable der
    MEMORY_BASIC_INFORMATION-Struktur anschauen.
    Ist sie == MEM_COMMIT, gehört der Speicher uns.
    Danach müssen wir noch darauf achten das
    wir nicht Programmcode oder andere Sachen
    gefunden haben. Das kann man mit der
    Protect-Variable überprüfen. Normale Variablen
    kann man ja sowohl auslesen als auch schreiben,
    also ist der gesuchte Wert: PAGE_READWRITE
    Als zusätzliche Sicherheit überprüfe ich
    noch die Type-Variable, die sollte immer == MEM_PRIVATE
    sein. Hier ist der erweiterte Code:

    void GetMemMinMax(void)
    {
       MEMORY_BASIC_INFORMATION mbi;
       unsigned int adress = 0x400000;
       do
       {
          VirtualQueryEx(hproc,(void*)adress,
          &mbi,sizeof(MEMORY_BASIC_INFORMATION));
    
          if((mbi.State == MEM_COMMIT)&&
             (mbi.Protect == PAGE_READWRITE)&&
             (mbi.Type == MEM_PRIVATE))
          {
             uint start = (uint)mbi.BaseAddress;
             uint end = (uint)mbi.BaseAddress+mbi.RegionSize;
    
             cout << "Bereich: " << hex << start << " - "
                 << hex << end;
          }
    
          adress += mbi.RegionSize;
       } while(adress < 0x80000000);
    }
    

    In der start und end Variable wird jeweils die
    Anfangs und Endadresse des Bereich gespeichert.
    So, jetzt können wir also nach unseren
    Speicherbereichen suchen! Ob der gesuchte Wert
    darin enthalten ist, müssen wir noch prüfen.
    Dazu schreibe ich wieder eine neue Funktion mit
    Namen ScanMem():

    void ScanMem(DWORD start, DWORD end)
    {
       cout << "Bereich wird gescannt...\n";
       DWORD read = 0;
       uint buffer = 0;
       for(start;start<end;start++)
       {
          ReadProcessMemory(hproc,(void*)start,&buffer,
                      sizeof(uint),&read);
          if(buffer == 15)
          {
             cout << "Wert an " << hex << start << " gefunden!";
             char choice;
             cout << "Abbrechen? [j,n]";
             cin >> choice;
             if(choice == 'j')
                return;
          }
       }
       return;//nichts gefunden
    }
    

    Wenn das Programm den Wert gefunden hat,
    wird der User gefragt ob weiter gesucht werden
    soll. Man kann nämlich immernoch nicht sicher
    sein ob dieser Wert DIE gesuchte Variable ist.
    Hier ist ScanMem() bereits in die Schleife eingebaut:

    do
       {
          VirtualQueryEx(hproc,(void*)adress,
          &mbi,sizeof(MEMORY_BASIC_INFORMATION));
    
          if((mbi.State == MEM_COMMIT)&&
             (mbi.Protect == PAGE_READWRITE)&&
             (mbi.Type == MEM_PRIVATE))
          {
             uint start = (uint)mbi.BaseAddress;
             uint end = (uint)mbi.BaseAddress+mbi.RegionSize;
    
             cout << "Bereich: " << hex << start << " - "
                 << hex << end;
    
             ScanMem(start,end);
          }
    
          adress += mbi.RegionSize;
       } while(adress < 0x80000000);
    

    Hier vollständigkeitshalber
    nochmal der gesamte Programmcode:

    #include <windows.h>
    #include <iostream.h>
    
    typedef unsigned int uint;
    
    void GetMemMinMax(void);
    void ScanMem(DWORD start, DWORD end);
    
    HANDLE hproc;
    DWORD procid;
    
    int main(void)
    {
       HWND hWnd;
    
       hWnd = FindWindow(0,"Opfer");
       if(!hWnd)
           return 0;
    
       GetWindowThreadProcessId(hWnd, &procid);
       hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);
       GetMemMinMax();
       CloseHandle(hproc);//<-- Wichtig!
       return 0;
    }
    
    void GetMemMinMax(void)
    {
       MEMORY_BASIC_INFORMATION mbi;
       unsigned int adress = 0x400000;
       do
       {
          VirtualQueryEx(hproc,(void*)adress,
          &mbi,sizeof(MEMORY_BASIC_INFORMATION));
    
          if((mbi.State == MEM_COMMIT)&&
             (mbi.Protect == PAGE_READWRITE)&&
             (mbi.Type == MEM_PRIVATE))
          {
             uint start = (uint)mbi.BaseAddress;
             uint end = (uint)mbi.BaseAddress+mbi.RegionSize;
    
             cout << "Bereich: " << hex << start << " - "
                 << hex << end;
    
             ScanMem(start,end);
          }
    
          adress += mbi.RegionSize;
       } while(adress < 0x80000000);
    }
    
    void ScanMem(DWORD start, DWORD end)
    {
       cout << " Bereich wird gescannt...\n";
       DWORD read = 0;
       int buffer = 0;
       for(start;start<end;start++)
       {
          ReadProcessMemory(hproc,(void*)start,&buffer,
                      sizeof(int),&read);
          if(buffer == 15)
          {
             cout << "Wert an " << hex << start << " gefunden!";
             char choice;
             cout << "Abbrechen? [j,n]";
             cin >> choice;
             if(choice == 'j')
                return;
          }
       }
       return;//nichts gefunden
    }
    

    Machen wir einen Testlauf! Wenn alles klappt, steht in
    der Konsole:
    Bereich: 408000 - 40d000 Bereich wird gescannt...
    Wert an 409040 gefunden! Abbrechen? [j,n]

    Und *täterätä* die Adresse stimmt!!!
    Ich hoffe, das damit die meisten Fragen was
    Speicherbereiche angeht beantwortet sind.
    Falls ihr Kritik, Anregungen oder Fragen habt,
    schickt eine Mail an master@codecreator.net!
    Viel Spaß!

    Es ist deshalb noch nicht online weil ich
    a) zu faul bin die Site zu aktualisieren und
    b) weil ich es noch nicht auf Korrektheit hin überprüft habe

    Ist also mit Vorsicht zu genießen

    [ Dieser Beitrag wurde am 04.01.2003 um 11:14 Uhr von cd9000 editiert. ]



  • @Kane:

    Herzlichen Dank für das Tut. Werde das mal ausprobieren.

    Ciao...



  • Argh.. ich hab' die Codetags vergessen 🙄

    Naja, ich hoffe man kann es trotzdem lesen.



  • Da du registriert bist, kannst du deine Beiträgt editieren, um z.B. Codetags hinzuzufügen. 🙂



  • Hey cool, thx cd!
    Ich denk mal wieder viel zu kompliziert... 😃


Anmelden zum Antworten