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 et qui peut être programmé en ASM ainsi: 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: 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. 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 ! 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. Ces trois tests (SICE, NTICE et FROGICE) se trouvent à la suite les uns des
autres dans le même call: Dans la call suivant, RD 116 remet le couvert avec la même batterie de tests,
à savoir: détection SICE, NTICE et FROGICE: Softice possède un handler pour l'interruption 068h (V86) et il met F386h
lorsque la fonction 43h est appelée. 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... 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: Une petite intérrogation sur le contenu des registres va donner: Et ca ne pourrait pas ressembler à une interrogation base de registres? Un d EAX va donner Et si vous tracez SUR le call 00422EE0, vous aurez une nouvelle boite de message/ExitProcess. Avec cette dernière détection, s'en est fini des Anti-Sice. 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)... 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... A chaque fois que vous rencontrerez cet anti-Sice, vous trouverez, comme points
communs, les valeurs suivantes: 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: 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. 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. et la programmer en ASM: 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! Les magics values ExceptHandler: 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 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! RingZeroCodeProtected: L'IDT 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 :)
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
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
** 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
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
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
);
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
: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)
: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
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
: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? :)...
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]
: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
[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
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...............
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
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
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)
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)
-SI = 4647h
-DI = 4A4Dh
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)
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
( 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
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
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
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
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
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
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
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émoireS_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
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
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 Kernel32S_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