IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

Gestionnaire SEH avec fs:[0] qui ne marche pas en C++


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut Gestionnaire SEH avec fs:[0] qui ne marche pas en C++
    Bonjour,

    J'ai codé en ASM un petit shellcode qui :

    1/ patch l'adresse du SEH handler dans la stack
    2/ créé une exception div par 0
    3/ gère l'exeption et modifie le registre EIP pour sauter après le div
    4/ recharge le context pour que l'execution du prog continue après le div tranquillement

    Quand je compile le shellocode sous MASM32, il marche très bien (vérifié sous olly).

    Parcontre quand je le compile avec VisualStudio 2008 dans une dll en cpp, il bloque sur l'exception. Pourtant le SEH handler est bien patché dans la stack.

    /!\ Je ne veux pas utiliser try et catch en cpp !
    Je veux juste comprendre pourquoi je n'arrive pas à gérer mon exception quand c'est compilé avec VisualStudio.

    Quelqu'un peut m'éclairer s.v.p ? C'est important. Merci d'avance

    Voici mon shellcode en hexa :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EB195E64A10000000083C00489306633C066F7F0E80D000000EB15E8E2FFFFFF8B4C240CEBEE5E89B1B800000033C0C3
    Shellcode en ASM :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     jmp short _seh_handler
    _code:
       pop esi
       mov eax ,dword ptr  fs:[0]
       add eax, 4
       mov [eax], esi                                     ; patch le SEH handler
     
       xor  ax, ax                                          ; créé une exeption div par 0
       div ax
     
    _new_eip:
       call _eip
       jmp _end
     
    _seh_handler:
       call _code
     
       mov ecx, [esp+0Ch]                             ; ecx = adresse de la structure CONTEXT
       jmp short _new_eip
    _eip:
       pop esi
       mov dword ptr [ecx+0B8h], esi               ; on va donc modifier eip pour sauter par dessus l'exception
       xor eax, eax                                        ; recharge le context
       retn
    _end:
    Mes options de compilation dans VisualStudio :
    /O2 /Os /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "MaLib_EXPORTS" /D "_WINDLL" /D "_MBCS" /FD /EHa /MT /GS- /Zc:wchar_t- /Zc:forScope- /GR- /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /nologo /c /Gd /TP /errorReport:prompt
    Et du Linker:
    /OUT:"C:\MaLib.dll" /INCREMENTAL:NO /NOLOGO /DLL /MANIFEST:NO /DEF:"exports.def" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /ENTRY:"DllMain" /DYNAMICBASE:NO /MACHINE:X86 /ERRORREPORTROMPT ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib

  2. #2
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Bonjour,

    a priori, je ne vois rien qui cloche dans ton code...

    Quelques petits détails tout de même, au cas où:

    1) Plutôt que de faire des CALLs + JMPs pour obtenir des adresses de labels (c'est difficile à lire sinon) tu peux faire :

    - mov r32, offset label
    - lea r32, label

    le même code :

    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    _code:
        lea esi, _seh_handler
        mov eax ,dword ptr  fs:[0]
        add eax, 4
        mov [eax], esi                                     
     
        xor  ax, ax                                        
        div ax
     
        ret
     
    _seh_handler:
        mov ecx, [esp+0Ch]                             
        lea esi, _end
        mov dword ptr [ecx+0B8h], esi               
        xor eax, eax                                
        retn
    _end:

    2) Patcher l'adresse du dernier SEH en cours me parait étrange. Pourquoi ne pas construire un SEH pour la procédure (fonction) en cours ?

    3) l'adresse de "rétablissement" - à savoir CONTEXT.EIP - dans le SE handler pointe sur _end:. Hors on ne sait pas ce qui est exécuté après ce label.

    4) Au cas où... Si tu debug avec olly, es-tu sur de passer l'exception au programme plutôt que de la faire gérer par olly? => SHIFT + F9 avec un BP sur le code situé au label _end:

    Au pire, essaye d'uploader ton code où les binaires en questions sur le forum, on pourra toujours y jeter un coup d'œil.

    P.S: A titre d'exemple, voilà le type de code que j'utilise pour gérer les exceptions en asm avec MASM:

    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    .code
    start:
    	push offset SEHandler
    	push dword ptr fs:[0]
    	mov dword ptr fs:[0], esp
     
    	xor eax, eax
    	div eax ; oops!
     
    	@@safe_code:
    	nop
    	nop
    	nop
     
    	pop dword ptr fs:[0]
    	add esp,4h
    	ret 
     
    ;##########################################################################
    SEHandler proc C lpExcept:DWORD, lpFrame:DWORD, lpContext:DWORD, lpDispatch:DWORD
    	mov	eax, [lpExcept] ; EXCEPTION_RECORD
    	mov	ecx, [lpContext] ; CONTEXT
     
    	push @@safe_code ;adresse de rétablissement. Habituellement plutôt vers une proc qui prend la main et essaye de faire tourner le prog normalement.
    	pop [ecx][CONTEXT.regEip]
     
    	;logging d'exception si besoin est.
     
    	xor	eax, eax
    	ret
    SEHandler endp
    ;##########################################################################
     
    end start

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Salut Neitsa ! Merci pour ta réponse

    1) Je fais des CALLS et JMPS pour faire un shellcode.
    Le mov ou lea fait des adresses en dur...

    2) Oui, enfaite j'ai essayé les 2 methodes, patcher le dernier SEH en cours et construire un nouveau SEH.

    3) C'est volontaire le eip sur _end. C'est pour posé un BP après le _end et voir si tout c'est bien passé.

    4) J'ai coché dans Olly "Ingnore Integer division by 0".

    Donc j'ai fais un nouveau shellcode qui construit un nouveau SEH :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EB1D5E5664FF3500000000648925000000006633C066F7F0E80D000000EB15E8DEFFFFFF8B4C240CEBEE5E89B1B800000033C0C3
    Et voici un binaire compilé avec VisualStudio 2008:
    http://rapidshare.com/files/260027389/VmDetect.exe.html

    Essaie de copié le shellcode à l'entrypoint et de posé un BP après le _end.
    Chez moi, le SEH est bien construit mais ça bloque sur le div ax, ax...

  4. #4
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Hello,

    Pour le premier point, je suis désolé, j'avais un peu mis de coté que c'était pour un shellcode et forcément les adresses hardcodées, ça le fait moins ...

    En essayant ton binaire, j'ai tout de suite compris de quoi il retournait.

    Par défaut les binaires compilés sous VC++ 2008 sont compilés avec un mécanisme de protection appelé SafeSEH (il faut explicitement passer le switch /SAFESEH:NO pour ne pas avoir cette protection).

    Pour résumer, les binaires compilés avec cette option dispose d'une liste de SEH enregistrées en dur dans le binaire, et tout SEH qui n'en fait pas partit est considéré comme malveillant et donc n'est jamais appelé par le système.

    C'est une bonne protection, dans le sens où, pour un stack overflow, on dispose généralement de deux possibilités, sauf cas très particuliers:

    1) Ecraser une adresse de retour.
    2) Ecraser une adresse de SEH.

    Avec cette protection, l'écrasement de SEH devient impossible puisqu'il est interdit d'appeler un SEH spécialement mis sur la pile...

    Il existe des moyens "d'évasions", mais dans ton cas, c'est impossible puisque tu cherches à mettre toi-même ton propre SEH. Comme il ne fait pas parti des SEH dûment enregistrés dans le binaire, ça ne fonctionne pas.

    -----------------

    Pour ton programme VMDetect.exe, tout les binaires dans l'espace d'adressage du processus sont protégés via SAFESEH:

    /SafeSEH Module Scanner
    SEH mode Base Limit Module version Module Name
    /SafeSEH ON 0x400000 0x409000 1, 0, 0, 1 C:\Work\Reverse\temp\VmDetect.exe
    /SafeSEH ON 0x76390000 0x763ad000 5.1.2600.5512 (xpsp.080413-2105 C:\WINDOWS\system32\IMM32.DLL
    /SafeSEH ON 0x77c10000 0x77c68000 7.0.2600.5512 (xpsp.080413-2111 C:\WINDOWS\system32\msvcrt.dll
    /SafeSEH ON 0x77dd0000 0x77e6b000 5.1.2600.5755 (xpsp_sp3_gdr.090 C:\WINDOWS\system32\ADVAPI32.dll
    /SafeSEH ON 0x77e70000 0x77f02000 5.1.2600.5795 (xpsp_sp3_gdr.090 C:\WINDOWS\system32\RPCRT4.dll
    /SafeSEH ON 0x77f10000 0x77f59000 5.1.2600.5698 (xpsp_sp3_gdr.081 C:\WINDOWS\system32\GDI32.dll
    /SafeSEH ON 0x77f60000 0x77fd6000 6.00.2900.5512 (xpsp.080413-210 C:\WINDOWS\system32\SHLWAPI.dll
    /SafeSEH ON 0x77fe0000 0x77ff1000 5.1.2600.5753 (xpsp_sp3_gdr.090 C:\WINDOWS\system32\Secur32.dll
    /SafeSEH ON 0x78520000 0x785c3000 9.00.21022.8 C:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375\MSVCR90.dll
    /SafeSEH ON 0x785e0000 0x786fd000 9.00.21022.08 C:\WINDOWS\WinSxS\x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_a173767a\mfc90.dll
    /SafeSEH ON 0x7c800000 0x7c8f6000 5.1.2600.5781 (xpsp_sp3_gdr.090 C:\WINDOWS\system32\kernel32.dll
    /SafeSEH ON 0x7c900000 0x7c9b2000 5.1.2600.5755 (xpsp_sp3_gdr.090 C:\WINDOWS\system32\ntdll.dll
    /SafeSEH ON 0x7e410000 0x7e4a1000 5.1.2600.5512 (xpsp.080413-2105 C:\WINDOWS\system32\USER32.dll
    Pour savoir si un module est protégé, il faut parser le PE et trouver l'IMAGE_OPTIONAL_HEADER, et notamment la table des IMAGE_DATA_DIRECTORY.

    la table à l'index 10 (indexée à partir de 0) est située la table IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG :

    DataDirectory[10] - IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
    (+0xB0) VirtualAddress: 0x00003740
    (+0xB4) Size: 0x00000040
    Dans cette table on trouve les champs suivant:

    Structure for Load Config
    Starting at: 0x00403740
    (+0x00) Characteristics: 0x00000048
    (+0x04) TimeDateStamp: 0x00000000
    (+0x08) MajorVersion: 0x0000
    (+0x0A) MinorVersion: 0x0000
    (+0x0C) GlobalFlagsClear: 0x00000000
    (+0x10) GlobalFlagsSet: 0x00000000
    (+0x14) CriticalSectionDefaultTimeout: 0x00000000
    (+0x18) DeCommitFreeBlockThreshold: 0x00000000
    (+0x1C) DeCommitTotalFreeThreshold: 0x00000000
    (+0x20) LockPrefixTable: 0x00000000
    (+0x24) MaximumAllocationSize: 0x00000000
    (+0x28) VirtualMemoryThreshold: 0x00000000
    (+0x2C) ProcessHeapFlags: 0x00000000
    (+0x30) ProcessAffinityMask: 0x00000000
    (+0x34) CSDVersion: 0x0000
    (+0x36) Reserved1: 0x0000
    (+0x38) EditList: 0x00000000
    (+0x3C) SecurityCookie: 0x004050CC
    (+0x40) SEHandlerTable: 0x004039F0
    (+0x44) SEHandlerCount: 0x00000003
    Les deux derniers champs indiquent respectivement où se trouve la table des SEH (qui contient des VA vers les SEH enregistrés pour le binaire) et leur nombre. (N.B: A noter, le champ SecurityCookie qui est là pour protéger des stack overflow!)

    004039F0 05 15 00 00 CB 21 00 00 F8 21 00 00
    donc, trois SEH enregistrés avec comme VA (et RVA):

    SEH1: 0x1505 => RVA: 0x401505
    SEH2: 0x21CB => RVA: 0x4021CB
    SEH3: 0x21F8 => RVA: 0x4021F8
    Ce qui se confirme lors de l'analyse du binaire.


    Dans ton cas précis, il n'y a malheureusement rien à faire si ce n'est tomber sur un binaire non compilé avec /SAFESEH...

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Je me disais bien qu'il avait quelque chose dans le PE !
    C'est éxactement ça que je cherchais /SAFESEH:NO

    En tout cas, très belle explication ! Merci beaucoup

    Hors sujet:
    Je suis à la recherche de ton pdf nommé "PEB_LDR_DATA...".
    Je l'avais eu sur le site de la FRET et je n'arrive plus à le trouver
    C'est possible de l'avoir s'il te plaît ?

    Merci encore !

  6. #6
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    C'est bien lui
    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/11/2010, 15h43
  2. [MySQL] Problème avec un script qui ne marche pas
    Par greg056 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 15/03/2009, 20h07
  3. Requete avec champs calculés qui ne marche pas
    Par The_Super_Steph dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 05/06/2007, 14h39
  4. requete SQl avec la fonction max () qui ne marche pas
    Par eclipse012 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 09/11/2006, 14h32
  5. Formulaire avec du PHP qui ne marche pas !
    Par Sandara dans le forum Langage
    Réponses: 19
    Dernier message: 02/06/2006, 18h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo