In most files, the EP is in the first section. In many packers or file infecters, it will be in another section. It's actually common in the header itself (Upack, FSG), and sometimes (like - among others - in collapsed.asm), it's at RVA 0, in which case the MZ signature is just interpreted as dec ebp, pop edx, which is benign. Many packers just put some trampoline code at RVA 0, then the rest of the code further.
So, usually:
Section0 VA <= EntryPoint <= Section0 VA + Physical Sizeand to a general extend:
0 <= EntryPoint <= SizeOfImageBut no check is actually done on the EntryPoint value!
If there is no need to execute any code, no problem will occur:
some PE files are just used as resource containers, for example storing images and icons used in several products or softwares. In this case, there is no code whatsoever, thus no expected execution. The only form of interaction with this file is via the resource APIs.
In a DLL, the code at the EntryPoint (DllMain) is executed on loading and unloading, whether it's loaded normally or via LoadLibraryA/FreeLibrary (LoadLibraryEx is an exception, you can specify it NOT to run DllMain, aka the code at the EP of the DLL).
So, if you always load a DLL with LoadLibraryEx and the right parameters, the EP value will not be used.
In both cases, the EP value could be bogus.
Moreover, if the EP is actually executed (which just means, code at EP + IMAGEBASE is executed) and no problem happens, it's still ok!
Example:
- Open Notepad in a debugger, check ExitProcess address: 7C81CB12 ExitProcess 8BFF MOV EDI,EDI)
- Set the EP to that address (substract IMAGEBASE): 7c81cv12 - 1000000 = 7B81CB12)
- Run...execution starts directly at ExitProcess...
Even better, if you force your code to be at some address, via, for example, a DLL without relocations, and an executable that imports this DLL, with the right EP value, in the expected DLL code, you can get a working PE , with a huge or a negative EntryPoint...
In my example, no_relocs.dll:
IMAGEBASE 330000h, Relocation 0
Section 0 VA 200
push MB_ICONINFORMATION ; UINT uType
push tada ; LPCTSTR lpCaption
...
And the loader no_relocs_loader.exe:
EntryPoint: FFF30200
ImageBase: 00400000
=> Execution at 00330200 = Start of Section 0 of no_relocs.dll
So this file, empty with a negative EntryPoint, just runs fine.
In conclusion, it's difficult to decide in advance if an EntryPoint value is valid or not. It's just possible to say if it's standard or not.
Original idea from Costin Ionescu.
Binaries Sources: dll loader
[...]
Faire des misères à l'EntryPoint
Dans la plupart des fichier, l'EP est dans la première section. Dans beaucoup de packeurs ou d'infecteurs, il sera dans une autre section. C'est aussi courant de le trouver dans l'en-tête lui-même (Upack, FSG), et parfois (comme - entre autres - dans collapsed.asm), il est à la RVA 0, auquel cas la signature MZ est juste interprétée comme dec ebp, pop edx, ce qui est bénin. Beaucoup de packers mettent just du code 'trampoline' à RVA 0, et le reste du code est ailleurs.
Donc, d'habitude :
Section0 VA <= EntryPoint <= Section0 VA + Physical Sizeet de manière générale :
0 <= EntryPoint <= SizeOfImage
Mais en fait, il n'y a aucune vérification sur la valeur de l'EntryPoint !
Si il n'y a pas besoin d'exécuter du code, aucune erreur ne se produira :
Certains PE sont juste utilisés comme conteneurs de resources, par exemple pour stocker les images et les icones utilisées dans plusieurs produits ou programmes. Dans ce cas, il n'y a pas le moindre code, donc pas d'exécution à attendre. L'unique forme d'interaction avec se fichier se fera via les APIs de ressources.
Dans une DLL, le code à l'EntryPoint (le DllMain) est exécuté au chargement et au déchargement, que ce soit normalement ou via LoadLibraryA/FreeLibrary) (LoadLibraryEx est une exception, on peut spécifier de ne PAS exécuter le DllMain).
Donc, si on charge toujours une DLL avec LoadLibraryEx et les bons paramètres, la valeur de l'EP ne sera pas utilisée.
In both cases, the EP value could be bogus.
De plus, si l'EP est executé (ce qui signifie uniquement que l'execution est transférée à EP + IMAGEBASE) et que rien ne se passe de mal, tout va bien !
Exemple:
- Ouvrez Notepad dans un debugger, notez l'adresse d'ExitProcess : 7C81CB12 ExitProcess 8BFF MOV EDI,EDI)
- Changez l'EP vers cette adresse (soustraire l'IMAGEBASE): 7c81cv12 - 1000000 = 7B81CB12)
- Lancez... l'exécution débute directement à ExitProcess...
Encore mieux, si vous forcez l'exécution à une adresse, via par exemple, une DLL sans relocations, et un exécutable importe cette DLL, avec la bonne valeur d'EP, qui pointe sur le code de la DLL, on obtient un PE qui tourne, avec un EP trop haut ou au contraire négatif...
Dans mon example, no_relocs.dll :
IMAGEBASE 330000h, Relocation 0
Section 0 VA 200
push MB_ICONINFORMATION ; UINT uType
push tada ; LPCTSTR lpCaption
...
Et dans le chargeur, no_relocs_loader.exe :
EntryPoint: FFF30200
ImageBase: 00400000
=> Exécution à 00330200 = Début de la Section 0 de no_relocs.dll
Donc ce fichier, vide et avec un EntryPoint négatif, fonctionne correctement.
En conclusion, il est difficile de dire à l'avance si un EntryPoint est correct ou non. Mais il est facile de déterminer s'il est standard ou non.
Idée originale de Costin Ionescu.
Binaires Sources: dll loader
You should write about relocation table tricks. It's possible to place the entrypoint outside of the file, then use relocations on the imagebase to move it back in... :-)
ReplyDeleteI thought relocation tricks were not funny, but it looks like I was wrong. I will give it a try.
ReplyDelete