SMC



  • Wo finde ich den Infos zu Self-Modifying-Code? Wie genau funktioniert das ganze, etc.?



  • Ich glaube selbstmodifizierender Code hat kein bestimmtes Verfahren. Der Trick besteht halt einfach dadrin, Daten ins Codesegment zu schreiben an Stellen, wo ab und zu auch mal ausgeführt wird.
    Die Frage ist, wo du das nutzen willst. In jedem modernen Betriebssystem sind schreibzugriffe auf Codestücke nämlich verboten und führen nur zu ner Schutzverletzung 🙂



  • hmm, man kann doch auch zeugs von außerhalb des codesegments ausführen. sonst würde kein verdammter jitter funzen. bsp.:

    const char c = '\xC3';
    ((void (*)(void)) &c)();
    

    sowas ähnliches funzt (auf meinem x86).

    [ Dieser Beitrag wurde am 05.09.2002 um 16:04 Uhr von Mr. n editiert. ]



  • Was ist Jitter? 😕

    lg, phreaking



  • Original erstellt von phreaking:
    **Was ist Jitter? 😕
    **

    *kopfschüttel*
    JITter = JIT-Compiler = Just-In-Time-Compiler, kompiliert erst kurz vor der Ausführung in Maschinencode. Meistens wird eine IL (Intermediate Language) verwendet. Bsp.:
    C#-Code => MS-IL (on-run: )=> Maschinencode
    oder aber
    Perl6 => Parrot-Bytecode => Ausführen | Jittern

    [ Dieser Beitrag wurde am 05.09.2002 um 19:20 Uhr von Mr. n editiert. ]



  • *kopfschüttel*

    Sorry, ich bin eben ein Unwissender 😞
    Trotzdem noch eine Frage: Was sind die Besonderheiten einer IL (außer der Zeit, zu der die Kompilierung stattfindet)?

    lg, phreaking

    [ Dieser Beitrag wurde am 05.09.2002 um 19:43 Uhr von phreaking editiert. ]



  • ich weiß ja auch das wichtige nicht (nur solcche sachen eben)... *g*
    die Intermediate Language hat die Besonderheit: sie ist schnell zu kompilieren (meistens eine recht einfache, bytecode-basierte "sprache"). sie wird eingesetzt, da mit ihr eine datei auf mehreren plattformen ausgeführt werden kann.



  • also smc funktioniert auch auf PMode Betriebssystemen. Zumindest wird es nicht direkt durch PMode unmöglich.
    Mensch kann zwar keine Daten in ein Codesegment schreiben, aber niemand verbietet einem einen Daten-Deskriptor (mit schreibrechten) für den Selben Speicherbereich zu erstellen.
    im Realmode (und v86?) ist das aber viel einfacher, da es halt keine Rechtebeschränkung gibt. Ich hab das aber auch erst einmal in einer Platzoptimierten routine genutzt, die ein paar daten tauscht:

    ;mkGDTE v0.002
    ; make Global Descriptor Table Entry
    ; for RealMode on x86
    ;
    ;
    ;
    
    ;         +--------+--------+
    ; SP + 01 |  AVL   | N286C. |  SP+ 00  Vaiable & non286compatible
    ;         +--------+--------+
    ; SP + 19 | Gran.  | SegType|  SP+ 18  granularity
    ;         +--------+--------+
    ; SP + 17 | Present|  DPL   |  SP+ 16
    ;         +--------+--------+
    ; SP + 15 | SegBaseAddr (h.)|  SP+ 14
    ;         +--------+--------+
    ; SP + 13 | SegBaseAddr (l.)|  SP+ 12
    ;         +--------+--------+
    ; SP + 11 |00000000| SegSize|  SP+ 10 <-- high
    ;         +--------+--------+
    ; SP + 09 | SegSize (low)   |  SP+ 08
    ;         +--------+--------+
    ; SP + 07 | GDT ptr (high)  |  SP+ 06
    ;         +--------+--------+
    ; SP + 05 | GDT ptr (low)   |  SP+ 04
    ;         +--------+--------+
    ; SP + 03 | retAddr (Segm.) |  SP+ 02
    ;         +--------+--------+
    ; SP + 01 | retAddr (offS.) |  SP+ 00
    ;         +--------+--------+
    ;
    
    ;
    mkGDTE:
    pop dword [retAddr]                ;smc trick to simiulate a ret with a jmp
                                       ;now we can pop other values and won't
    ;jmp quit                                   ;need to buffer them in regs
                                       ;
    pop di                             ;lets make a ptr. to
    pop es                             ;our destination ;)
    
    pop word [es:di  ]                 ;pop&store SegSize (low)
    
    pop word [es:di+6]                 ;pop&store SegSize (high)
    
    pop word [es:di+2]                 ;pop&store SegBaseAddr (low)
    
    pop word ax                        ;pop SegBaseAddr (high)
    mov ah, [es:di+7]                 ;store high byte of SegBaseAddr (high)
    mov al, [es:di+4]                 ;store low  byte of SegBaseAddr (high)
    
    pop bx                             ;DPL in bl & Present in bh
     shl bl, 6
     shl bx, 6
    pop ax                             ;SegType in al & Gran. in ah
     or  bh, al                        ;integrate Segtype in bh
     shl bh,  1
    mov bh,[es:di+5]                   ;store DPL&Co. (one byte)
    
    pop bx                             ;AVL in bl & N286C in bh
     shl ah,  1
     or  ah, bh                        ;integrate N286C in ah
     shl ah,  2
     or ah, bl                         ;integrate AVL
     shl ah, 4                         ; low Nibble of ah should be 0
    or ah,[es:di+6]
    
    quit:
    
    db 0xEA                            ;Hard Code for a non-relative far JMP
    retAddr dd 0
    

    der pop am Anfang trägt automatisch unten die Rücksprungadresse ein.



  • wieso muss es eigentlich der Code-Bereich sein?



  • wieso muss es eigentlich der Code-Bereich sein?

    Wie meinen? In einem Daten-Segment (sprich mit dem Descriptor des selben) kannst Du im protected mode keinen code ausfuehren, das gibt eine exception. 😕



  • das seh ich anders, oder was bedeutet das hier:

    //the probably most obfuscating way to print "2" on i386+ machines with MSVC
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef void (*nfp_t)(void);
    
    int main(int argc, char* argv[])
    {
    #pragma warning(disable: 4305 4309)
        char jf[] = { 
            0x42, 0xC3
        };
        int t;
        nfp_t jf2;
    
        jf2 = (void (*)()) malloc(2);
        memcpy((void *) jf2, jf, 2);
        __asm {
            mov edx, 0
        }
        ((nfp_t) (void *) jf)();
        jf2();
    
        __asm {
            mov t, edx
        }
    
        printf("%d\n", t);
    
        return 0;
    }
    


  • ich nehm mal an, 0x42, 0xC3 stellt den Opcode "mov edx, 42h" dar, ja?
    und das funktioniert also so? ausprobiert? erstaunlich!



  • und wo ist das "ret" ????



  • 0x42 0xC3 bedeutet:

    inc edx
    ret 0
    


  • ok.
    Und funktioniert der Code nun, oder nicht?



  • ich hab des schon 20 mal und in verschiedenen variationen ausgeführt. JA!



  • das seh ich anders, oder was bedeutet das hier

    Fakt ist, dass sich ein Segment, in das geschrieben werden kann nicht ausfuehren laesst.
    Wahrscheinlich wird fuer den Aufruf von jf2 ein neuer "Code"-Descriptor erstellt, der auf die gleiche Speicherstelle zeigt, in die vorher geschrieben wurde. (vielleicht auch nochmal -bg-s Beitrag durchlesen, er hat das praktisch auch schon geschrieben 😉 )



  • hmm, irgendwie find ich das immer noch etwas merkwürdig:

    24:       ((nfp_t) (void *) jf)();
    00401064 8D 45 FE             lea         eax,[ebp-2]
    00401067 8B F4                mov         esi,esp
    00401069 FF D0                call        eax
    0040106B 3B F4                cmp         esi,esp
    0040106D E8 CE 22 00 00       call        __chkesp (00403340)
    25:       jf2();
    00401072 8B F4                mov         esi,esp
    00401074 FF 55 F4             call        dword ptr [ebp-0Ch]
    00401077 3B F4                cmp         esi,esp
    00401079 E8 C2 22 00 00       call        __chkesp (00403340)
    


  • kommt zwar etwas verzögert, aber jetz weiß ihc, _warum_s geht:

    The idea behind: There is a syscall sys_mprotect which allows a program to change the flags for (nearly) every page (i only tested pages in the section .bss). A page is the smallest memory unit available for virtual memory management. On the x86 architecture this page is 4KB. But as i noticed we didn't need this call to make a page in the section .bss executable, because on x86 a readable page is also a executable page, and the section .bss is read/write.

    aus http://linuxassembly.org/articles/smc.html



  • Das interessante bei dem obfuscated-2-Programm ist übrigens, dass es nur funktioniert, wenn man VC auhc ein Release erstellen lässt. Im Debug-Modus bekommt man nämlich nicht 2 sondern 1245054 wiel da ja die ursprünglichen Registerbelegungen nicht so ganz stimmen (sprich edx ist vorher nicht 0) 🙂

    [ Dieser Beitrag wurde am 27.09.2002 um 13:56 Uhr von TriPhoenix editiert. ]


Anmelden zum Antworten