PRELUDE

Hello,

Je discutais aujourd'hui 30 Avril 2000 avec DarkAngel, et voilà un log de notre conversation :

...
<DarkAnge1> pour le news defis fcf tu peux me donner ton avis de reverser ?
<TeeJi> oui
<DarkAnge1> il s'agit de rajouter une dll + un password (dialogboxa)
<TeeJi> tres bien..
<TeeJi> met defini bien ce que tu veux...
<DarkAnge1> attend je te dis ce k'il y a dans les explications :
<DarkAnge1> Pour ce nouveau défis (toujours sur le reverse) il va falloir rajouter des fonctions à un programme mais plus particulierement rajouter une DLL à ce programme cette dll pourra contenir aussi bien une simple messageboxa que le keygen pour le numero de serie du prog.(Bien évidement cetains imports sont manquants, comme "LoadLibrary" c'est donc a vous de les rajouter :-)
<DarkAnge1> Enfin ce serai bien que vous rajoutiez un password, et un timer enfin si c'est pas trop demander :-) Voila c'est tout.Bien évidement n'hésit
<DarkAnge1> la cible c'est AceFTP ki possedent pas mal d'imports et ki je pense est prog en delphi
<DarkAnge1> alors est il suffisement interessant ???
<TeeJi> oui, tres bien
<TeeJi> mais il faut voir comment il vont le realiser..
<TeeJi> Si il y a qqn qui expliquerait comment reconstruire une ImportTable et l'ImportDirectory, ce serait super..
<DarkAnge1> je ne suis pas sur k'il y ait beaucoup de reponses mais bon :)
<TeeJi> Tu veux que les fonctions soit dans l'IAT ?
<TeeJi> ou que la DLL soit simplement chargée ?
<DarkAnge1> ke la dll soit chargee c'est suffisant mais rajouter les api dans l'iat c'est excellent mais personne ne va se faire chier comme ca :-)
<TeeJi> je me doute :)
<TeeJi> tu veux que j'essaye d'expliquer comment le rajouter dans l'IAT ?
<TeeJi> ce serait intéressant...
<DarkAnge1> oui je veux bien si tu pouvais faire un petit tutor la dessus :)
...
<DarkAnge1> www.fcf2000.org/defis.html     <== si tu veux recuperer la target du defis
<DarkAnge1> a+
<TeeJi> a+
Session Close: Mon May 01 00:15:49 2000

Donc voilà, je vais faire ce que j'ai dis, rajouter une DLL et ses fonctions dans l'IAT.

Evidemment, quand on l'entend comme ça, ça pourrait paraître compliquer et je ne vous cacherez pas que j'ai eu peur un instant après en me demandant si cela était même possible. Je vous rassure, si ce cours existe c'est que c'est totalement faisable, à condition de bien connaître le format PE.

MISE EN CONDITION

Allons-y d'abord pour une petite explication du Format PE en ce qui concerne les Import :

Un Fichier PE est constituer ainsi :
 
 

Exe Header

Coff Header

Optional Header
qui contient les Data Directories

Section Header

Section1

...

Section n

Ce que nous voulons modifier, c'est ce qui à un rapport avec les Imports, soit la valeur du Data Directory IMAGE_DIRECTORY_ENTRY_IMPORT qui se trouve dans l'Optional Header. Pour caclculer sa position, il faut reguarder le DWord situé à l'offset 0x03C qui nous donne l'offset du Coff Header. L'OptionalHeader commence en CoffHeader+0x18 et le Data Directory qui nous intéresse est en OptionalHeader+0x68. Le Data Directory se compose ainsi :

    Address        Size
   ?? ?? ?? ??    ?? ?? ?? ??         ; IMAGE_DIRECTORY_ENTRY_IMPORT

A l'adresse donnée ( RVA ), nous trouvons l'IMAGE_IMPORT_DESCRIPTOR qui est une structure comme celle-ci ci-dessous. Si on suppose qu'il y a 2 DLL :

Pour la 1ere DLL :
    OriginalFirstThunk      ?? ?? ?? ??     ; RVA to orig. 1st thunk
    TimeDateStamp           ?? ?? ?? ??     ;
    ForwarderChain          ff ff ff ff     ; no forwarders
    DLLName                 ?? ?? ?? ??     ; RVA to DLL name
    FirstThunk              ?? ?? ?? ??     ; RVA to 1st thunk
Pour la seconde DLL :
    OriginalFirstThunk      ?? ?? ?? ??     ; RVA to orig. 1st thunk
    TimeDateStamp           ?? ?? ?? ??     ;
    ForwarderChain          ff ff ff ff     ; no forwarders
    DLLName                 ?? ?? ?? ??     ; RVA to DLL name
    FirstThunk              ?? ?? ?? ??     ; RVA to 1st thunk
Pour terminer :
    00 00 00 00
    00 00 00 00
    00 00 00 00
    00 00 00 00
    00 00 00 00

En DLLName, on trouve :

Le nom de la DLL, terminé par 0x00 :
    6b 65 72 6e 65 6c 33 32 2e 64 6c 6c 00  ; "kernel32.dll"
    00 00 00                                ; et on doit completer pour l'alignement 32 bits.

En OriginalFirstThunk, on trouve une structure comme ceci, en supposant qu'il y aie 2 fonction importées :

    AddressOfData   30 02 00 00             ; RVA vers le nom de la fonction ( ex : "WriteConsoleA" )
    AddressOfData   40 02 00 00             ; RVA vers le nom de la fonction ( ex : "GetStdHandle"  )
                    00 00 00 00             ; Pour terminer

En FirstThunk, on retrouve exactement la même chose que OriginalFirstThunk ( en réalité c'est pas exact mais nous allons faire comme si.. ).

Nous avons à présent tout ce qu'il nous faut pour rajouter une DLL dans l'IAT.

MISE EN PRATIQUE

Je prends comme outils de travail, Notepad.exe fournit avec Win98 SE FRA. J'utiliserai Hex WorksShop pour toutes les modifications. Allons-y. Recherchons d'abord l'adresse de l'IMAGE_DIRECTORY_ENTRY_IMPORT :

00000030:  00 00 00 00-00 00 00 00-00 00 00 00-80 00 00 00   ; 0x00000080 est le Coff Header

0x80 + 0x18 + 0x68 = 0x100

00000100:  00 60 00 00 ; 0x00006000 est l'IMAGE_DIRECTORY_ENTRY_IMPORT.

Donc, nous trouvons en 0x6000 l'IMAGE_IMPORT_DESCRIPTOR :

.00406000:  B0 61 00 00-93 A1 39 37-FF FF FF FF-8A 65 00 00
.00406010:  F0 63 00 00-18 61 00 00-B3 C2 1F 37-FF FF FF FF
.00406020:  9C 67 00 00-58 63 00 00-CC 61 00 00-91 A1 39 37
.00406030:  FF FF FF FF-92 6B 00 00-0C 64 00 00-B8 60 00 00
.00406040:  72 C2 3E 35-FF FF FF FF-F6 6C 00 00-F8 62 00 00
.00406050:  C0 62 00 00-93 A1 39 37-FF FF FF FF-7A 6D 00 00
.00406060:  00 65 00 00-A0 60 00 00-91 A1 39 37-FF FF FF FF
.00406070:  DA 6D 00 00-E0 62 00 00-00 00 00 00-00 00 00 00
.00406080:  00 00 00 00-00 00 00 00-00 00 00 00-

Rem : Un changement de couleur indique un changement de DLL.

Donc, nous voulons rajouter une structure pour notre DLL. La DLL que je vais utiliser est ma DLL Uring. Je rajouterai les fonctions Ring0 et Ring0Ret de ma DLL dans l'IAT.

Pour commencer, il nous faudrait rajouter 5 DWORD, ce qui est impossible à cet endroit. Je vais donc déplacer l'IMAGE_IMPORT_DESCRIPTOR vers un endroit vierge, par exemple ici :

.00406E00:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
...
.00406EE0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

Avec HWS, je sélectionne les bytes entre 6000 et 608C et je fait CTRL-C pour les copier. Ensuite je vais en 6E00, je selectionne 0x8C bytes et je fais CTRL-V pour les coller. Une fois cela de fait, je modifie le DWord en 0x100 par 0x00006E00 :

.00000100:  00 6E 00 00 ;L'IMAGE_IMPORT_DESCRIPTOR se trouve à présent en 0x6E00.

Si vous lancer maintenant Notepad.exe, tout devrait fonctionner. Hélas, ca ne fonctionne pas, et cela est dû à la section qui est utilisée pour d'autre chose. On va donc déplacer plutôt en 4F00, à la fin de la section .text :

.00404F00:  B0 61 00 00-93 A1 39 37-FF FF FF FF-8A 65 00 00
.00404F10:  F0 63 00 00-18 61 00 00-B3 C2 1F 37-FF FF FF FF
.00404F20:  9C 67 00 00-58 63 00 00-CC 61 00 00-91 A1 39 37
.00404F30:  FF FF FF FF-92 6B 00 00-0C 64 00 00-B8 60 00 00
.00404F40:  72 C2 3E 35-FF FF FF FF-F6 6C 00 00-F8 62 00 00
.00404F50:  C0 62 00 00-93 A1 39 37-FF FF FF FF-7A 6D 00 00
.00404F60:  00 65 00 00-A0 60 00 00-91 A1 39 37-FF FF FF FF
.00404F70:  DA 6D 00 00-E0 62 00 00-00 00 00 00-00 00 00 00
.00404F80:  00 00 00 00-00 00 00 00-00 00 00 00-

Maintenant tout fonctionne. ( Rem : n'oublier pas d'effacer le code que vous auriez mis en 6E00 ! )
On va à présent chercher les paramètres de notre structure :

    OriginalFirstThunk      ?? ?? ?? ??     ; RVA to orig. 1st thunk
    TimeDateStamp           ?? ?? ?? ??     ;
    ForwarderChain          ff ff ff ff     ; no forwarders
    DLLName                 ?? ?? ?? ??     ; RVA to DLL name
    FirstThunk              ?? ?? ?? ??     ; RVA to 1st thunk

On va mettre la DLLName juste après la structure de fin ( avec que des 00 ) :

.00404F70:  DA 6D 00 00-E0 62 00 00-00 00 00 00-00 00 00 00
.00404F80:  FF FF FF FF-00 00 00 00-00 00 00 00-00 00 00 00
.00404F90:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00404FA0:  75 72 69 6E-67 2E 64 6C-6C 00 00 00-00 00 00 00  uring.dll

En rouge nous avons notre structure et en bleu la DLLName ( 0-Terminated String ! ) La DLLName est en 0x4FA0 ( RVA )
On export 2 fonctions, donc l'OriginalFirstThunk sera de 3DWords, soit 0x0C Bytes. Idem pour le FirstThunk.

.00404FB0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00404FC0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

En vert sera l'OFT et en orange le FT. Nous devons ensuite mettre les structures IMAGE_IMPORT_BY_NAME :

.00404FC0:  00 00 00 00-00 00 00 00-01 00 52 69-6E 67 30 00          Ring0
.00404FD0:  02 00 52 69-6E 67 30 52-65 74 00 00-00 00 00 00  Ring0Ret

En rouge, ce sont les Ordinal des fonction qui ne doivent pas êtres obligatoirement correctes.

On peut maintenant remplir le OFT et le FT :

.00404FB0:  C8 4F 00 00-D0 4F 00 00-00 00 00 00-C8 4F 00 00
.00404FC0:  D0 4F 00 00-00 00 00 00-01 00 52 69-6E 67 30 00

On écrit notre IMAGE_IMPORT_DESCRIPTOR :

    OriginalFirstThunk      B0 4F 00 00     ; RVA to orig. 1st thunk
    TimeDateStamp           00 00 00 00     ;
    ForwarderChain          ff ff ff ff     ; no forwarders
    DLLName                 A0 4F 00 00     ; RVA to DLL name
    FirstThunk              BC 4F 00 00     ; RVA to 1st thunk

.00404F70:  DA 6D 00 00-E0 62 00 00-B0 4F 00 00-00 00 00 00
.00404F80:  FF FF FF FF-A0 4F 00 00-BC 4F 00 00-

On doit encore modifier l'IMAGE_DIRECTORY_ENTRY_IMPORT pour que tout fonctionne :

00000100:  00 4F 00 00-A0 00 00 00 ; N'oubliez pas de rajouter 0x14 à la Size ( En rouge ) !

Et on termine en essayant :). Le test pour ma part est très concluant.

Le seul ennuis, c'est que si vous avez mis l'IMAGE_IMPORT_DESCRIPTOR dans la section .text, vous perdez les infos d'Import avec WDasm. Ceci n'est pas le cas si vous créez une nouvelle section avec les caracteristiques 0x40000040 et que vous mettez l'IMAGE_IMPORT_DESCRIPTOR dedans :

Ma nouvelle section .TeeJi ( lisez mon cours sur les section pour savoir comment on rajoute une section ) :

00000240:  2E 54 65 65-4A 69 00 00-00 10 00 00-00 E0 00 00  .TeeJi      Ó
00000250:  00 10 00 00-00 E0 00 00-00 00 00 00-00 00 00 00      Ó
00000260:  00 00 00 00-40 00 00 40-00 00 00 00-00 00 00 00      @  @

Et voici l'IMAGE_IMPORT_DESCRIPTOR :

.0040E000:  B0 61 00 00-93 A1 39 37-FF FF FF FF-8A 65 00 00  _a  ôí97    èe
.0040E010:  F0 63 00 00-18 61 00 00-B3 C2 1F 37-FF FF FF FF  &shy;c  a  ¦- 7
.0040E020:  9C 67 00 00-58 63 00 00-CC 61 00 00-91 A1 39 37  £g  Xc  ¦a  æí97
.0040E030:  FF FF FF FF-92 6B 00 00-0C 64 00 00-B8 60 00 00      Æk  d  ©`
.0040E040:  72 C2 3E 35-FF FF FF FF-F6 6C 00 00-F8 62 00 00  r->5    ÷l  °b
.0040E050:  C0 62 00 00-93 A1 39 37-FF FF FF FF-7A 6D 00 00  +b  ôí97    zm
.0040E060:  00 65 00 00-A0 60 00 00-91 A1 39 37-FF FF FF FF   e  á`  æí97
.0040E070:  DA 6D 00 00-E0 62 00 00-B0 E0 00 00-00 00 00 00  +m  Ób  _Ó
.0040E080:  FF FF FF FF-A0 E0 00 00-BC E0 00 00-00 00 00 00      áÓ  +Ó
.0040E090:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.0040E0A0:  75 72 69 6E-67 2E 64 6C-6C 00 00 00-00 00 00 00  uring.dll
.0040E0B0:  C8 E0 00 00-D0 E0 00 00-00 00 00 00-C8 E0 00 00  +Ó  ðÓ      +Ó
.0040E0C0:  D0 E0 00 00-00 00 00 00-01 00 52 69-6E 67 30 00  ðÓ      Ring0
.0040E0D0:  02 00 52 69-6E 67 30 52-65 74 00 00-00 00 00 00  Ring0Ret

Rem : N'oubliez pas de copier la DLL soit dans le repertoire de l'Executable, soit dans le repertoire system de Windows.

PREUVE

   Object06: .TeeJi   RVA: 0000E000 Offset: 0000E000 Size: 00001000 Flags: 40000040

   Import Module 007: uring.dll

 Addr:0000E0C8 hint(0001) Name: Ring0
 Addr:0000E0D0 hint(0002) Name: Ring0Ret

Rem : A côté d'Addr:, c la valeur du FirstThunk qui devrait être en réalité l'adresse 'censée' de nos fonctions en mémoire. Mais cela à que très peut d'importance.

RESUME

Pour terminer, je vais résumer les grandes étapes :

    - Rechercher l'IMAGE_IMPORT_DESCRIPTOR
    - Le déplacer dans un endroit libre avec assez d'espace pour rajouter une structure.
    - Ecrire le nom de la DLL, réserver l'espace pour l'OriginalFirstThunk et le FirstThunk et écrire le nom des fonctions importées
    - Modifier l'OFT, l'FT et la structure IMAGE_IMPORT_DESCRIPTOR avec les RVA correspondant.
    - Modifier l'Adresse et la Size de l'IMAGE_DIRECTORY_ENTRY_IMPORT

Voilà, maintenant il vous faut appliquer cela à d'autres programme. Si une erreur se trouve dans cet essai, j'aimerais en être au courant de manière à apporter correction. Merci !

Amicalement,
TeeJi