VBox 4.2 - Ready Made Protection
Bye bye VBox !

Introduction


Je vais ici expliquer comment contrer VBox 4.20 à jamais. Pour ceux qui ne connaissent pas VBox, c'est une Ready Made protection écrite par WeiJunLi utilisé principalement par Symantec, Adobe et autres. Depuis sa création, VBox à fait beaucoups de progrès. Voici quelques une des caractéristiques de la protection :

1. Vboxt420.DLL et VBoxz420.DLL crypté.
2. CRC Check de la DLL par le programme protégé.
3. Anti-Sice et Anti-WDasm.
4. ...

Le point 2 est tout particulièrement intéressant car il empèche de modifier la DLL. Il faut donc modifier chaque programme protégé séparemment. Ceci est la principale différence avec la version précédente et va nous compliquer un peu les choses. La méthode que je vais exposée ici ne s'adresse pas aux débutant car je vais toucher au coeur du système. En clair, on va appliquer notre patch non pas aux programme protégé, mais à Kernel32.DLL et User32.DLL. Pour les personnes qui aimeraient rester prudente, on peut remplacer très facilement les modifications disk par une modification mémoire aux démarrage de Windows par exemple, il faudra simplement écrire le Memory Patch que je laisse en exercice :).


Outils nécessaires


Windows 98 SE Fr ( Je le note pour des raisons d'addresses qui risquent d'être différentes avec d'autres versions )
SofICE v4.0
HView v6.15
TurboDebugger v5


Target


Deep Paint 1.0c (by Right Hemisphere Ltd). http://www.rightemisphere.com


Explications


1. L'Anti-Sice

:01E768F0 55             push   ebp
:01E768F1 56             push   esi
:01E768F2 57             push   edi
:01E768F3 8BEC           mov    ebp,esp
:01E768F5 B989179000     mov    ecx,00901789
:01E768FA BECE517400     mov    esi,007451CE
:01E768FF 33F1           xor    esi,ecx        ;ESI = 901789 XOR 7451CE = E44647
:01E76901 B8C4320500     mov    eax,000532C4
:01E76906 03C1           add    eax,ecx        ;EAX = 901789 + 532C4 = 954A4D
:01E76908 33FF           xor    edi,edi
:01E7690A 97             xchg   edi,eax        ;EDI = EAX = 954A4D
:01E7690B 3BC1           cmp    eax,ecx        ;EAX = 0 != ECX = 901789 => Toujours différent !
:01E7690D 7501           jne    01E76910       ;Ce jne est donc en réalité un jump inconditionnel
:01E7690F 8B
:01E76910 CC             int    3              ;Interruption 3 avec DI = 4A4D ( Magic Number 1 )
                                               ;                 et SI = 4647 ( Magic Number 2 )
:01E76911 8BC1           mov    eax,ecx
:01E76913 5F             pop    edi
:01E76914 5E             pop    esi
:01E76915 5D             pop    ebp
:01E76916 C3             ret

:0700F795 FF65FC         jmp    [ebp-04]
:0700F79833C0           xor    eax,eax        ;On revient ici

De manière à ne pas pouvoir modifier directement dans la DLL cette portion de code est décrypté en mémoire dans de l'espace alloué avec VirtualAlloc, puis, après exécution, effacée avec VirtualFree. On ne peut donc pas mettre de BPM en 01E76910 car cette addresse change tout le temps. La solution est donc de mettre le BPM en 0700F795. Maintenant que nous avons cela, on peut retourner sous Sice, et mettre un BPM 0700F795 X après le lancement avec le Symbol Loader. Je rapelle que le BPM ... X permet de ne pas modifier le code en mémoire et ainsi éviter des erreurs aux cas d'un CRC Check par exemple. Lorsqu'on breakera, il suffira dès lors de tracé jusqu'à l'Int 3 et de remplacer SI ou DI par une autre valeur avant son exécution.

2. La DialogBox

Maintenant, nous nous retrouvons devant le même shéma de protection que les anciennes version de VBox. Je réexplique rapidement. L'appuis sur la touche Try renvois 0 dans EAX. Ensuite, un peu après la DialogBox, un appel à RaiseException affiche les messages d'erreurs liés aux temps, etc.. Donc, le patch consistera à forcé le renvois de 0 dans EAX par la DialogBox et à ne pas exécuté RaiseException tout en faisant bien garde à rétablir la pile. Tout ceci peut être fait à l'aide de Softice très simplement.

0177:080078EC  8B0D68C90D08        MOV       ECX,[080DC968]
0177:080078F2  A1D03E0D08          MOV       EAX,[080D3ED0]
0177:080078F7  57                  PUSH      EDI
0177:080078F8  68B07E0008          PUSH      08007EB0
0177:080078FD  8B513C              MOV       EDX,[ECX+3C]
0177:08007900  8B4808              MOV       ECX,[EAX+08]
0177:08007903  52                  PUSH      EDX
0177:08007904  68CB000000          PUSH      000000CB
0177:08007909  51                  PUSH      ECX
0177:0800790A  FF1560670E08        CALL      [USER32!DialogBoxParamA]

Après l'appel à DialogBoxParamA on fait un R EAX 0 pour mettre EAX à 0. On trace jusqu'au RaiseException situé ici :

0177:070570D1  52                  PUSH      EDX
0177:070570D2  8B54240C            MOV       EDX,[ESP+0C]
0177:070570D6  50                  PUSH      EAX
0177:070570D7  51                  PUSH      ECX
0177:070570D8  52                  PUSH      EDX
0177:070570D9  FF15585A0807        CALL      [KERNEL32!RaiseException]

Arrivé en :070570D9 il suffit de faire R EIP EIP+6 pour éviter ce call et R ESP ESP+10 pour rétablir la pile ( 4 Paramètres ). Maintenant que nous savons cela, nous pouvons commencer le patch.

3. Idée Intuitive

Comme je disais en introduction, nous allons appliquer notre patch non pas sur l'éxécutable lui-même car alors il faudrait recommencer à chaque fois, ni sur la DLL à cause du CRC-Check mais nous allons dévier l'appel aux Fonctions API concernée. Je rappelle que ces fonctions sont DialogBoxParamA de User32.DLL et RaiseException de Kernel32.DLL. En gros, il suffira de vérifié si c'est VBox qui appel la fonction, et si c'est le cas on applique les modification sinon on donne la main à la fonction original.

4. RaiseException - Kernel32.DLL

Commencons par le plus facile. Nous devons d'abord trouver de la place libre que nous trouvons facilement à la fin du fichier ( dans Kernel32.DLL ) :

:BFFE4800 0000                    add       [eax],al    @Offset 00074800 in File:Kernel32.DLL
...
:BFFE4820 0000                    add       [eax],al

Ensuite, nous allons modifier l'Export Table pour que lors de l'appel à la fonction, on passe d'abord par notre fonction. Pour cela, on désassemble Kernel32.DLL et on reguarde l'addresse de la fonction :

Exported fn(): RaiseException - Ord:0273h
:BFFA0ACB 9C                      pushfd                @Offset 00030ACB in File:Kernel32.DLL

Maintenant, avec HView on recherche CB 0A 03 00 dans Kernel32.DLL et on le remplace par 00 48 07 00. On rajoute enfin notre fonction:

.BFFE4800: 813C24DF700507               cmp       d,[esp],0070570DF  ;Vérifie si on vient de VBox
.BFFE4807: 7405                         je       .0BFFE480E          ;Si oui, on saute
.BFFE4809: E9BDC2FBFF                   jmp      .0BFFA0ACB          ;sinon, Jmp RaiseException
.BFFE480E: 83C414                       add       esp,014            ;On retablit la pile
.BFFE4811: FF6424EC                     jmp       d,[esp][-0014]     ;et on retourne dans VBox

5. DialogBoxParamA - User32.DLL

Maintenant, nous allons nous attaquer au gros morceau. Nous allons, comme pour Kernel32.DLL, dévier grace à l'Export Table DialogBoxParamA vers notre fonction que nous écriverons à la fin du fichier User32.DLL. Il nous faudra aussi 2 DWord où sauveguarder Adresse de Retour ainsi que l'Adresse de la Dialog Proc. Pour les 2 DWord, nous avons le champs libre dans la section .DATA en 0BFF5D000 et 0BFF5D004.

Exported fn(): DialogBoxParamA - Ord:0091h
:BFF52FD5 B12E                    mov cl, 2E              @Offset 00002FD5 in File:User32.DLL

:BFF605D0 0000                    add       [eax],al      @Offset 000105D0 in File:User32.DLL
...

Il faut donc rechercher et remplacer D52F0000 par D0050100 dans l'Export Table. Ensuite on écris notre fonction :

:BFF605D0 51                      push ecx                      ;Sauve le registre
:BFF605D1 8B4C2404                mov ecx, dword ptr [esp+04]   ;Récupère l'Adresse de Ret
:BFF605D5 890D00D0F5BF            mov dword ptr [BFF5D000], ecx ;Sauve l'AddDeRet
:BFF605DB 81398B0D48C9            cmp dword ptr [ecx], C9480D8B ;Reguarde si on viens de VBox
:BFF605E1 7512                    jne BFF605F5                  ;Sinon on saute
:BFF605E3 8B4C2414                mov ecx, dword ptr [esp+14]   ;Si oui, on récupère la WinProcAdresse
:BFF605E7 890D04D0F5BF            mov dword ptr [BFF5D004], ecx ;On la sauve
:BFF605ED C74424141906F6BF        mov [esp+14], BFF60619        ;Et on la remplace par notre Proc

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:BFF605E1(C)
|
:BFF605F5 59                      pop ecx                       ;On restaure le registre
:BFF605F6 83C404                  add esp, 00000004             ;
:BFF605F9 E8D729FFFF              call BFF52FD5                 ;DialogBoxParamA
:BFF605FE 83EC04                  sub esp, 00000004             ;
:BFF60601 51                      push ecx                      ;On sauve le registre
:BFF60602 8B0D00D0F5BF            mov ecx, dword ptr [BFF5D000] ;On récupère l'AddDeRet
:BFF60608 894C2404                mov dword ptr [esp+04], ecx   ;On la remet sur la pile
:BFF6060C 81398B0D48C9            cmp dword ptr [ecx], C9480D8B ;On reguarde si on vient de VBox
:BFF60612 7502                    jne BFF60616                  ;Sinon on saute
:BFF60614 33C0                    xor eax, eax                  ;Si oui, EAX == 0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:BFF60612(C)
|
:BFF60616 59                      pop ecx                       ;On restaure le registre
:BFF60617 C3                      ret                           ;On redonne la main au programme
 

:BFF60618 90                      nop                           ;DialogProc
:BFF60619 837C240818              cmp dword ptr [esp+08], 00018 ;Chargement de la DialogBox terminée ?
:BFF6061E 7510                    jne BFF60630                  ;Sinon on saute
:BFF60620 C744240811010000        mov [esp+08], 00000111        ;Si oui, on injecte le message
                                                                ;WM_COMMAND avec comme paramètre
:BFF60628 C744240C95040000        mov [esp+0C], 00000495        ;l'ID du bouton EXIT

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:BFF6061E(C)
|
:BFF60630 FF2504D0F5BF            jmp dword ptr [BFF5D004]      ;On redonne la main à la DialogProc

Maintenant que les modifications ont été faites, vous devez quittez Windows ( Redémarrage en mode MS-Dos ) et remplacer les Kernel32.DLL et User32.DLL par les fichiers modifiés.
 

Exodus

Je ne sais pas si ce crack fonctionnera pour tout les programmes VBoxés. Cependant, rien n'empèche à ce cours d'évoluer et donc, si il existe des erreurs, ou si des optimisations peuvent arriver par la suite, je les rajouterai avec grand plaisir. De plus, les seules modifications qui pourraient, à mon avis, arriver serait le moyen de savoir si on vient bien de VBox ce qui est loin d'être la plus grosse difficulté. Je terminerai par dire que même si l'API Spoofing est une technique très intéressante, je ne vous conseille pas de modifier Kernel32.DLL comme je le fait ici pour toute les protections existantes sans quoi vous risqué de gros ralentissement. Sur ce, je vous laisse et espère vous avoir appris quelquechose.

Rem : Ce crack n'a été utilisé qu'avec DeepPaint. Car il semble qu'il y ai une différence de version de VBox entre celui fourni avec DeepPaint et GoLive.. et je n'ai que ceux là. Si vous pourriez tester cette métode et me tenir au courant, j'aimerais vérifié au plus vite ! Merci.
 

Greetz

Je voudrais saluer principalement Christal et toutes les personnes motivées de la scène francophone qui ne se prennent pas la tête !
 
 
Amicalement
TeeJi