Protection   Néolite  

Les Protections Renforcées

Outils   ProcDump Wdasm SoftIce    
Cible   NotePad  

By TeeJi

Préface

    Je vais aujourd'hui aborder NeoLite de NeoWorx Inc.

 

Neolite.jpg

 NeoLite compresses Windows 32-bit .EXE files and DLLs.
It compresses them in such a manner that they are still executed normally. No
additional software is required to run the compressed software, it is completely
transparent.  There is no speed penalty incurred.

The slowest thing in a typical computer system is the hard drive (or worse,
the network connection), so many programs actually load faster after being
compressed with NeoLite.  Execution performance is completely unchanged, and
in a networked office it can greatly reduce network traffic from the loading
of executables from central servers.

NeoLite typically provides a 50% space savings, sometimes over 70%!

NeoLite can be used with any standard .EXE and .DLL files, and most .OCX and
.VBX files, including those created with Visual Basic, Visual C++, Inprise
(Borland) Delphi, C++ Builder, WatCom C++, LabView, etc.

NeoLite should not be used on self-extracting archive files.

 

Outils Utilisés

    Pour mon étude, j'ai utilisé

  • NeoLite 2.0 Trial
  • Notepad.exe et Calc.exe fournis en standard avec Windows. ( Version fournie avec Windows 95 OSR 2. )
  • ProcDump v1.5 build 0
  • Hview 6.15
  • WDasm 8.93 et 6.9
  • SoftIce 4.0

Première approche et unique approche.

    Bon, cette fois-ci je vais tout retaper car à force de reprendre ce que j'avais dis à l'étude précédente, je parle de choses inutiles. Je vais dans cette étude, expliquer une autre méthode que celle que j'ai utilisée juqu'à présent dans WWPack32, UPX et AS-Pack. Non seulement parceque la protection est plus pensée et plus subltile. Mais aussi parcequ'il faut connaître des méthodes différentes ( bien que celle que j'ai donné puisse fonctionner avec cette protection ) pour arriver à notre fin.

    Commencons comme d'habitude par comparer le PE Header original avec celui compressé avec NeoLite :
 
Avant compression :

Disassembly of File: originalNotepad.exe 
Code Offset = 00000400, Code Size = 00003A00 
Data Offset = 00003E00, Data Size = 00000400
Number of Objects = 0006 (dec), Imagebase = 00400000h
   Object01: .text    RVA: 00001000 Offset: 00000400 Size: 00003A00 Flags: 60000020 
   Object02: .bss     RVA: 00005000 Offset: 00000000 Size: 00000000 Flags: C0000080 
   Object03: .data    RVA: 00006000 Offset: 00003E00 Size: 00000400 Flags: C0000040 
   Object04: .idata   RVA: 00007000 Offset: 00004200 Size: 00000E00 Flags: 40000040 
   Object05: .rsrc    RVA: 00008000 Offset: 00005000 Size: 00003200 Flags: 40000040 
   Object06: .reloc   RVA: 0000C000 Offset: 00008200 Size: 00000A00 Flags: 42000040

Après le passage de NeoLite :

Disassembly of File: neoNotepad.exe 
Code Offset = 00001200, Code Size = 00001B90 
Data Offset = 00000000, Data Size = 00000400
Number of Objects = 3909 (dec), Imagebase = 8A5DCB2Ah
   Object01: .text    RVA: 00001000 Offset: 00000000 Size: 00003A00 Flags: C0000080 
   Object02: .bss     RVA: 00005000 Offset: 00000000 Size: 00000000 Flags: C0000080 
   Object03: .data    RVA: 00006000 Offset: 00000000 Size: 00000400 Flags: C0000080 
   Object04: .idata   RVA: 00007000 Offset: 00000400 Size: 00000200 Flags: 40000040 
   Object05: .rsrc    RVA: 00008000 Offset: 00000600 Size: 00000C00 Flags: 40000040 
   Object06: .reloc   RVA: 0000C000 Offset: 00000000 Size: 00000A00 Flags: 42000080 
   Object07: .neolit  RVA: 0000D000 Offset: 00001200 Size: 00001B90 Flags: E0000020 
   Object08:          RVA: 00000000 Offset: 00000000 Size: 00000000 Flags: 00000000 
   ... 
   Object3909:        RVA: 00000000 Offset: 00000000 Size: 00000000 Flags: 00000000

Program Entry Point = 0040D140 (neoNotepad.exe File Offset:0000FED0)
    Je sais que la première fois, cela parait étonnant, 3909 sections :) ! Ceci doit être une protection qui utilise certaines caractéristiques du PE Header, ou peut-être une erreur dans WDasm. Mais dans tout les cas, c'est juste là pour nous perturber.

     Nous pouvons constater déjà plusieurs choses :

  • La dernière section s'appelle .neolit. Vu que son nom n'est pas configurable avant compression, ce sera donc le moyen de reconnaître un programme compressé par NeoLite.
  • L'adresse de l'Entry Point du programme Compressé ( EPC ) se trouve dans la section .neolite.


    Je passe donc au désassemblage avec WDasm sans oublier de modifier les caractéristiques des sections. Je lance le désassemblage et ERROR ! Impossible de le désassembler avec WDasm 8.93 :( Bon, impossible n'existe pas dans mon vocabulaire, je vais donc attaquer ce programme compressé par NeoLite non pas avec WDasm 8.93 mais avec WDasm 6.9. Je change toutes les section en mettant Cxxxxxxx sauf .neolit à qui je donne les caractéristique E0000020. Je lance le désassemblage, il me dit qu'il y aune erreur dans le PE Header.. je click OK, et j'apperçois enfin le code désassemblé. Je remarque aussi que WDasm 6.9 ne prend en compte que les 7 première sections.

    Je me rend à l'adresse de l'EPC ( 40D140 ) et je vois ceci :
//******************** Program Entry Point ********
:0040D140 E9A6000000              jmp 0040D1EB
...
:0040D1E7 0D0A00008B              or eax, 8B00000A
:0040D1EC 44                      inc esp

    Nous nous trouvons donc devant un problème car le jmp ne saute pas sur une instruction correctement alignée. On va donc passer sous Softice pour pouvoir avoir les bonnes instructions. Je lance le programme compressé avec le Symbol Loader afin de breaker sur l'EPC mais je n'ai aucun résultat, Softice ne break pas. :(.

    Dans ce cas là, il y a 3 solutions à notre problème :

  • La première serait de jouer avec le PE Header jusqu'à ce que le Symbol Loader nous cède ( j'y arriverai par la suite ). Mais j'avoue y avoir passé quelques minutes en vaint.
  • La seconde est de calculer l'offset disque de l'EPC et de remplacer l'octet à cette adresse par CC ( = opcode de INT 03 ) et ensuite mettre un BPINT 03 sous Softice et lancer le programme, sans oublié de remplacer CC par la valeur d'origine à cet offset quand vous êtes sous Softice car sinon c'est le CRASH assuré.
  • La dernière qui fonctionna très bien chez moi, est d'abord de connaître sur quel segment se charge normalement les exécutables, sous Win9x, c'est 147:xxxxxxxx et de remplacer les xxx par la valeur de l'EPC. ( 0040D140 ). Esuite vous allez sous Softice avec CTRL-D ( par défaut ) et vous tapez : BPX 147:40D140. Lorsque vous lancerez votre programme, vous vous trouverez sous Softice lorsque son EIP sera à 40D140 ( soit la valeur de l'EPC )! Notez que cette méthode ne fonctionne pas à chaque fois.. à savoir pourquoi !?

Quand vous êtes enfin sous Softice, vous apercevez normalement ce qui suit :

0147:0040D140  E9A6000000          JMP       0040D1EB
...
0147:0040D1EB  8B442404            MOV       EAX,[ESP+04]
0147:0040D1EF  230551D14000        AND       EAX,[0040D151]
0147:0040D1F5  E8ED040000          CALL      0040D6E7

    Le call ci-dessus va décompresser le programme originale et va afficher le NagScreen me rappelant que j'ai utilisé une version Trial de NeoLite v2.0.

0147:0040D1FA  FE05EAD14000        INC       BYTE PTR [0040D1EA]
0147:0040D200  FFE0                JMP       EAX

    Le Call va renvoyé la valeur de l'Entry point du programme Original ( EPO ) dans EAX et le JMP EAX si dessus va donc donner la main au programme original.

    Nous savons donc trouver à présent la valeur de l'EPO et nous savons quelle est l'instruction qui y saute.
    Maintenant, il va falloire trouver un endroit ou installer notre Patch.
 
    Afin de trouver de l'espace libre, je retourne sous WDasm 6.9 à la recherche de 000000 20 Dup (00) qui se trouve généralement à la fin des section. Et dans notre cas, il faudrait qu'ils se trouvent à la fin de la section du Loader soit dans la section .neolit. Et malheureusement, il n'y a aucun 0000 à la fin de cette section. On va donc écrire notre patch dans les Information de Version ou sur l'Icone mais en tout cas autrepart que d'habitude. 

.00408725: 0000                         add       [eax],al 
.00408727: 0000                         add       [eax],al 
.00408729: 0000                         add       [eax],al 
.0040872B: 0000                         add       [eax],al 
.0040872D: 0000                         add       [eax],al 
.0040872F: 0000                         add       [eax],al 
.00408731: 0000                         add       [eax],al 
.00408733: 0000                         add       [eax],al 
.00408735: 0000                         add       [eax],al 
.00408737: 0000                         add       [eax],al 
.00408739: 0000                         add       [eax],al 
.0040873B: 0000                         add       [eax],al 
.0040873D: 0000                         add       [eax],al 
.0040873F: 0000                         add       [eax],al 
.00408741: 0000                         add       [eax],al 
.00408743: 0000                         add       [eax],al 
.00408745: 0000                         add       [eax],al

    J'ai trouvé cela en me baladant avec HView dans le code du programme, je crois qu'il y a là toute la place nécessaire à notre patch, encore faut-il qu'il n'utilise pas ce code. Pour cela, on va mettre un BPR 408725 408745 et vérifier si Softice break. Si c'est le cas, il faudrait trouver une autre solution. Allons y..

    Rem : J'ai trouvé un moyen pour que le Symbol Loader fonctionne. Il faut mettre toutes les sections avec les caractéristiques C0000040 sauf .text et .neolit à E0000020

    Résultat du BPR : négatif, il n'y a pas d'accès :). Maintenant, je vais creer notre patch ( le problème ici, est qu'il est limité à 34 bytes, mais vu que la modification que je vais faire à Notepad.exe n'est pas très imposante, cela suffira grandement ).

     je vais faire un patch pour notepad qui enlève l'accès à l'aide. Ceci n'a rien d'extraordinaire, je vais juste nopper le call WinHelpA. Je vais insérer mon patch en 0040D8725 et modifier le JMP EAX situé en 40D200 en un JMP 40D8725 pour qu'il jump sur mon patch. Je rajouterai aussi JMP EAX à la fin de mon patch. J'aurai surement besoin d'écraser l'instruction qui précède le JMP EAX pour mettre le JMP vers mon patch, ce qui ne pose pas de problème à partir du moment où vous n'oublier pas de rajouter toutes les instructions écrasées dans votre patch. Voici le résultat de mes opérations :  

:0040D1F5  E8ED040000          CALL      0040D6E7   | Le call du loader qui va décompresser 
:0040D1FA  E926B5FFFF          JMP       00408725   | Le jump vers mon patch 
:0040D1FF  00FF                ADD       BH,BH 
:0040D201  E080                LOOPNZ    0040D183 
:0040D203  3DEAD14000          CMP       EAX,0040D1EA
:00408725  FE05EAD14000        INC       BYTE PTR [0040D1EA]          | Je remet ce que j'ai écrasé 
:0040872B  C7052C12400090909090MOV       DWORD PTR [0040122C],90909090| Le crack 
:00408735  66C705301240009090  MOV       WORD PTR [00401230],9090     | / 
:0040873E  FFE0                JMP       EAX                          | Je saute vers l'EPO 
:00408740  0000                ADD       [EAX],AL                     | Le reste de l'espace libre 
:00408742  0000                ADD       [EAX],AL                     | 
:00408744  0000                ADD       [EAX],AL                     | 

 
    Après les modifications, je trace petit à petit, et lorsque j'arrive en 0040872B et que l'instruction
MOV DWORD PTR [0040122C],90909090 s'exécute, Erreur Fatal !! :(

    Ce problème, je ne l'ai encore jamais rencontré. Ce problème existe car NeoLite protège en écriture la mémoire utilisée par le programme original. Windows nous refuse donc toutes modifications du code et donc empèche de cracker le programme. Pour arriver à faire cela, NeoLite utilise untilise paraîtrait-il une API appelée VirtualProtect. Nous allons donc vérifier si ces dire sont corrects.

    Je relance donc le NotePad compressé avec NeoLite par le Symbol Loader. Arrivé dans Softice, je met un BPX VirtualProtect et je fait F5, puis F12 plusieurs fois tout en oubliant pas de noter les adresses appelant cette fonction. Voici ce que j'obtient :  

Break due to BPX KERNEL32!VirtualProtect  (ET=1.15 milliseconds) 
0147:0040DB56  FF5576              CALL      [EBP+76]
Break due to BPX KERNEL32!VirtualProtect  (ET=262.41 microseconds) 
0147:0040DB06  FF5576              CALL      [EBP+76]
Break due to BPX KERNEL32!VirtualProtect  (ET=30.46 microseconds) 
0147:0040DB56  FF5576              CALL      [EBP+76]
Break due to BPX KERNEL32!VirtualProtect (ET=399.81 microseconds) 
0147:0040DB56  FF5576              CALL      [EBP+76]
Break due to BPX KERNEL32!VirtualProtect  (ET=152.56 microseconds) 
0147:0040DB06  FF5576              CALL      [EBP+76]
Break due to BPX KERNEL32!VirtualProtect  (ET=38.89 microseconds) 
0147:0040DBE2  FF5576              CALL      [EBP+76]
Break due to BPX KERNEL32!VirtualProtect  (ET=443.17 microseconds) 
0147:0040DCC6  FF5576              CALL      [EBP+76]  

      Maintenant que nous avons tout les appels à cette fonction, nous mettons un BPX sur chacun d'entre-eux et chaque fois que nous breakons, On les noppe et on reguarde si le programme original se lance toujours très bien. Je vous rassure tout de suite, il se lance à merveille ! :)
    Nous allons donc voir si on peut directement les patcher sur disque. Ce qui est tout à fait possible :  

.0040DB06: 90                           nop 
.0040DB07: 90                           nop 
.0040DB08: 90                           nop
.0040DB56: 90                           nop 
.0040DB57: 90                           nop 
.0040DB58: 90                           nop
.0040DBE2: 90                           nop 
.0040DBE3: 90                           nop 
.0040DBE4: 90                           nop
.0040DCC6: 90                           nop 
.0040DCC7: 90                           nop 
.0040DCC8: 90                           nop

    Je sauve les modifications faites avec HView, et je relance le programme pour voir si il fonctionne toujours ( au cas probable ou il y aurait un CRC Check ). Le résultat est ce que nous attendions. Pas de CRC Check !:). Nous allons denouveau essayer notre patch ( en le construisant à l'aide de Doftice ) et nous vérifirons ainsi si il n'y a plus d'Erreur Fatal lors d'un accès en écriture sur le Code du programme décompressé.

    C'est le moment de vérité...  tout fonctionne :) !! Essayons de repérer maintenant les adresses des instructions à modifier relativement à l'EPC :
 

  • L'intruction qui donne la main au programme décompressé ( ici JMP EAX ) se trouve à 40D200-40D140 = 0x60 bytes de l'EPC
  • Les différents call VirtualProtect se trouvent à
  • 40DB06-40D140 = 0x9C6 bytes de l'EPC
  • 40DB56-40D140 = 0xA16 bytes de l'EPC
  • 40DBE2-40D140 = 0xAA2 bytes de l'EPC
  • 40DCC6-40D140 = 0xB86 bytes de l'EPC

Résumé et conclusions

    Résumons-nous maintenant :

  • Le compression est identifiable par la section .neolit.
  • Les adresses important donnée relativement à l'EPC sont notées juste ci-dessus.
  • Et je vous laisse trouver de l'espace inutiliser pour insérer votre patch. Je ne vais pas non plus tout faire pour vous :)

   Conclusions :
 


Amicalement,
TeeJi
teejee@hotmail.com