Laden...

Funktion umbiegen

Erstellt von userid4106 vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.959 Views
U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren
Funktion umbiegen

Hallo,

ich habe mal ein bisschen im Internet nach einer merkwürdigen Sache gesucht.
Beim disassemblieren einer DLL ist mir halt mal aufgefallen, dass im Prologue eine Assembler Instruktion enthalten ist die einem 2Byte NOP sehr ähnlich sieht.



mov edi, edi


Ich bin dann mal irgendwann dahinter gekommen, dass diese no-op während eines HotPatches gegen einen jmp zur gepatchten Funktion ersetzt wird.
Jetzt hab ich also mal versucht da was zu basteln(C++)



void lockUnhandledExceptionFilter()
{
    HMODULE kernel32 = LoadLibraryA("kernel32.dll");
    assert(kernel32);

    if (FARPROC gpaSetUnhandledExceptionFilter = GetProcAddress(kernel32, "SetUnhandledExceptionFilter"))
    {
        unsigned char expected_code[] = {
                                            0x8B, 0xFF, // mov edi,edi
                                            0x55,       // push ebp
                                            0x8B, 0xEC, // mov ebp,esp
                                         };

        // only replace code we expect
        if (memcmp(expected_code, gpaSetUnhandledExceptionFilter, sizeof(expected_code)) == 0)
        {
            unsigned char new_code[] = {
                                            0x33, 0xC0,       // xor eax,eax
                                            0xC2, 0x04, 0x00, // ret 4
                                        };

            //BOOST_STATIC_ASSERT(sizeof(expected_code) == sizeof(new_code));

            DWORD old_protect;
            if (VirtualProtect(gpaSetUnhandledExceptionFilter, sizeof(new_code), PAGE_EXECUTE_READWRITE, &old_protect))
            {
                CopyMemory(gpaSetUnhandledExceptionFilter, new_code, sizeof(new_code));

                DWORD dummy;
                VirtualProtect(gpaSetUnhandledExceptionFilter, sizeof(new_code), old_protect, &dummy);

                FlushInstructionCache(GetCurrentProcess(), gpaSetUnhandledExceptionFilter, sizeof(new_code));

                SetUnhandledExceptionFilter(0);
            }
        }
    }
    FreeLibrary(kernel32);
} 


Nun meine Frage. Wenn ich den Code rennen lasse dann wird auch, wie erwartet, die Instruktionen geändert. Wenn ich allerdings meine Applikation neu starte dann ist wieder der alte Prologue drin. Woran kann das liegen und wie kann ich es realisieren, dass die Instruktionen permanent(also so lange das System läuft) vorhanden sind?
Außerdem würde ich gerne wissen wann das wieder "zurück gestellt" wird. Immer wenn meine Applikation beendet wird oder ist da irgendwo ein Timer der dann als Beispiel alle 2 Sekunden überprüft ob alles ok ist?

309 Beiträge seit 2007
vor 14 Jahren

Ich vermute einmal, wenn deine App. neu startet dass sie auch neu geladen wird ... somit auch die "original"Daten enthält.

**"Zufall ist das Pseudonym Gottes, wenn er nicht selbst unterschreiben will.” **
Anatole France

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren

Hi,
ne..das ist es nicht. Ich überschreibe ja eine Funktion die im kernel32 liegt. Deswegen kann diese überschriebene Funktion ja nicht wieder verschwinden wenn ich das Programm schließe. Also kann es ja schon.
Wenn die Funktion in meiner eigenen Applikation wäre dann könnte ich mir das wohl auch denken;-)
Aber das ist sie ja eben nicht.

Gelöschter Account
vor 14 Jahren

ne..das ist es nicht.

also ich denke schon das es so ist. du lädst die kernel dll in deinen prozess und veränderst das geladene modul aber das kümmert doch nciht die dll die auf der platte liegt? die wird ja jedesmal frisch geladen und entspricht nachwievor dem original.

K
133 Beiträge seit 2009
vor 14 Jahren

Da stimme ich Jack zu. Der kernel32 wird ja in den Speicher deines Programmes geladen ansonsten wäre das komplette "_Sicherheit_skozept" ja für den Eimer?!

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren

Ah..ok..das wusste ich nicht. Jetzt stellt sich aber mir doch die Frage wie Microsoft das macht wenn die ihrer HotPatches einspielen...Denn immerhin mache ich ja nichts anderes als den halben Prologue zu überschreiben. Ob ich jetzt einen jmp mache oder fürs erste einfach nur einen ret ist doch völlig wurscht....

Gelöschter Account
vor 14 Jahren

Jetzt stellt sich aber mir doch die Frage wie Microsoft das macht wenn die ihrer HotPatches einspielen die datei ersetzen?

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren

Dann wäre der NO-OP aber Schwachsinn. Und die werden das bestimmt nicht gemacht haben weil sie gerade Langeweile hatten!

Gelöschter Account
vor 14 Jahren

du könntest auch die datei selbst einfach öffnen und in ihr byte-code einfügen und dann wieder schließen.

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren

Das ist aber nicht das was ich wollte. Ich wollte verstehen wie Microsoft das macht. Also wo da der Trick ist.
Nehmen wir man an ich würde wie in dem Beispiel eine Funktion im Kernel manipulieren. Ich bezweifel das man den "mal eben" öffnen und was rein schreiben kann. Denn immerhin wird die DLL ja "benutzt" bzw ist geladen. SOllte das selbe sein we mit einem laufenden Programm. Das kann man dann doch auch nicht löschen/manipulieren...Oder?(Ohne Trick 17 und von hinten durch die Brust ins Auge)

Gelöschter Account
vor 14 Jahren

wenn du andere programme manipulieren willst, musst du auf dll-injection zurückgreifen.

wenn du systemdll´s manipulieren willst dann ist das einfachste den bytecode direkt zu ändern. alle programme die dann diese dll laden haben dann deine neue funktionalität. deshalb muss man dann auch neu starten, damit sichergestellt ist, das keine alten dll´s geladen sind.

was hotpatching betrifft, so kann ich dir das da empfehlen:API hooking for hotpatchable operating systems

1.130 Beiträge seit 2007
vor 14 Jahren

die datei ersetzen?

das muss man so oder so

Dann wäre der NO-OP aber Schwachsinn. Und die werden das bestimmt nicht gemacht haben weil sie gerade Langeweile hatten!

nö: man halte zuerst alle threads kurz an, ersetze die datei, ersetze dann die nops aller geladenen Versionen der dll und lasse alles wieder laufen.

Wo ist das problem?

Da stimme ich Jack zu. Der kernel32 wird ja in den Speicher deines Programmes geladen ansonsten wäre das komplette "Sicherheitskozept" ja für den Eimer?!

es gibt bestimmt speicherbereiche, die man nicht schreiben aber sehr wohl ausführen kann im usermode (mindestens einen)
wieso sollten sich nicht mehrere theorethisch mehrere prozesse soeinen teilen können?

wenn du systemdll´s manipulieren willst dann ist das einfachste den bytecode direkt zu ändern. alle programme die dann diese dll laden haben dann deine neue funktionalität. deshalb muss man dann auch neu starten, damit sichergestellt ist, das keine alten dll´s geladen sind.

jup, so gehts am einfachsten. allerdings schützt m$ die systemdateien vor unbefugtem zugriff (zumindest die originale)

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

1.361 Beiträge seit 2007
vor 14 Jahren

Hi,

der "Trick" mit den 5 NO-Ops vor der Funktion und dem 2-byte "mov edi,edi" wird ja gut in Jack's Link beschrieben.

Allerdings reicht das allein nicht aus für ein vollständiges Hot-Patching. (Die Änderungen müssen auch persistent auf dem Datenträger gemacht werden)

Dafür spielen verschiedene Operationen mit hinein. Wird im Windows Internals Buch ganz gut aufgelistet.
Ein Auszug aus dem Abschnitt Windows® Internals, Fifth Edition: System Mechanisms > Hotpatch Support kannst du unter eben genanntem Link nachlesen.

beste Grüße
zommi

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren

Coole Sache..Danke:-)

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 14 Jahren

Ich habe die Tage einen sehr interessanten Blog Eintrag gefunden.
Runtime Code Patching - Not for the Faint of Heart

[EDIT=herbivore]Bitte fremde Blog-Einträge nur verlinken, aber nicht als Vollzitat ins Forum kopieren ==> Vollzitat des Blogeintrags entfernt.[EDIT]