Piece of Christal's Page

  Protection
   Anti Sice Multiples  

Les Anti SoftIce

  Outils
   SoftIce    
  Cible
   Crackme n°4 RD 116  

By "Groupe de travail"

Anti SoftIce routines: Causes et Remèdes

(Le texte qui suit est une synthèse d'un ensemble de documents).


SoftIce peut être “ découvert ” de multiples façons. Je n’ai pas l’intention de les passer toutes en revue (et je doute que ce soit possible, il en sort régulierement de nouvelles), mais d’aborder quelques cas de figures courant.
Tout d'abord, il faut s'équiper un peu, et récupérer FROGICE (actuellement la version 4) qui est l'outil, par excellence, de lutte contre les Anti-Sice (http://www.thepentagon.com/frog_s_print -> pas d'accès possible à ce site avec Internet Explorer). Cet outil est livré avec un fichier Code.txt résumant les principaux modes de détection de softIce, et comment les repérer. Vous y trouverez de nombreuses références dans ces lignes.


Meltice : Code 0B

Le principe est simple: l'application va chercher la présence de SoftIce en mémoire:

Cette méthode est mieux connue sous le nom de "MeltICE" parce qu'elle a été librement distribuée via http://www.winfiles.com. A l'origine, elle fut utilisée par Numéga pour permettre au Symbol Loader de vérifier si SoftIce était actif ou non. Le code se trouve dans nmtrans.dll (répertoire de Numéga\SoftIce9X):
Le principe est simple, l'application va charger en mémoire la chaîne à trouver, et essayer d'ouvrir les drivers de SoftIce (SICE, SIWVID pour Win9x, NTICE pour WinNT), avec l'API CreateFileA

(extrait du Crackme n°4 de RD 116)

:00442FE5  50                  PUSH    EAX            > \\.\SICE
:00442FE6  E8B12FFCFF          CALL    KERNEL32!CreateFileA
:00442FEB  83F8FF              CMP     EAX,-01        > si EA = -1
:00442FEE  741F                JZ      0044300F       > continue
:00442FF0  6A20                PUSH    20             > sinon
:00442FF2  B988314400          MOV     ECX,00443188   > ExitProcess
:00442FF7  BA9C314400          MOV     EDX,0044319C
:00442FFC  A1304C4400          MOV     EAX,[00444C30]
:00443001  8B00                MOV     EAX,[EAX]
:00443003  E8E4DBFFFF          CALL    00440BEC
:00443008  6A00                PUSH    00
:0044300A  E8BD2FFCFF          CALL    KERNEL32!ExitProcess
:0044300F  8D45FC              LEA     EAX,[EBP-04]
:00443012  BAC8314400          MOV     EDX,004431C8

et qui peut être programmé en ASM ainsi:

S_Meltice proc
push  0
push  FILE_ATTRIBUTE_NORMAL
push  OPEN_EXISTING
push  0
push  FILE_SHARE_READ+FILE_SHARE_WRITE
push  GENERIC_READ+GENERIC_WRITE
push  offset Sice                          ;Sice db \\.\SICE
                                           ;le nom du vxd qu'on veut ouvrir
call CreateFileA
cmp  eax,-001                              ;eax=-1 si sice n'est pas loadé
je   @END                                  ;good guy
xor  eax,eax                               ;bad guy
@END:
ret
S_Meltice endp

Le FPLoader permet de détourner facilement le résultat de cette recherche de la présence de SoftIce, et vous retournera dans ce cas:

** SOFTICE DETECTION ** code 0B, at cs:00443158
Attempting to load: SICE

Ou 00443158 va être la piste de départ des recherches de l'anti-Sice. En tapant U 00443158 (pour afficher cette partie du code dans la fenêtre de SI) et en regardant un peu autour, vous tomberez vite sur la routine particulièrement révélatrice, vue ci dessus.
Vous pouvez aussi la localiser en utilisant l'un des BPX suivant:


- BPX CreateFileA if*(esp->4+4)=='SICE' || *(esp->4+4)=='SIWV' || *(esp->4+4)=='NTIC'
- BPINT 30 if eax==002A001 && (*edi=='SICE' || *edi=='SIWV')
- BPINT 30 if (*edi=='SICE' || *edi=='SIWV')
- BPX KERNEL32!ORD_0001 if *edi=='SICE'
- BPX VMM_GetDDBList if eax->3=='SICE' || eax->3=='SIWV'


Une fois la présence de Sice repérée, il faudra que l'information soit stockée quelque part pour pouvoir être traitée en conséquence. Dans le cas que nous venons de voir, le mov edi, eax va jouer ce rôle. Dans le cas suivant, un Flag sice_détecté va être mis à 1, alors que dans l'exemple du Crackme de RD 116, le traitement est immédiat (ExitProcess).

(Extrait des codes de Drapeau Noir n°5)

:00401024  68F2614100          PUSH      004161F2  > \\.\SICE
:00401029  E86B400100          CALL      00415099  > CreateFileA
:0040102E  83F8FF              CMP       EAX,-01   > Sice détecté?
:00401031  740A                JZ        0040103D  > no jump
:00401033  C705EE61410001000000MOV       DWORD PTR [004161EE],00000001 

Vous aurez remarqué que dans cet exemple, le test se situe quelques lignes en dessous de l'Entry Point (401000) de l'application. Pour peu que le Symbol Loader de Sice vous rende la main sur cet Entry Point, il devient facile de shunter ce test, en poussant la valeur 00 dans [004161EE], le flag de détection de SoftIce, ou de le pister (par un BPM) jusqu'à la routine de traitement de la présence de Softice.

Il peut y avoir des variantes: (extrait du codage d'ASProtect)

:00C8F65E  A12C34C900          MOV     EAX,[00C9342C]
:00C8F663  50                  PUSH    EAX              > \\.\NTICE
:00C8F664  E8734DFFFF          CALL    KERNEL32!_lopen  > ici
:00C8F669  40                  INC     EAX
:00C8F66A  7510                JNZ     00C8F67C
:00C8F66C  6A00                PUSH    00
:00C8F66E  A13034C900          MOV     EAX,[00C93430]
:00C8F673  50                  PUSH    EAX              > \\.\SICE
:00C8F674  E8634DFFFF          CALL    KERNEL32!_lopen  > et ici
:00C8F679  40                  INC     EAX
:00C8F67A  7425                JZ      00C8F6A1

Au retour de l'API, EAX est incrémenté, et s'il vaut 00, SICE est détecté. Or si SI est présent, la valeur retournée sera -01 !

Mais comment fonctionne CreateFileA?

Oups! Cette API est assez complexe. Elle crée ou ouvre les objets qui suivent, et retourne un handle qui peut être utilisé pour accéder à l'objet:
· files
· pipes
· mailslots
· communications resources
· disk devices (Windows NT only)
· consoles
· directories (open only)

HANDLE CreateFile( 
LPCTSTR lpFileName,               // pointe vers le nom du fichier 
DWORD dwDesiredAccess,           // mode d'accès (lecture-écriture)
DWORD dwShareMode,              // share mode 
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointe vers les attributs de sécurité 
DWORD dwCreationDistribution, // comment créé 
DWORD dwFlagsAndAttributes,  // attribut de fichier 
HANDLE hTemplateFile        // handle à remplir avec les attributs à copier 
);

Dans le cas des détections anti-Sice, cette fonction va rechercher en mémoire la présence de la Chaîne spécifiée après les \\.\, et retourner -1 (FFFFFFFF) en cas d'échec.
Si par contre la valeur retournée est différentes de -1, vos problèmes vont commencer.


Dans son Crackme, RD 116 va tester, après la présence éventuelle de SoftIce pour les plate-formes Win9X, la présence de NTICE:

:0044306F  50                  PUSH    EAX               > \\.\NTICE
:00443070  E8272FFCFF          CALL    KERNEL32!CreateFileA
:00443075  83F8FF              CMP     EAX,-01
:00443078  741F                JZ      00443099


Et pour être plus sur de ne pas se faire "escroquer", il va aussi chercher si ForgIce est actif:

Le Code OE: détection FROGICE

Ce code est retourné quand une application essaye de détecter FrogsICE VxD par un appel à CreateFileA, sur le même principe que la détection MeltIce:
( Forg's Print a prévu la parade en permettant de patcher FrogIce -> cf Code.txt)

:004430F9  50                  PUSH    EAX EAX            > \\.\FROGICE
:004430FA  E89D2EFCFF          CALL    KERNEL32!CreateFileA
:004430FF  83F8FF              CMP     EAX,-01
:00443102  741F                JZ      00443123

Ces trois tests (SICE, NTICE et FROGICE) se trouvent à la suite les uns des autres dans le même call:

:0044339E  E8CDFBFFFF          CALL    00442F70   > celui ci (code 0B)
:004433A3  E85CF9FFFF          CALL    00442D04   > (code 0B)
:004433A8  E88BF8FFFF          CALL    00442C38   > (code 07)
:004433AD  E8F2F8FFFF          CALL    00442CA4   > (code 07)

Dans la call suivant, RD 116 remet le couvert avec la même batterie de tests, à savoir: détection SICE, NTICE et FROGICE:

:00442D79  50                  PUSH    EAX                > \\.\SICE
:00442D7A  E81D32FCFF          CALL    KERNEL32!CreateFileA
:00442D7F  83F8FF              CMP     EAX,-01
:00442D82  741F                JZ      00442DA3


Dans le call suivant, la détection de SoftIce va déclencher un code 07.


Le Code 07: l'Interruption 68

C'est probablement le second test de dépistage le plus couramment utilisé. Le principe est le suivant:

Cette interruption est liée au débuggage d'un process. Il devient assez simple, en y faisant appel, de découvrir la présence de SoftIce.

Son appel se fait ainsi:

INT 68 - MS Windows debugging kernel - OUTPUT STRING
      AH = 47h
      ES:SI -> string

INT 68 - APPC/PC - ENABLE/DISABLE MESSAGE TRACING
      AH = FCh
      AL = new state
           00h disable tracing
           01h enable tracing
      DX = number of bytes to keep (0=all)

Et peut être programmé ainsi en ASM:

S_int68 proc
mov ah,43h         ;fonction 43h
int 68h
cmp ax,0F386h      ;sice est la?
jnz @END
xor eax,eax
@END:
ret
S_int68 endp

Softice possède un handler pour l'interruption 068h (V86) et il met F386h lorsque la fonction 43h est appelée.

Ce qui va nous donner pour le crackme de RD 116:

:00442C38  B443                MOV     AH,43    > fonction 43h
:00442C3A  CD68                INT     68       > int 68
:00442C3C  663D86F3            CMP     AX,F386  > ax = F386 ?
:00442C40  751F                JNZ     00442C61 > si non, continue
:00442C42  6A30                PUSH    30       > si oui, ExitProcess
:00442C44  B9642C4400          MOV     ECX,00442C64
:00442C49  BA782C4400          MOV     EDX,00442C78
:00442C4E  A1304C4400          MOV     EAX,[00444C30]
:00442C53  8B00                MOV     EAX,[EAX]
:00442C55  E892DFFFFF          CALL    00440BEC
:00442C5A  6A00                PUSH    00
:00442C5C  E86B33FCFF          CALL    KERNEL32!ExitProcess
:00442C61  C3                  RET

En ayant trouvé le début de la zone des tests anti-Sice, cette routine est très facile à localiser (trop?) dans la mesure ou en traçant dessus vous aurez immédiatement un message "SoftIce détecté", dans un style assez personnel...

:00443158 53 49 43 45 00 00 00 00-48 75 68 75 68 75 00 00  SICE....Huhuhu..
:00443168 4C 4F 4C 2C 20 54 75 20-65 73 20 75 6E 20 76 72  LOL, Tu es un vr
:00443178 61 69 20 62 6F 65 75 66-20 74 6F 69 3F 00 00 00  ai boeuf toi?...
:00443188 53 6F 66 74 49 43 45 20-44 65 74 45 63 54 65 44  SoftICE DetEcTeD
:00443198 21 21 21 00 53 6F 66 74-49 43 45 20 65 73 74 20  !!!.SoftICE est
:004431A8 63 68 61 72 67 E9 20 70-65 75 74 2D EA 74 72 65  chargé peut-.tre
:004431B8 3F 21 20 3D 29 00 00 00-FF FF FF FF 09 00 00 00  ?! =)...........
:004431C8 5C 5C 2E 5C 4E 54 49 43-45 00 00 00 48 6F 68 6F  \\.\NTICE...Hoho
:004431D8 68 6F 00 00 4A 65 20 72-EA 76 65 20 6F 75 20 74  ho..Je rêve ou t
:004431E8 75 20 61 73 20 65 73 73-61 79 E9 20 64 65 20 6D  u as essayé de m
:004431F8 65 20 63 72 61 63 6B 65-72 3F 00 00 44 E9 73 69  e cracker?..Dési
:00443208 6E 73 74 61 6C 6C 65 20-53 6F 66 74 49 43 45 20  nstalle SoftICE
:00443218 26 20 72 65 76 69 65 6E-73 20 3D 29 00 00 00 00  & reviens =)....
:00443228 FF FF FF FF 0C 00 00 00-5C 5C 2E 5C 46 52 4F 47  ........\\.\FROG
:00443238 53 49 43 45 00 00 00 00-48 69 68 69 68 69 00 00  SICE....Hihihi..
:00443248 54 75 20 65 73 20 73 75-72 20 64 65 20 73 61 76  Tu es sur de sav
:00443258 6F 69 72 20 63 72 61 63-6B 65 72 3F 00 00 00 00  oir cracker?....
:00443268 45 74 20 6F 6E 20 61 70-70 65 6C 65 20 63 61 20  Et on appele ca
:00443278 75 6E 20 63 72 61 63 6B-65 72 3F 20 3A 29 21 21  un cracker? :)!!
:00443288 21 00 00 00 4C 6F 6C 2C-20 54 75 20 6D 65 20 70  !...Lol, Tu me p
:00443298 72 65 6E 64 73 20 70 6F-75 72 20 75 6E 20 63 6F  rends pour un co
:004432A8 6E 20 6F 75 20 71 75 6F-69 3F 20 3A 29 00 00 00  n ou quoi? :)...

Mais c'est rarement aussi facile de trouver les routines de détection, et pour localiser l'appel à l'Int68, un bpint 68 ne donnant rien, il faut utiliser un:

BPX exec_int if ax==68

(attention! Un F12 ferra planter l'application. Il faut utiliser F10, et encore, avec délicatesse!)

Mais ce n'est pas fini, RD 116 a encore en réserve d'autres Anti-Sice, comme vous pourrez vous en rendre compte en continuant à tracer avec F10:

La détection par le path:

:004433D5  8B83E0020000        MOV     EAX,[EBX+000002E0]
:004433DB  E8D0FAFDFF          CALL    00422EB0
:004433E0  8B55FC              MOV     EDX,[EBP-04]
:004433E3  33C9                XOR     ECX,ECX
:004433E5  A134584400          MOV     EAX,[00445834]

Une petite intérrogation sur le contenu des registres va donner:

:00F1427C 53 6F 66 74 77 61 72 65-5C 4D 69 63 72 6F 73 6F  Software\Microso
:00F1428C 66 74 5C 57 69 6E 64 6F-77 73 5C 43 75 72 72 65  ft\Windows\Curre
:00F1429C 6E 74 56 65 72 73 69 6F-6E 5C 41 70 70 20 50 61  ntVersion\App Pa
:00F142AC 74 68 73 5C 4C 6F 61 64-65 72 33 32 2E 45 78 65  ths\Loader32.Exe

Et ca ne pourrait pas ressembler à une interrogation base de registres?

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Loader32.Exe]
"Path"="C:\\Program Files\\NuMega\\SoftIce95"
@="C:\\Program Files\\NuMega\\SoftIce95\\Loader32.Exe"

Du genre, allez voir dans la base de registres si il n'y aurait pas quelques références à SoftIce...

En traçant encore un peu:

:00443408  E8ABF3FFFF          CALL    004427B8
:0044340D  8B55F8              MOV     EDX,[EBP-08]
:00443410  8B83E8020000        MOV     EAX,[EBX+000002E8] > EAX ???
:00443416  E8C5FAFDFF          CALL    00422EE0

Un d EAX va donner

0187:00F14910 43 3A 5C 50 72 6F 67 72-61 6D 20 46 69 6C 65 73  C:\Program Files
0187:00F14920 5C 4E 75 4D 65 67 61 5C-53 6F 66 74 49 63 65 39  \NuMega\SoftIce9
0187:00F14930 35 00 00 00 12 00 00 00-01 00 00 00 01 00 00 00  5...............

Et si vous tracez SUR le call 00422EE0, vous aurez une nouvelle boite de message/ExitProcess.

En traçant "Step Into" le call, vous arriverez ici:

:00422F0D  7410                JZ      00422F1F  > eax = -1 pour ok  (NO JUMP)
:00422F0F  8BC6                MOV     EAX,ESI
:00422F11  E80E0EFEFF          CALL    00403D24
:00422F16  8BD0                MOV     EDX,EAX
:00422F18  8BC3                MOV     EAX,EBX
:00422F1A  E86DFFFFFF          CALL    00422E8C  > Sice détecté
:00422F1F  33C0                XOR     EAX,EAX
:00422F21  5A                  POP     EDX
:00422F22  59                  POP     ECX
:00422F23  59                  POP     ECX
:00422F24  648910              MOV     FS:[EAX],EDX
:00422F27  683C2F4200          PUSH    00422F3C
:00422F2C  8D45FC              LEA     EAX,[EBP-04]
:00422F2F  E8AC09FEFF          CALL    004038E0
:00422F34  C3                  RET

Avec cette dernière détection, s'en est fini des Anti-Sice.
Dans un cas de figure comme ce Crackme, le plus simple est de nopper purement et simplement les calls de détection, soit en 0044339E, 004433A3, 004433A8, 004433AD et 00443416.
Vous pouvez la jouer plus délicatement en intervenant sur les différents sauts:

:0044306F  50                  PUSH    EAX            > \\.\NTICE
:00443070  E8272FFCFF          CALL    KERNEL32!CreateFileA
:00443075  83F8FF              CMP     EAX,-01
:00443078  741F                JZ      00443099

Soit en modifiant le cmp EAX, soit sur le JZ, soit encore en poussant sur la pile NTICE à la place de SICE (en fonction de votre OS)...

Mais il y aurait pu avoir d'autres détections, tant qu'à faire!

Le Code 02: L'INT 3

Le principe de cet anti-sice est de pousser des "nombres magiques" dans des registres, et de faire appel à l'INT 03:

B81109  MOV AX,0911 ; execute command.
8B17    MOV DX,[BX] ; ds:dx point to the command
BE4746  MOV SI,4647 ; 1st magic value.
BF4D4A  MOV DI,4A4D ; 2nd magic value.
CC      INT 3       ; Int call.(si SIce est loadé jmp 00AD)

c'est une méthode très souvent utilisée pour obtenir les 'Back Door commands' de SoftIce qui donnent des informations sur les Breakpoints, ou qui exécutent des commandes de SoftIce...
On peut aussi utiliser l'INT 03 pour crasher SoftIce et de lui demander d'exécuter certaines commandes (HBOOT...):
En voici une rapide description:

-AX = 0910h   (Display string in SIce windows)
-AX = 0911h   (Execute SIce commands -command is displayed is ds:dx)
-AX = 0912h   (Get breakpoint infos)
-AX = 0913h   (Set Sice breakpoints)
-AX = 0914h   (Remove SIce breakoints)

A chaque fois que vous rencontrerez cet anti-Sice, vous trouverez, comme points communs, les valeurs suivantes:

-SI = 4647h
-DI = 4A4Dh

Pour en savoir davantage sur ces fameuses "magic value", il faut aller voir de plus pres la table des intéruptions de Ralf Brown, dont en voici un extrait:

INT 03 - Soft-ICE - BACK DOOR COMMANDS - GET Soft-ICE VERSION
        AX = 0000h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
INT 03 - Soft-ICE v2.80 - BACK DOOR COMMANDS - POPUP & START A DEBUG SESSION
        AX = 0902h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
        DS:BX -> initial register values (see #00001)
Retour:   Registres comme spécifiés dans leurs valeurs initiales
Note:     Cette fonction est appelée par LDR.EXE au lancement d'un programme
          à débugger. Après avoir exécuté cette fonction, Soft-ICE pops up
          son écran noir
          et vous permet de commencer le débuggage du programme.
INT 03 - Soft-ICE - BACK DOOR COMMANDS - DISPLAY STRING IN Soft-ICE WINDOW
        AX = 0910h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
        DS:DX -> ASCIZ chaine à afficher (max 100 bytes, 0Dh OK)
INT 03 - Soft-ICE - BACK DOOR COMMANDS - EXECUTE Soft-ICE COMMAND
        AX = 0911h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
        DS:DX -> ASCIZ command string (max 100 bytes, 0Dh OK)
INT 03 - Soft-ICE - BACK DOOR COMMANDS - GET BREAKPOINT INFORMATION
        AX = 0912h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
Reour:  BH = entry number of last breakpoint set
        BL = type of last breakpoint set (see #00002)
        DH = entry number of last breakpoint to be triggered
        DL = type of last triggered breakpoint (see #00002)

(Table 00002)
Values for Soft-ICE breakpoint type:
 00h        BPM (breakpoint register types)
 01h        I/O
 02h        INTerrupt
 03h        BPX (INT 03-style breakpoint)
 04h        reserved
 05h        range

INT 03 - Soft-ICE v2.5x - BACK DOOR COMMANDS - SET Soft-ICE BREAKPOINT
        AX = 0913h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
        DS:DX -> breakpoint structure (see #00003)
Retour: AX = status
             00h successful
        BX = breakpoint number
             03h breakpoint table full
             06h memory limit error
             07h I/O limit error
             09h range limit error
             16h duplicate breakpoint

INT 03 - Soft-ICE v2.5x - BACK DOOR COMMANDS - REMOVE Soft-ICE BREAKPOINT
        AX = 0914h
        SI = magic value 4647h ('FG')
        DI = magic value 4A4Dh ('JM')
        BX = breakpoint number (returned by AX=0913h)

En trouvant des "magic values" dans un listing, le seul fait d’en modifier une ne permettra plus à l'Int 3 de repérer la présence de Sice.

Au début le plus simple est d'utiliser le FPLOADER pour trouver où ce type de détection se situe dans les codes du programme (le Fploader retourne une adresse qui va devenir le point de départ de la recherche de l'anti-Sice).

Une autre technique de détection est:

Le test avec ISDEBUGGERPRESENT

      call      S_IsDebug
      test      eax,eax
      je        @2      
      push      offset Num1
      call      SiceDetected

D'abord la DLL KERNEL32 est chargée, puis on recherche l'adresse de ISDEBUGGERPRESENT. L'appel peut se faire par un call eax et la valeur retournée est égale à 00 , ce qui est normal dans la mesure ou cette API ne fonctionne qu'avec WINDOWS NT.
( voir la description de cette API dans l'aide sur les api win32 ).

Un peu plus bas, vous devriez apercevoir une jolie INT3 perdue au beau milieu du code et en cherchant bien dans les registres (en général EBP) vous devriez trouver 4 octets évocateurs une fois traduit en ASCII - et qui sont 4243484B -> = BCHK en ASCII.
Il faut aussi tenir compte de la valeur de EAX qu'il faudra modifier par la suite ….

Donc que se passe t-il ? Par l'int3 on va tester la présence des 4 lettres BCHK ce qui signifie que Sice est actif.

Les errors Handlers

Lorsque vous programmez, il peut vous arriver d'avoir besoin de catcher des erreurs pour rediriger votre programme vers une zone mémoire plus sure ou vers un code qui évitera le plantage...
Pour cela vous utilisez les Exception Handler:
Lorsque qu'une erreur est catchée l'erreur est envoyée au débuggeur en premier. Si celui-ci la traite, rien d'autre ne se passe, dans le cas contraire l'erreur est envoyée à l'exception handler, puis une dernière fois au débugger...
Vous avez sûrement déjà vu des exceptions handler à l'œuvre (la boite de dialogue qui arrive quand un programme plante et qui affiche les registres. Et bien cette boite est celle par défaut :)
C'est à ce niveau que les premières protections anti-sice interviennent car si le débugger catche l'erreur et la traite, vous n'irez jamais dans le except handler.

La methode BCHK

On pourrait résumer cette routine ainsi:

           mov ebp,"BCHK"
           mov ax,4
           int 3
           cmp ax,4
           jne winice_présent

et la programmer en ASM:

S_BCHK proc

push offset ExceptHandler2
PUSH FS:[0] 
MOV FS:[0],ESP              ;mis en place de l'except Handler qui sera ici
                            ;notre ExceptHandler2

mov Flag,0
mov ebp,"BCHK"              ;on met le mot magique dans ebp
mov ax, 04h
int 3                       ;on crée une erreur
                            ;à ce moment si Sice est lancé on ne va rien voir et
                            ;tout va se passer normalement,
                            ;mais on n'atterrira pas dans l'except Handler...


mov eax,Flag                ;si Sice est lancé, il est tjrs a Zéro
mov Flag,0

POP FS:[0]
ADD ESP,4h                  ;on enlève l'except handler

ret

ExceptHandler2:
mov Flag,01                ;Si on arrive ici c'est que sice n'est pas lancé
                           ;on met 1 dans le Flag ->pas de debugger
xor eax,eax
ret

S_BCHK endp

Même si vous avez désactivé l'utilisation de l'int 03h dans softice (i3here off; faults off), vous ne pourrez pas passer cette routine!
Pourquoi? Simplement parce qu'elle a été spécialement crée par les programmeurs de Softice pour permettre la communication avec d'autres produits Numega Boundschecker...

Un des aspects les plus embarrassant de cette technique, les premières fois qu'on la rencontre, c'est que rien ne semble anormal...on vient de mettre 0 dans le Flag un peu avant, et c'est logique qu'il soit resté a zéro...
Par contre avec un peu d'expérience, on remarque facilement les codes types utilisés pour générer des erreurs et pour enclencher les Except Handlers...

Par exemple:

xor eax,eax
mov eax,[eax]       ;page Fault

Les magics values

S_Int_Handler proc

push offset ExceptHandler     ;idem que tout a l'heure, on met un offset handler
PUSH FS:[0] 
MOV FS:[0],ESP

mov Flag,0

MOV ESI,04647h                ;on met les mots magiques dans esi et edi
MOV EDI,04A4Dh
INT 3                         ;on appelle l'int 03h

POP FS:[0]
ADD ESP,4h                    ;on enlève l'exception handler
mov eax,Flag
ret

ExceptHandler:

xor eax,eax
mov Flag,01          ;si softice n'est pas lancé, on arrive là et on met le flag a 1 
;->pas de debugger

ret

S_Int_Handler endp

Ici c'est identique à tout à l'heure, sauf que cette fois ci ce n'est plus ebp qui contient le mot magique, mais esi et edi

Pour détecter si ces méthodes sont utilisées, le plus facile est de regarder si il n'y as pas un push fs:[0] aux alentours... (assez voyant lorsque vous tracez :)
Mais attention, les programmes utilisent souvent un vrai except handler et il n'y aura aucune routine anti-sice dedans.


Les méthodes un peu moins connues

Le dr7

Utilisation des debug Register (DRx) et des contôle Register (CRx):

Accéder a ces registres en mode V86 amène à une General Protection Fault (INT0D), que SoftIce ne gère pas correctement.
Pour pouvoir lire les debugs register (au nombre de 6) vous devez être en ring0. Pour ce faire, il existe 3 ou 4 méthodes pour passer du ring3 (niveau de privilège le plus bas, là où tournent les programmes normaux) au ring 0 (niveau de privilège le plus élevé -> Vxd...)
Etant donné que ce changement de ring pourrait dérouter certains d'entre vous, j'ai un peu masqué la méthode utilisée...).
En ring 0 le programme peut lire les debugs register. A titre d'exemple le dr7 vaut 400h normalement, mais si un debugger est présent il a de fortes chances pour qu'il change :)

S_DRx proc
push offset RingZeroCode           ;la routine qu'on veut exécuter en ring0
call RingZero                      ;fonction qui permet de passer en ring0 :)

cmp eax,0400h                      ;le dr7 était égal a 400h?
je @END                            ;oui ->good guy
xor eax,eax                        ;non ->Debugger detected
@END:
ret

RingZeroCode:

mov eax,dr7
iretd
S_DRx endp

Cette méthode est assez déroutante pour le "newbie" car le passage en ring0 n'est pas de toute simpliste, mais une fois que vous aurez compris le principe, cela devient enfantin!
L'important pour voir ce style de méthodes est de repérer les SIDT fword ptr [XXXXXXXX] et les iretd qui vont être les indicateurs permettant de savoir qu'il va se produire quelque chose en ring0 :)

Checker le dr7 en se protégeant:

Certains tools comme Frogsice tentent de catcher les accès au drx en enclenchant un bit du Dr6 qui déclenche une int01h si jamais vous essayez de toucher à un debug register :)
Pour contrer ce genre de protections, il existe une méthode, assez simple en soit, qui consiste à hooker nous même l'int 01h, et tant qu'a faire l'int 03h, pour éviter les breakpoints (0CCh)...

S_DRxP proc

sidt fword ptr IDT                    ;on obtient le registre IDT
mov ebx, dword ptr [IDT+2]            ;on met dans ebx l'adresse de la base de l'IDT
add ebx, 8*03h                        ;on se place au niveau de l'entrée de l'int 03h 
cli 
mov dx, word ptr [ebx+6]              ;on sauve le high word de l'ancienne routine 
shl edx, 16d
mov dx, word ptr [ebx]                ;le low word 
mov [lpOldGate], edx                  ;on sauvegarde
mov eax, offset RingZeroCodeProtected ;on installe notre routine 
mov word ptr [ebx], ax ;low word
shr eax, 16d
mov word ptr [ebx+6], ax ;high word

mov ebx, dword ptr [IDT+2] 
add ebx, 8*01h                       ;on se place au niveau de l'entrée de l'int 01h
cli 
mov dx, word ptr [ebx+6]             ;on sauvegarde le high word
shl edx, 16d
mov dx, word ptr [ebx]               ;le low word 
mov [lpOldGate2], edx                ;on sauvegarde
mov eax, offset HookInt0             ;on installe notre routine pour l'int 01h
mov word ptr [ebx], ax               ;low word
shr eax, 16d
mov word ptr [ebx+6], ax             ;high word 

int 03h ;on crée une int qui va nous envoyer dans notre routine de l'int 03h 

mov ebx, dword ptr [IDT+2]          ;on fait tout dans l'autre sens en restaurant 
add ebx, 8*01h
mov edx, [lpOldGate2]
mov word ptr [ebx], dx
shr edx, 16d
mov word ptr [ebx+6], dx            ;l'int 01h

mov ebx, dword ptr [IDT+2]
add ebx, 8*ExceptionUsed
mov edx, [lpOldGate]
mov word ptr [ebx], dx
shr edx, 16d
mov word ptr [ebx+6], dx            ;l'int 03h

cmp eax,0400h                       ;on re-test notre dr7
je @END
xor eax,eax
@END:
ret

RingZeroCodeProtected:

mov eax,dr7 ;les outils qui hookent l'int 01h ne verront rien 
            ;car leur routine n'est plus active

iretd

HookInt0:
iretd

S_DRxP endp


Les strings que softice laisse traîner en mémoire

S_Winice_brk proc

mov al,"W"            ;le W de WINICE :)
mov edi,10000h        ;on scanne la mémoire en commençant a 10000h
mov ecx,0FFFFFh       ;on va scanner sur 0FFFFFh bytes

@Loop:
repnz scasb
jecxz @END            ; scannage terminé sans rien avoir trouvé -> pas de softice en vue

cmp dword ptr [edi], "CINI"    ;on compare le INIC de WINICE 
                               ;(ne pas oublier qu'il faut inverser les caractères)

jz @Suite

jmp @Loop
@Suite: 
add edi, 4
cmp dword ptr [edi], "RB.E"   ;on compare la fin soit WINICE.BR->E.BR 
jnz @Loop
xor eax,eax                   ;softice est détecté :)


@END:

ret
S_Winice_brk endp

L'IDT

S_SIDT proc

SIDT FWORD PTR IDT
mov edi,dword ptr [IDT+2]
mov bx,word ptr [edi]
mov ax,word ptr [edi+8]
sub ax,bx
sub ax,010h

@END:
ret
S_SIDT endp

Si vous vous en rappelez, nous avions lu les adresses des fonctions qui contrôlaient les int lorsque nous passions en ring0. Cette fois ci, nous allons nous servir du fait que Softice détourne les int 01h et int 03h (ne vous fiez pas a ce qu'il dit quand vous faites IDT dans Softice.... il ment :)
En prenant le low word de l'adresse de la routine pour l'int 00h et celle pour l'int 01h, normalement vous devriez avoir:

bx=1350
ax=1360

Faites bx-ax-10 et si le résultat est égal à zéro sice n'as pas hooké les int, et donc il est absent :)
La fonction renvoie ax=0 si Sice est absent et une autre valeur s'il est là

Détection par la fonction 1 de la dll Kernel32

S_Kernel01 proc

push 0000004fh             ;fonction 4f 
push 002a002ah 
mov ebx,0bff713D4h         ;Kernel32!ORD_001
call ebx
cmp ax, 0f386h             ;retournée par les debuggers system
jnz @END
mov eax,Flag
@END:

ret
S_Kernel01 endp


Parmi les contre-mesures possibles, outre l'usage de FrogIce, il y a moyen de renforcer la "discrétion" de SoftIce. Pour cela, il existe des outils comme IcePatch qui vont intervenir à de multiples niveaux dans les fichiers suivants

winice.exe, siwvid.386, nmtrans.dll, dldr.exe, wldr.exe, dlog.exe, krnl386.exe, vmm32.vxd

MeltIce, par exemple, peut être bluffé en modifiant SICE et NTSICE dans winice.exe par SACE et NTSACE. Ensuite, pour que Symbol Loader continue a fonctionner, il suffit de modifier “ file://./SICE ” par “ file://./SACE ” et “ file://./NTSICE ” par “ file://./NTSACE ” dans mntrans.dll...

Ce texte a été complété par différents écrits, et principalement de:
Frog's Print, Pulsar, Dark-Angel, TeeJi

Bonne Journée
Christal