Protection   Anti SoftIce + Compression   Les Protections Renforcées
Outils   ProcDump SoftIce    
Cible   Cible n°5  

By Christal


French Initiation in the use of the FPLoader
Hommage à Frog's Print
Ou comment contourner une protection anti-SoftIce
Ou encore, comment se fâcher avec un copain…


Il était une fois un zoli programme détectant Softice, mais sans autre conséquence que de signaler le fait que ce célèbre débuggeur avait été piégé, et un rire que j'ai jugé sardonnique...
Dans l'espoir (maigre) de ne pas me fâcher complètement avec le copain qui a réalisé l'application en question, je resterai assez évasif quand à son nom, et à celui de son petit bijoux.
Hélas, je ne doute pas que plusieurs d'entre vous finirons par le reconnaître, et que vous aurez su apprécier à sa juste valeur la qualité du travail de TxMaMBxLx. Du grand Art!


Pour savoir de quel façon l'exécutable détectait la présence de SoftIce, j'ai lancé l'indispensable FPLoader de Frog'sPrint (
http://www.thepentagon.com/frog_s_print), qui est allé se loger à coté de l'horloge dans la barre des tâches, puis j'ai lancé l'application. Aussitôt le si bel écran bleu de MicroSoft est apparu, affichant:

=> Cible DxxPxxx Nxxx
** SOFTICE DETECTION ** code 0B, at cs:004161F6
Attempting to load: SICE

Voyons ce que la doc jointe avec FrogICE nous en dit:

Le Code 0B

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\SoftIce95):

* Possible StringData Ref from Data Obj ->"\\.\SICE"
                                  |
:100198DA 6824950710              push 10079524  > \\.\SICE
:100198DF FFD6                    call esi       > createfileA
:100198E1 83F8FF                  cmp eax, -1
:100198E4 8BF8                    mov edi, eax
:100198E6 752B                    jne 10019913

La façon dont MeltICE fonctionne est très simple:
Il essaye d'ouvrir les drivers de SoftIce (SICE, SIWVID pour Win9x, NTICE pour WinNT), avec l'API CreateFileA .
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 détecté à cs:10079524"

Il y a des centaines de BPX (dixit Frog's Print) que vous pourriez utiliser pour détecter cette recherche:

- 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'

En posant un bpx CreateFileA, et en ayant caché (Hook) la présence de SoftIce grâce au FPLoader, je suis arrivé ici après 23 appuis sur F12:

015F:00401000  6A00                PUSH      00
015F:00401002  E886400100          CALL      0041508D
015F:00401007  85C0                TEST      EAX,EAX
015F:00401009  7507                JNZ       00401012
015F:0040100B  6A00                PUSH      00
015F:0040100D  E881400100          CALL      00415093
015F:00401012  6A00                PUSH      00
015F:00401014  6800000004          PUSH      04000000
015F:00401019  6A03                PUSH      03
015F:0040101B  6A00                PUSH      00
015F:0040101D  6A03                PUSH      03
015F:0040101F  68000000C0          PUSH      C0000000
015F:00401024  68F2614100          PUSH      004161F2
015F:00401029  E86B400100          CALL      00415099  > CreateFileA
015F:0040102E  83F8FF              CMP       EAX,-01   > Sice détecté?
015F:00401031  740A                JZ        0040103D  > no jump
015F:00401033  C705EE61410001000000MOV       DWORD PTR [004161EE],00000001 
015F:0040103D  E8E0020000          CALL      00401322
015F:00401042  E8E5040000          CALL      0040152C
015F:00401047  33C0                XOR       EAX,EAX 

Vous aurez remarqué que ce 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 le test anti-SoftIce, en poussant la valeur 00 dans [004161EE], le flag de détection de SoftIce.

Bon, après avoir fait la modification en mémoire, et relancé la cible, débarrassé du détecteur de SoftIce, l'application s'ouvre avec…
SOFTICE DETECTED!!!

Ouch!
Soit je m'y suis mal pris, soit il y a un second test de détection…

En réutilisant le FPLoader, j'ai obtenu un deuxième écran bleu:

=> MSPEC=C:    
** SoftICE detection **  code 07, at  FCAF:00002FF0(?)  
Interrupt:68h >eax=00004301h  ebx=00000000h  ecx=800074A8h
               edx=800052D0h  esi=00008B98h  edi=0059FB28h  ebp=0059FB20h

(vous noterez que FrogsICE n'est pas capable de retourner le bon offset:segment d'un programme 32 bits)

Le Code 07

La seconde méthode utilisée pour détecter SoftIce joue sur l' int 68h (V86)
Voici le principe général de ce test de dépistage:
mov     ah,43h
int     68h
cmp     ax,0F386h
jz      SoftICE_Detected

et dans le cas qui nous intéresse, j'ai obtenu un retour ici:

0CA5:1103  2EFF2E0500          JMP       FAR CS:[0005]
0CA5:1108  80FC43              CMP       AH,43  identification SoftIce 4301
0CA5:110B  0F842601            JZ        1235
0CA5:110F  80FC44              CMP       AH,44
0CA5:1112  0F84C200            JZ        11D8
0CA5:1116  3D8150              CMP       AX,5081

en utilisant ce breakpoint:

BPX exec_int if ax==68

En traçant à partir de ces adresses, vous retournez vite aux codes du programme:

015F:0040127F  B443                MOV       AH,43
015F:00401281  CD68                INT       68          > int 68
015F:00401283  663D86F3            CMP       AX,F386
015F:00401287  7537                JNZ       004012C0
015F:00401289  833DEE61410001      CMP       DWORD PTR [004161EE],01 > 
Flag anti SoftIce
015F:00401290  742E                JZ        004012C0    > à modifier
015F:00401292  6887924000          PUSH      00409287
015F:00401297  68CF070000          PUSH      000007CF
015F:0040129C  FF7508              PUSH      DWORD PTR [EBP+08]
015F:0040129F  E8BF3D0100          CALL      USER32!SetDlgItemTextA
015F:004012A4  C705EE61410001000000MOV       DWORD PTR [004161EE],00000001
015F:004012AE  6813934000          PUSH      00409313
015F:004012B3  68B70B0000          PUSH      00000BB7
015F:004012B8  FF7508              PUSH      DWORD PTR [EBP+08]
015F:004012BB  E8A33D0100          CALL      USER32!SetDlgItemTextA
015F:004012C0  33C0                XOR       EAX,EAX
015F:004012C2  5E                  POP       ESI
015F:004012C3  5F                  POP       EDI
015F:004012C4  5B                  POP       EBX
015F:004012C5  C9                  LEAVE
015F:004012C6  C21000              RET       0010

Cette fois ci, le problème peut être résolu en modifiant le branchement en 00401290.

Yaplusqua!

Ouverture de l'éditeur hexadécimal de votre choix, recherche, et…
RIEN!

Aie!
Le programme doit certainement réserver encore quelques surprises…
Voyons voir, en commençant par regarder ce que peut nous indiquer l'hexéditeur:

Au bout de quelques lignes:

.......$Id: UPX
0.82 Copyright (
C) 1996-1999 Las
zlo Molnar & Mar
kus Oberhumer $.

Génial, la signature d'UPX...

Mais quelques lignes plus bas:

..............En
crypted by Stone
CF - PowerLame
PE-ExeEnCrypter
! :) 2nd&mi

Une DEUXIEME signature, celle de Pe-ExeEncrypter par Stone (http://www.cracking.net/stone), un maître du genre…

Il nous gâte, le monsieur, une double encryption/compression…

Commençons par rassembler les informations:

Lancement de procDump: options "PE Editor"

EntryPoint 004D000, image Base 00400000
Puis clic sur l'option " Séctions"

UPX0       00038000   00001000    00000000    00000400    E0000080
UPX1       00023000   00039000    00022600    00000400    E0000040
.rsrc      00001000   0005C000    00000C00    00022A00    C0000040
.Stone     00001000   0005D000    0000011B    00023800    C0000040

Les Characteristics sont typiques d'un programme compressé, on va les modifier rapidement en changeant le E0000080, et les C0000040 par des E0000020. De cette façon, SoftIce rendra la main sur l'entry point en lançant le programme/cible via le Symbol Loader, suivant la règle suivante:

   0x00000020 IMAGE_SCN_CNT_CODE 
   0x20000000 IMAGE_SCN_MEM_EXECUTE 
   0x40000000 IMAGE_SCN_MEM_READ 
OR 0x80000000 IMAGE_SCN_MEM_WRITE
 ----------------------------------- 
   0xE0000020 

Désormais, le programme est désassemblable (sans les ressources), et débuggable.

Mais comment réussir à patcher cette cible bi-compressée?

- En utilisant R!SC Process Patcher, mais compte tenu de la double compression/encryption, il risque d'avoir du mal à mettre la main sur le deuxième test anti-SoftIce.
- Ecrire un script pour ProcDump qui automatiserait la création d'un Dump. Faisable, mais d'un intérêt modéré dans la mesure ou une telle double compression ne se retrouvera probablement jamais. Beaucoup d'énergie pour pas grand chose.
- En réalisant un patch par hard Patching. Pas évident, on y reviendra.
- En réalisant à la main le dump de la cible. Facile, mais l'inconvénient, c'est que le résultat sera un exécutable plus gros que celui d'origine.

Commençons par la solutions la plus facile, le dump de la cible.

En traçant de l'entrypoint, vous verrez que c'est STONE qui ouvre le bal (logique d'après l'EP), suivi de UPX.
Il va falloir procéder en deux étapes, une pour l'encryption ,l'autre pour la compression.

C'est parti.
Il ne faut pas oublier notre Anti-SoftIce, et avant d'arriver en 00401033, vous taperez, sur la ligne de commande de SoftIce, "e 401033". Ainsi, vous verrez les codes de cette adresse s'afficher dans la fenêtre des Datas. Il n'y aura plus qu'à cliquer sur le 01 pour le remplacer par 00, puis [Echap], pour valider la modification. C'est plus rapide que de passer par le mode assemblage. En 00401290 une simple inversion de drapeau suffira (R FL Z).

Mais pour le moment, vous êtes dans la section Cible!.Stone.
En traçant, vous arrivez en 0045D096, stoppez tout:

015F:0045D094  5F                  POP       EDI
015F:0045D095  5D                  POP       EBP
015F:0045D096  FFE0                JMP       EAX       > passe la main à UPX
015F:0045D098  0000                ADD       [EAX],AL  > début de la zone compressée

Remplacez le JMP EAX, par un JMP EIP, pour obliger le programme à boucler sur lui même, et relevez le contenu de EAX: 0045B300. C'est l'entrypoint de la partie compressée par UPX, et vous allez en avoir besoin: Notez le.

Ouvrez ProcDump, et cliquez sur " Options " pour choisir " Rebuilt Import Table ", puis sélectionnez la cible dans la liste des taches actives de la fenêtre de ProcDump. Après quelques instants, vous pourrez sauvez un joli dump du nouvel exécutable. Des 143 ko d'origine, vous avez toujours un programme de la même taille. C'est assez normal dans la mesure ou Pe-ExeEncrypter est un crypteur et non pas un compresseur. Ave UPX la taille va certainement changer…

Il faut maintenant modifier l'entry point de ce premier Dump que vous venez de réaliser. Encore grâce à ProcDump, vous allez pouvoir remplacer les
4D000 du départ par 45B300 (entry point donné par EAX) - 400000 (image base) = 5B300 (nouvel EP). Vous ferrez cette modification en utilisant l'options "PE Editor". Et, bien sur, vous n'oublierez pas d'utilisez la fonction "Kill Task" pour supprimer la boucle folle sur la cible qui est toujours en mémoire.

Ok! Vous voilà avec un dump décrypté, exécutable, désassemblable (mais toujours sans ressources) et débuggable.

Passons à l'étape 2: le dump décompressé.

En relançant la Cible via le Loader de Sice, vous attaquerez le programme par l'adresse 004FB300 (et heureusement…), dans la section UPX1.
Le passage de relais d'UPX au programme d'origine est assez facile à trouver: pour en connaître l'adresse, il suffit, bien souvent, d'aller regarder à la fin du listing que vous aurez pu obtenir avec Wdasm:

:0045B47C 61           popad                  > restauration des registres 
:0045B47D E97E5BFAFF   jmp 00401000           > vers programme d'origine
:0045B482 0000         add byte ptr [eax], al > zone compressée ou nulle

Le jmp Entry_point est l'une des caractéristiques de ce compresseur. Dans notre cas, l'entry point du programme d'origine est le classique 00401000. Il pourra arriver que ce ne soit pas le cas, et alors le PoPad juste au dessus pourra devenir votre fil d'Ariane…

Il ne reste plus qu'à faire les mêmes opérations que pour le dump précédent, en remplaçant le jmp 0040100 par un jmp EIP, et à la fin du Dump donner le nouvel EP, soit 1000.

Vous voici avec un programme de 367 ko, au lieu des 143 ko avant décompression, et qui va pouvoir être patché "normalement" et sans autres surprises.
Bye Bye Anti SiftIce…

Hard Patching:

Dans la cas d'une encryption et d'une souscouche de compression, le gros problème est de trouver de la place pour y glisser les quelques lignes nécessaire à un patch modifiant la partie anti SoftIce. L'objectif de ce texte n'étant pas de réussir un Patch Hard de la cible (comprenez l'application d'un patch ne nécessitant pas de passer par des dumps mémoire), voici quand même ce qu'il y aurait moyen de faire:

0045D093 POP ESI
0045D094 POP EDI
0045D095 POP EBP
0045D096 JMP EAX > fin du décryptage de STONE
à remplacer par
0045D096 JMP adresse1_du_patch > adresse à trouver

015F:0045D090  5B                  POP       EBX
015F:0045D091  59                  POP       ECX
015F:0045D092  5A                  POP       EDX
015F:0045D093  5E                  POP       ESI
015F:0045D094  E93FFBFFFF          JMP       0045CBD8  > par exemple en 0045CBD8
015F:0045D099  004000              ADD       [EAX+00],AL

Mais le POP EDI et POP EBP ont été écrasés. Il faudra les penser à les restorer.

Adresse1_du_Patch

015F:0045CBD8  5F                  POP       EDI > restoration du POP EDI
015F:0045CBD9  5D                  POP       EBP > idem pour EBP
015F:0045CBDA  C7057DB44500E96B1700MOV       DWORD PTR [0045B47D],00176BE9
015F:0045CBE4  C60581B4450000      MOV       BYTE PTR [0045B481],00
C'est 2 lignes de commandes modifient le jmp 401000 pour le forcer à venir en Adresse2_du_Patch
015F:0045CBEB  FFE0                JMP       EAX > retour à la "normale"
Adresse2_du_Patch (à la suite du premier)
015F:0045CBED  C6053910400000      MOV       BYTE PTR [00401039],00 > 1er anti-Sice
015F:0045CBF4  C60590124000EB      MOV       BYTE PTR [00401290],EB > 2ème anti-Sice
015F:0045CBFB  E90044FAFF          JMP       00401000 > vers le prog décrypt/décomp
015F:0045CC00  0000                ADD       [EAX],AL

Le patch 1 va restorer les 2 codes écrasés par la mise en place du jmp branchant vers Adresse1_du_patch, puis de DWORD va modifier 4 octets à l'adresse du jmp 00401000. Le Byte va finir le travail (un jmp long est codé sur 5 octets). Désormais, le jmp 00401000 est devenu un jmp 0045CBED, en 0045B47D, et va brancher sur Adresse2_du_patch.

Le patch 2 va modifier un octet en 00401039, empéchant la mise à 1 de [004161EE], et un autre octet en 00401290, en remplaçant le 742E par un EB2E. Bye Bye Anti SoftIce...

Spécial Greetz à TaMaMBoLo pour ses Drapeaux Noirs, et particulièrement le n°5...

Bonne journée

Christal