Ergebnis 1 bis 4 von 4
  1. #1
    OpCodeKiddy Avatar von EBFE
    Registriert seit
    30.03.2009
    Beiträge
    442

    Standard Universal Decrypter

    Kurze Anmerkung: das Programm hat einen recht spezifischen Anwendungszweck . Muss also nicht jeder verstehen oder sinnvoll finden.
    In erster Linie wurde es für "Learning by doing" geschrieben (bisschen PE Format wiederholen). Weiterhin ein schöner "PoC", dass sehr viele "Crypter" nicht nur komplett auf RunPe-Prinzip basieren, sondern auch nichtmal irgenwelche Änderungen beinhalten.
    Ebfe's universal decrypter
    Sprache: MASM32

    Anwendungszweck: Entpacken von Anwendungen,
    die mit RunPE/CreateProcessEx/LoadExe&CO basierenden Cryptern gepackt wurden.

    getestet: Trojka 2/3, SC Crypter v1
    OSgetestet: Vista SP1, XP SP2/3

    Anleitung:
    Wenn der Dump erfolgreich war, kommt eine Erfolgsmeldung *g*

    Zu beachten:

    a) Es existiert keine Prüfung, ob die Zielanwendung nun wirklich gecryptet ist.
    Es wird einfach drauf los versucht sie zu entpacken. Dafür gibt es zwei Gründe:
    1) der Unpacker ist generisch
    2) Zuverlässige signaturbasierende Cryptererkennung schaffen noch nichtmals AVs *g*

    b) Es sind auf jeden Fall Debugrechte nötig - also als Administrator oder
    entsprechender User starten!

    c)Es kann sein, dass die Stub mehrere Kindprozesse startet (wofür auch immer),
    es werden alle gedumpt und gefixt. Es bleibt dem Anwender überlassen, den "richtigen"
    Dump auszuwählen. Hint: Icon und Dateigröße sollten in 90% aller Fälle eindeutig sein.

    d)Timeout ist relativ hoch gesetzt - sollte etwas schiefgehen, kann es bis zu 20Sek
    dauern, bis eine Meldung kommt.
    Inhalt:
    \readme.txt
    \undecrypt.exe
    \source\dialog.inc
    \source\makeit.bat
    \source\undecrypt.asm

    Zweck: 90% aller "Sczenecrypter" entpacken *g*
    Zu beachten: wer das selbst assemblieren möchte, sollte in der makeit.bat den Pfad anpassen.

    MD5:
    release.zip: 0e122aedb8b23fecaf2008424734fd2d
    http://files.mail.ru/S46EN9
    Geändert von EBFE (08.04.2009 um 17:38 Uhr)

  2. Folgende Benutzer haben sich für diesen Beitrag bedankt:

    l0dsb (18.10.2010), Mofo (16.10.2010), ocz (16.10.2010)

  3. #2
    BackNine Wurm Avatar von Mofo
    Registriert seit
    29.11.2008
    Beiträge
    312

    Standard

    Sry das ich diesen alten Thread wieder hervorhole, aber ich denke er ist noch nicht ganz veraltet

    Mich würde interessieren wie du vorgehst, nicht detailliert, aber ein kurzes résumée wäre toll, denn ich bin noch asm-Anfänger und kann daher deinem Source kaum etwas entnehmen..

    Du ermittelst den Kind-Prozess der fraglichen pe, liest die Peteile aus dem ram und schreibst die 'gedumpte?' pe auf die Platte?
    Geändert von Mofo (16.10.2010 um 20:08 Uhr)




  4. #3
    OpCodeKiddy Avatar von EBFE
    Registriert seit
    30.03.2009
    Beiträge
    442

    Standard

    Es basiert auf der Annahme, dass die üblichen RunPE APIs genutzt werden: CreateProcess, ZwUnmapViewOfSection, WriteProcessMemory, GetThreadContext, SetThreadContext, ResumeThread. Genauer: es hookt die ResumeThread und WriteProcessMemory API. Daher funktioniert es heutzutage nicht mehr wirklich zuverlässig, da viele "C0der" auf "ZwResumeThread" und "ZwWriteProcessMemory" Aufrufe umgestiegen sind


    Zuerst starte ich den Prozess "Suspended":
    Code:
    invoke CreateProcess,file_path,0,0,0,FALSE,CREATE_SUSPENDED,0,0,addr startup,addr proc_info
    Nun nutze ich die Tatsache aus, dass zumindest bis unter Vista die Kernel/NTDLL in allen Prozessen die gleiche Adresse hat und ermittele "WriteProcessMemory" und "ResumeThread" Adressen in der Kernel32.DLL meines Programms (die ich dann auf andere Programme "übertragen" kann). Diese speichere ich (zugegebenermaßen unschönerweise) in EDI / ESI, anstatt extra Variablen dafür anzulegen.

    Nun warte ich in einem Loop:
    Code:
    invoke ResumeThread,proc_info.hThread
    invoke Sleep,1
    invoke SuspendThread,proc_info.hThread
    invoke ReadProcessMemory,proc_info.hProcess,edi,addr temp,1,addr startup
    test eax,eax ;wenn rückgabe=0 dann ist gar nichts verfügbar
    bis die Kernel32.DLL in dem Zielprozess verfügbar ist (EDI enthält dabei die Adresse von ResumeThread API und es wird immer wieder versucht, daraus etwas zu lesen. Sobald das gelingt, heißt es, dass die DLL im anderen Prozess nun verfügbar ist)

    Dann kommt die "Debug" Funktion. Ihr Ziel ist es, die Stub / RUNPE Code solange ausführen zu lassen, bis sie den Code entpackt hat - aber nicht den letzen Schritt (ResumeThread) machen lassen.

    Dafür werden "Breakpoints" aka EBFEs Platziert
    zurst Speicher beschreibbar setzen:
    Code:
    invoke VirtualProtectEx,proc_info.hProcess,edi,4,PAGE_EXECUTE_READWRITE,addr temp
    und dasselbe, nur mit ESI statt EDI als Parameter. Ich errinnere nochmal - unschönerweise nutze ich Register als Variablen (weil ich diese ziemlich oft brauche und weil ich faul bin). ESI == WritePRocessMemory Adresse, EDI == ResumeThread Adresse.
    Ich platziere einen EBFE ähm Breakpoint auf ResumeThread, dann lese ich "Originalbytes" aus der Adresse von ESI==WriteProcessMemory und platziere schließlich auch da einen Breakpoint.

    Code:
    ;BPs platzieren
        invoke WriteProcessMemory,proc_info.hProcess,edi,offset BP1,2,addr temp
        test eax,eax
        jz error
        invoke ReadProcessMemory,proc_info.hProcess,esi,addr orig_bytes,2,addr temp
        test eax,eax
        jz error
        invoke WriteProcessMemory,proc_info.hProcess,esi,offset BP1,2,addr temp
        test eax,eax
        jz error
    Nun warte ich in einer Schleife - einmal pro Sekunde pausiere ich und prüfe, ob das Programm an einem meiner BPs angehalten wurde:

    laufen lassen + anhalten
    Code:
    invoke ResumeThread,proc_info.hThread
    invoke Sleep,1000
    invoke SuspendThread,proc_info.hThread
    nun BPs prüfen:
    Code:
    mov context.ContextFlags,CONTEXT_FULL
    invoke GetThreadContext,proc_info.hThread,addr context
    
           .if context.regEip==edi ;ist EIP==BP Adresse?
             mov eax,base
             jmp @f
           .elseif context.regEip==esi ;WriteProcessMemory
             ;originalbytes scheiben
             invoke WriteProcessMemory,proc_info.hProcess,esi,addr orig_bytes,2,addr temp
             ;Base auslesen:
             mov ecx,context.regEsp
             add ecx,8
             invoke ReadProcessMemory,proc_info.hProcess,ecx,addr base,4,addr temp
    das Prinzip ist simpel - sobald EIP von dem "debuggten" Prozess gleich ESI (== WritePrzessMemory) Adresse ist, weiß ich, dass nun zum ersten mal etwas in den Speicher der Exe geschrieben wird. Dank MSDN weiß ich auch, dass WriteProcessMemory Function (Windows) den lpBase Parameter an 2-ter Stelle hat. Also lese ich den ESP des "debuggten" Prozess aus, addiere eine 8 dazu (damit erhalte ich die Adresse des 2-ten Parameters auf dem Stack, plus 8 muss sein, weil 4 Bytes für Parameter1 draufgehen und 4 Bytes für die Rücksprungadresse) und lese nun die Zieladresse des ersten "WriteProzessMemory" Aufrufs. Und das ist halt in 99,9% aller RunPEs die ImageBase der "gecrypteten" Exe, die gerade geschrieben wird.

    Danach schreibe ich die originalbytes (die für den EBFE "Breakpoint" des WriteProzessMemory überschrieben wurden) und setze den Prozess fort.

    Sobald die EIP von dem "debuggten" Prozess gleich EDI (== ResumeThread) ist, weiß ich, dass der RunPE Code nun alles lauffertig entpackt hat und den Code nun laufen lassen möchte. Damit ist die "Debugfunktion" quasi fertig - und springt zum RET (k.A warum ich das so hässlich gelöst habe, wahrscheinlich stand hier vorher noch irgendeine Fehlerbehandlunsroutine. Solche "hässlichen" Codestellen sind meistens überbleibsel von "Erweiterungen" oder "Codekürzungen" )

    Die Debug-Funktion gibt (in EAX) die "ImageBase" der nun "entcrypteten" Exe zurück.
    Außerdem weiß ich, (solange sie nicht -1 ist), ist alles ok und die Stub hat alles "lauffertig" entcryptet. Nun bräuchte ich nur noch zu dumpen:

    Code:
        ;debugge (lasse die Stub die Anwendung entpacken)
        invoke Debug
        cmp eax,-1
        je quit
        
        ;so, an dieser Position heißt es: Zielanwendung ist entpackt, nun alle kinder dumpen und fixen    
        invoke DumpChildProcess,proc_info.dwProcessId,eax
        quit:
        invoke Terminate_childs
        ret
    DumpChildProzess arbeitet mit CreateSnapshot32 und Process32First um die ganze Prozessliste durchzugehen. Dafür gibt es eher massig Beispiele in vielen Sprachen. Es vergleicht halt die ParentID mit der ID der Anwendung, die wir gereade "Decrypten". Hintergrund: viele Crypter haben ja diesen "integrierten" Bindermechanismus und starten mehrere Prozesse bzw. Trojka Crypter hat aufjedenfall mehrere gestartet und irgenwelche komischen Aktionen gemacht (so genau weiß ich es nun auch nicht mehr).

    Im wesentlichen ruft es "invoke DumpAndFix,base,proc_entry.th32ProcessID" für die Prozesse auf.

    Dessen Aufgabe ist klar . Das Fixen muss sein, da wir den kompletten Speicherblock auf die Platte speichern und dann natürlich die ganzen Sections nicht mehr den FileAlignment haben (und damit verschieben/ändern sich die ganzen RawAddress/RawSize Werte).

    Dazu wird der Prozess geöffnet:
    Code:
        invoke OpenProcess,PROCESS_TERMINATE+PROCESS_VM_READ,FALSE,procid
        test eax,eax
        jz error_c
    und dann versucht, über den PE Header an die ImageSize dranzukommen (um zu wissen, wieviel tatsächlich gedumpt werden muss)
    Code:
        read_pe:
            mov ecx, base
            add ecx, 03ch
            invoke ReadProcessMemory,child_handle,ecx,addr temp,4,addr temp2
            test eax,eax
            jnz @f
    ....
    ....
        add ecx,50h ;image size auslesen
        invoke ReadProcessMemory,child_handle,ecx,addr imagesize,4,addr temp
    Warum hier 03C und 0x50 Werte verwendet werden, sollte aus dem PE-Header Format klar sein


    dann wir der Speicherinhalt ausgelesen (zuerst extra dafür eigener Speicher alloziert):
    Code:
        ;so, nun imagebase vorhanden+imagesize - auslesen und speichern
        invoke VirtualAlloc,NULL,imagesize,MEM_COMMIT,PAGE_READWRITE
        test eax,eax
        jz error_alloc
        mov memory, eax
        invoke ReadProcessMemory,child_handle,base,memory,imagesize,addr temp
    der PE Header des ausgelsenen Prozess wird dann gefixt
    Code:
        ;fixen
        invoke Fix,memory,imagesize
    und anschließend das ganze gespeichert:
    Code:
        invoke CreateFile,offset dump,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,
    (der Loop ist eine quick&dirty Lösung für automatische Namensvergabe bei mehreren Childprozessen... einfach vorstellen als:
    Code:
    i=0
    while fileexist("dump"+str(i)+".exe":
        do i = i+1
    filename = "dump" + str(i) + ".exe"
    Nun noch etwas zum Fix:
    im wesentlichen werden hier die "originellsten" RunPE "Verunstaltungstricks" behandelt. Also 1) wird MZ wieder an den Anfang geschrieben (manche Crypter lassen das Weg bzw überschreiben es)
    2) wird überprüft ob es einen PE Header gibt
    3)in einem Loop werden die SectionHeaders durchlaufen und nun an die Dumpgrößte angepasst. Da wir eine gültige PE-Exe gedumpt haben, können wir davon ausgehen, dass die Sections auch "gültig" im Speicherplatziert waren (also SectionAlignment bzw alle VirtualAddress und VirtualSize Adressen waren ok). Daher brauchen wir auch nur die ganzen RAW Werte auf Virtual umzustellen und sind damit fertig:
    Code:
        fixloop:
          mov eax,[edi].VirtualAddress
          mov [edi].PointerToRawData,eax   
          add edi, sizeof IMAGE_SECTION_HEADER
        loop fixloop
    Geändert von EBFE (16.10.2010 um 21:50 Uhr)
    TrueCrypt/RAR/Zip Passwort vergessen und das Bruten dauert ewig? Oder brauchst du fein abgestimmte Wortlisten? Hilf dir selbst mit WLML - Word List Markup Language
    Gib Stoned/Mebroot/Sinowal und anderen Bootkits keine Chance: Anti Bootkit v 0.8.5

  5. Folgende Benutzer haben sich für diesen Beitrag bedankt:

    Atropos (16.10.2010), Cyber Tjak (17.10.2010), DizzY_D (16.10.2010), GregorSamsa (18.10.2010), Hawkins (16.10.2010), Mofo (16.10.2010), ocz (16.10.2010), Southpark (16.10.2010), Tisschbein (18.10.2010), xeramon (17.10.2010)

  6. #4
    NoClose Wurm
    Registriert seit
    21.03.2008
    Beiträge
    196

    Standard

    Zitat Zitat von EBFE Beitrag anzeigen
    Es basiert auf der Annahme, dass die üblichen RunPE APIs genutzt werden: CreateProcess, ZwUnmapViewOfSection, WriteProcessMemory, GetThreadContext, SetThreadContext, ResumeThread. Genauer: es hookt die ResumeThread und WriteProcessMemory API. Daher funktioniert es heutzutage nicht mehr wirklich zuverlässig, da viele "C0der" auf "ZwResumeThread" und "ZwWriteProcessMemory" Aufrufe umgestiegen sind
    Hier gibt es so ein ähnliches Tool, dass einige Anti-Bypass Methoden integriert hat. Für die meisten RUNPE Anwender sollte es unmöglich sein das zu bypassen:

    hxxp://www.hackhound.org/forum/index.php?topic=20577.0

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •