Map and projects (the most frequently updated page of this blog)

2010/01/22

On aura plus de pain sur la planche, parce que la planche aura brûlé

messing with sections physical offset
With a high alignment (>= 1000h), nothing prevents 2 sections to come from the same physical data.
Thus, if 2 sections with different virtual addresses have the same PointerToRawData and SizeOfRawData, their content will be initially the same. Relocations and imports will be applied afterward though.
SECTION_0:
.VirtualSize dd Section0Size
.VirtualAddress dd Section0Start - IMAGEBASE
.SizeOfRawData dd Section0Size
.PointerToRawData dd Section0Start - IMAGEBASE
...
SECTION_1:
.VirtualSize dd Section0Size *same
.VirtualAddress dd Section1Start - IMAGEBASE
.SizeOfRawData dd Section0Size *same
.PointerToRawData dd Section0Start - IMAGEBASE *same

A section can be virtually non-empty and physically empty. In this case, it will just be full of zero. It's a common way to create space for uninitialized data, or in packers, to create memory space for the original sections without the need to allocate memory yourself.

You'd expect a physically empty section to have an empty physical size.
But if only the PointerToRawData is null (and not SizeOfRawData), the section will still be seen as physically empty, thus full of zero.
However, if PointerToRawData is smaller than 0200h (this value is independent of the Section or File Alignment), it will be rounded to 0, without the 'empty zero-ed effect'.
So, with a Section with a PointerToRawData between 1 and 1ffh, and a physical size equal to the PE, you can map the whole PE in a duplicate way.
whole_pe_offset equ 1; < 200h otherwise not rounded to 0
SECTION_1:
.VirtualSize dd pe_size
.VirtualAddress dd pe_size
.SizeOfRawData dd pe_size - whole_pe_offset
.PointerToRawData dd whole_pe_offset

In the 2 files, I made the code jump to its copy. Don't set your breakpoints in the wrong parts that are not executed!

Thanks to Costin Ionescu.

Sources and binaries

[...]
faire des misères physiques aux sections
Dans le cas d'un alignement élevé (>= 1000h), rien n'empêche 2 sections d'être basées sur les mêmes données physiques.
Donc, si 2 sections aux adresses virtuelles différentes ont les mêmes PointerToRawData et SizeOfRawData, leur contenu sera initialement le même. Les relocations et les imports seront pris en compte ensuite, cependant.
SECTION_0:
.VirtualSize dd Section0Size
.VirtualAddress dd Section0Start - IMAGEBASE
.SizeOfRawData dd Section0Size
.PointerToRawData dd Section0Start - IMAGEBASE
...
SECTION_1:
.VirtualSize dd Section0Size *même valeur
.VirtualAddress dd Section1Start - IMAGEBASE
.SizeOfRawData dd Section0Size *même valeur
.PointerToRawData dd Section0Start - IMAGEBASE *même valeur

Une section peut être virtuellement non vide, et physiquement vide. Dans ce cas, elle sera juste remplie de zéros. C'est une méthode standard pour créer de l'espace pour les données non initialisées, ou dans les packeurs, pour créer de l'espace mémoire à la place des sections originales, sans avoir à initialiser de la mémoire soi-même.

On s'attend à ce qu'une section vide physiquement ait une taille physique vide.
Mais si seul le PointerToRawData est nul (et non la SizeOfRawData), la section sera toujours vue comme physiquement vide, donc pleine de zéros.
Cependant, si PointerToRawData est plus petit que 0200h (cette valeur est indépendante des alignements de fichier ou de section), il sera arrondit à zéro, sans l'effet 'rempli de zéro'.
Donc, avec une section avec un PointerToRawData entre 1 et 1ffh, et une taille physique égale au PE, on peut mapper le PE entier dans une copie.
whole_pe_offset equ 1; < 200h otherwise not rounded to 0
SECTION_1:
.VirtualSize dd pe_size
.VirtualAddress dd pe_size
.SizeOfRawData dd pe_size - whole_pe_offset
.PointerToRawData dd whole_pe_offset

Dans les 2 fichiers, j'ai fait sauter le code vers sa copie. Ne mettez pas les points d'arrêts sur la partie jamais exécutée!

Remerciements: Costin Ionescu.

Sources et binaires

No comments:

Post a Comment