ReadProcessMemory Implementierung



  • Hallo !
    Ich arbeite gerade an meinem Anti-Anticheat Framework für Spiele.
    Da es Anticheats gibt, die recht aggressive API-Funktionen hooken, habe ich es mir in den Kopf gesetzt ReadProcessMemory selbst zu implementieren.

    Erstmal vorneweg, es wird kein Weg daran vorbei gehen einen Kerneltreiber zu schreiben, richtig?

    Nun gut, ich habe mal IDA geöffnet und kernel32.dll importiert um zu sehen was intern passiert. Zu meiner Überraschung sah es so aus:

    .text:7DD89D55 ; BOOL __stdcall ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead)
    .text:7DD89D55                 public ReadProcessMemory
    .text:7DD89D55                 mov     edi, edi
    .text:7DD89D57                 push    ebp
    .text:7DD89D58                 mov     ebp, esp
    .text:7DD89D5A                 pop     ebp
    .text:7DD89D5B                 jmp     ReadProcessMemory_0
    .text:7DD89D5B ReadProcessMemory endp
    

    Gut, also wird einfach nur eine andere Funktion namens ReadProcessMemory_0 aufgerufen. Ich bin gleich mal zu dieser gesprungen, diese scheint aber nur zu einer anderen Funktion weiterzuspringen:

    jmp     ds:__imp_ReadProcessMemory_0
    

    Jetzt ist meine Frage, wo kann ich kann ich die Implementierung dieses Imports finden? IDA zeigt zumindest den Import aus API-MS-Win-Core-Memory-L1-1-0, laut meinen Recherchen sind das aber nur Dummy-Funktionen die während der Laufzeit ersetzt werden. Wo sind dann dann die Originalkernelfunktionen ?

    Habe mich noch nicht so wirklich mit den "Tiefen" von Windows auseinandergesetzt. 🙂

    Grüße,
    Flo



  • BOOL
    WINAPI
    ReadProcessMemory(
        HANDLE hProcess,
        LPCVOID lpBaseAddress,
        LPVOID lpBuffer,
        DWORD nSize,
        LPDWORD lpNumberOfBytesRead
        )
    {
        NTSTATUS Status;
    
        Status = NtReadVirtualMemory(
                    hProcess,
                    (PVOID)lpBaseAddress,
                    lpBuffer,
                    nSize,
                    lpNumberOfBytesRead
                    );
    
        if ( !NT_SUCCESS(Status) ) {
            BaseSetLastNTError(Status);
            return FALSE;
            }
        else {
            return TRUE;
            }
    }
    

    ^^ das original sieht etwa so aus. NtReadVirtualMemory macht dann:

    ...
    //
            // Reference the target process.
            //
    
            Status = ObReferenceObjectByHandle(ProcessHandle,
                                               PROCESS_VM_READ,
                                               PsProcessType,
                                               PreviousMode,
                                               (PVOID *)&Process,
                                               NULL);
    
            //
            // If the process was successfully referenced, then attempt to
            // read the specified memory either by direct mapping or copying
            // through nonpaged pool.
            //
    
            if (Status == STATUS_SUCCESS) {
    
                Status = MmCopyVirtualMemory(Process,
                                             BaseAddress,
                                             PsGetCurrentProcess(),
                                             Buffer,
                                             BufferSize,
                                             PreviousMode,
                                             &BytesCopied);
    
                //
                // Dereference the target process.
                //
    
                ObDereferenceObject(Process);
            }
        }
    ...
    

    🙂



  • Danke fricky. 😉



  • Hallo Icematrix

    Wenn ich das richtig verstanden habe magst du die gegebene ReadProcessMemory Funktion nicht und wolltest dir deswegen eine Eigene schreiben die freundlicher ist.
    Nun würde mich mal interessieren, ob du es denn geschaft hast, und ob du uns/mir dein Ergebnis mitteilen würdest?

    Toll fände ich ja so ein Funktion wie:

    cli::array<System::Byte ^, 1> ^ System::Diagnostics::Process::GetMemory(System::IntPtr ^process, System::IntPtr ^baseAddress, System::Int64 ^range)
    

    Und das ohne irgendwelchen access und privilege Blödsinn aber sowas behält Microsoft warscheinlich für sich.
    Ich könnt mir das auch als eine property von der Klasse ProcessModule vorstellen.
    Vielleicht ist ein Byte-Array auch nicht der beste Typ als Rückgabewert. Das ganze vielleicht variabel machen, so a la template nur halt als CLI.

    Sorry, ich träume schon wieder.

    MfG

    Mumpitz



  • Mumpitz schrieb:

    Toll fände ich ja so ein Funktion wie:

    cli::array<System::Byte ^, 1> ^ System::Diagnostics::Process::GetMemory(System::IntPtr ^process, System::IntPtr ^baseAddress, System::Int64 ^range)
    

    Wenn Du sie bitte noch entschlüsseln würdest?


  • Mod

    Übersetzt: Er möchte die Funktion direkt in .NET haben.



  • Wenn ich das richtig verstanden habe magst du die gegebene ReadProcessMemory Funktion nicht und wolltest dir deswegen eine Eigene schreiben die freundlicher ist.
    Nun würde mich mal interessieren, ob du es denn geschaft hast, und ob du uns/mir dein Ergebnis mitteilen würdest?

    Uhm, ich finde die Funktion der WinAPI durchaus gut so.
    Aber da ich neuerdings ein 64-bit Windows habe ist mein Interesse am Schreiben von Kerneltreibern deutlich gesunken 😉



  • hi Icematrix,
    geht es hier um GameGuard?
    Normal kann man einfach nen +5 byte jump machen aber bei kernel Funktionen geht das leider nicht wie du erkannt hast, weil es die Funktionen im Kernel nochmal hookt. Fragt sich nur wie das auf nem 64 bit windows geblockt wird? Und wie willst du die ganze Funktion neu implementieren? Auf jeden Fall kann man den Speicher lesen, wenn man eine DLL injected und in dieser mit pointer auf die adressen zugreift.


Anmelden zum Antworten