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 |
|
Section Header |
|
Section1 |
|
... |
|
Section n |
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
­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