1

Voilà donc je suis en train d'écrire un programme relativement peu légal. Cela dit, j'ai besoin d'un pattern scanner de bytes, que j'ai déjà écrit.

Sauf que cette fois ci, sur l'exécutable que je vise, j'ai des trucs bizarres.
Je récupère les addresses de début et de fin de quelques segments:
IMAGE_NT_HEADERS* ntHeader = ImageNtHeader(GetModuleHandle(NULL)); IMAGE_SECTION_HEADER* sectionHeader = IMAGE_FIRST_SECTION(ntHeader); for (DWORD i = 0; i < ntHeader->FileHeader.NumberOfSections; ++i, ++sectionHeader) { if (memcmp((char*)sectionHeader->Name, ".text", 5) == 0) { StartTextAddress = sectionHeader->VirtualAddress + (DWORD)GetModuleHandle(NULL); EndTextAddress = StartTextAddress + sectionHeader->Misc.VirtualSize; } else if (memcmp((char*)sectionHeader->Name, ".rdata", 6) == 0) { StartRdataAddress = sectionHeader->VirtualAddress + (DWORD)GetModuleHandle(NULL); EndRdataAddress = StartRdataAddress + sectionHeader->Misc.VirtualSize; } else if (memcmp((char*)sectionHeader->Name, ".data", 5) == 0) { StartDataAddress = sectionHeader->VirtualAddress + (DWORD)GetModuleHandle(NULL); EndDataAddress = StartRdataAddress + sectionHeader->Misc.VirtualSize; } }
Sauf que par exemple, pour le segment .text, ça me sort 0x401000 - 0xDEC6CC.

rdata? 0xDED000 - 0x1059879
data? 0x105A000 - 0x125C5CE0

Un petit tour sur IDA?

Shs1q8m.png

De toute évidence mon beau calcul pour la fin du segment ne fonctionne plus....

Je suis pas encore un dieu des api windows, mais là tout de suite quelqu'un a une idée? Je pourrais tricher en regardant le début du prochain segment mais il ne me semble pas qu'il y ait garantie que tous les segments se suivent sans discontinuité...

J'ai modifé l'exécutable cible pour virer l'ASLR (C'est chiant et ça me ralentit), pour le reste c'est du propre. Ce petit snippet fonctionne parfaitement pour une version plus ancienne, je suis un peu à l'ouest...

Je tourne sur du Windows 7

[EDIT] tiens je viens de remarquer que le bousin se cassait totalement la gueule sur .rdata .... Marrant.

2

Je n'ai pas fait le calcul, mais peut-être que les adresses de fin affichées dans IDA sont arrondies par excès, pour que la taille du segment soit un multiple de la taille de page mémoire ?

Pour l'adresse de début différente, n'oublie pas qu'à moins qu'il n'y ait pas de table de relogement, les adresses dans le fichier exécutable ne sont qu'une suggestion. Le chargeur est libre de reloger les segments ailleurs, en particulier s'il y a un conflit.

EDIT : ah non, pour certains segments, l'adresse de fin n'est même pas un multiple de 16...
avatarZeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

3

Pourrais-tu afficher, en plus de Start, la valeur de la RVA elle-même? Ça pourrait donner des indices.
avatarMaintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

4

Hum "VirtualSize" ca sonne vaguement comme "prendre la taille supérieur qui colle le mieux a la pagination actuelle"

Sinon les valeurs début/fin, enfin surtout fin pour IDA ne sont pas forcement ce qui sera utilisé reelement.

Tu n'a pas moyen de recuperer la taille autrement que par "VirtualSize"?

Si tu peux:
VirtualSize
The total size of the section when loaded into memory, in bytes. If this value is greater than the VirtualSizeThe total size of the section when loaded into memory, in bytes. If this value is greater than the SizeOfRawData member, the section is filled with zeroes. This field is valid only for executable images and should be set to 0 for object files. member, the section is filled with zeroes. This field is valid only for executable images and should be set to 0 for object files.

Pourquoi tu n'utilse pas "SizeOfRawData" ?

cf: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx

D'ailleurs sachant que PhysicalAddress et VirtualSize sont dans une union, tu n'est pas juste en train de lire l'addresse physique et non la taille, et aussi je ne vois pas comment on peux savoir ce que Misc contient reelement o_o
Le contenu du champ "Characteristics" serait interessant (cette structure est bizzare, je coprends vraiment pas l'interet de cet union)
avatarProud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

5

Je lis la taille des octets en mémoire, pas ceux sur le disque wink
Godzil (./4) :
Le contenu du champ "Characteristics" serait interessant (cette structure est bizzare, je coprends vraiment pas l'interet de cet union)

C'est juste une combinaison de flags?

[EDIT] Ah mais je pensais que j'avais zappé le problème mais en fait non, je viens de remarquer LordPE dans mon historique de téléchargements... Donc en fait tout est bon, c'est IDA qui arrondit faut croire grin

6

Non par union je parle des champts PhysicalAddress et VirtualSize, je ne vois aucun moyen dans la strucure de savoir lequel des deux est remplis. Comme les deux sont des dwords, il n'y a pas d'astuce...
avatarProud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

7

Godzil (./6) :
Non par union je parle des champts PhysicalAddress et VirtualSize, je ne vois aucun moyen dans la strucure de savoir lequel des deux est remplis. Comme les deux sont des dwords, il n'y a pas d'astuce...

Je suppose que windows n'écrit pas la même chose dans ce champ que ce qu'il y a sur le disque quand c'est en cours d'exécution ... Si je devais deviner (Sans regarder le code du kernel), je suppose que Windows écrit le retour de VirtualAlloc ... Mébon.

8

Je me suis reattache a cette histoire recemment, en fait les differences +/- Image Base ce sont simplement les alignements de sections sur disque

9

Récemment j'ai un peu bossé sur le format PE et la table des sections, mais seulement pour des exes non-chargés, donc je n'ai jamais eu à me poser la question sur VirtualSize contre PhysicalAddress (Edit: ni à me soucier d'ASLR)...
Il m'a surtout fallu un moment pour comprendre qu'entre VirtualSize et SizeOfRawData, il n'y avait pas de garantie que l'un soit toujours plus grand que l'autre, vu qu'une section peut contenir (ou non) des données "non-initialisées" (auquel cas VirtualSize peut être supérieur à SizeOfRawData).

Enfin, au cas où ça pourrait être utile, mon code C# de mapping de RVA vers offset (dans un exe non-mappé) fait ceci (avec sortedSections une liste triée par VirtualAddress; le this indique un comparateur qui compare juste ce champ):
public bool MapRVAToFileOffset(uint rva, out uint fileOffset) { if(sortedSections==null) { throw new ArgumentNullException("sortedSections"); } int ixFoundForReal; IMAGE_SECTION_HEADER dummy = new IMAGE_SECTION_HEADER(); dummy.VirtualAddress = rva; int ixBinarySearch = sortedSections.BinarySearch(dummy, this); if(ixBinarySearch >= 0) ixFoundForReal = ixBinarySearch; else { int ixNext = ~ixBinarySearch; if(ixNext==0) { fileOffset=0; return false; } //Before the first section? I don't think it's a valid RVA. ixFoundForReal = ixNext-1; } Debug.Assert(ixFoundForReal >= 0, "ixFoundForReal can't be negative at this point."); Debug.Assert(ixFoundForReal < sortedSections.Count, "ixFoundForReal can't exceed section table length."); Debug.Assert(sortedSections[ixFoundForReal].VirtualAddress <= rva, "RVA can't be below the found section."); uint offsetInSection = rva - sortedSections[ixFoundForReal].VirtualAddress; if(offsetInSection >= sortedSections[ixFoundForReal].VirtualSize) { fileOffset=0; return false; } //RVA is outside the section's virtual data if(offsetInSection >= sortedSections[ixFoundForReal].SizeOfRawData) { fileOffset=0; return false; } //RVA can't be mapped into the file because it's in the part of the section that's not in the file. fileOffset = sortedSections[ixFoundForReal].PointerToRawData + offsetInSection; return true; }
avatarMaintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

10

Je n'ai rien d'utile à dire parce que je ne comprends pas la moitié du post, mais wow, j'ai rarement vu une coding style qui cumule autant de choses avec lesquelles je ne suis pas d'accord grin
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

11

Déjà, il faudrait que je commente et que j'aère un peu plus.grin
Mais développe, avec un peu de chance tu mentionneras quelque chose que je reconnais comme faute...

Edit: Déjà le coup de la ArgumentNullException sur une variable membre, ce n'est pas très propre et ça suggère un refactoring pas fini...
avatarMaintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

12

Hmm alors en vrac :

- Les "if" avec l'instruction sur la même ligne que la condition
- ...mais parfois l'instruction se trouve quand même sur la ligne suivante
- ...et d'autres fois on a une seule ligne mais deux instructions
- Les accolades quand un "if" ne contient qu'une instruction
- ...mais parfois elles ne sont pas présentes
- La parenthèse ouvrante collée après les mots-clé
- L'absence d'espaces autour des opérateurs binaires
- ...mais parfois il y en a quand même
- La convention de nommage qui ne semble pas respecter MSDN, mais je n'arrive pas à trouver la cohérence (par exemple "IMAGE_SECTION_HEADER" vs "Debug")
- Les déréférencements multiples d'une même variable (par exemple "sortedSections[ixFoundForReal]", mais là ça sort de la seule coding style)

Bon, après comme d'habitude les goûts et les couleurs hein ^^
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

13

Alors, je commence:

>Les "if" avec l'instruction sur la même ligne que la condition
Je trouve ça plus lisible dans certains cas, notamment les vérifications des arguments en début de fonction.
> ...mais parfois l'instruction se trouve quand même sur la ligne suivante
Ouais, ça dépend des cas. Dérangeant hein?

>Les accolades quand un "if" ne contient qu'une instruction
Nécessaire quand le if est sur une seule ligne, sinon le beautifieur de Visual passe à la ligne. Et puis, je trouve que ça montre bien que le if est sur une seule ligne.
>...mais parfois elles ne sont pas présentes
Généralement, quand je trouve que l'instruction sur la ligne suivante est plus lisible, au cas par cas.

>La parenthèse ouvrante collée après les mots-clé
furieuxBRÛLE, HÉRÉTIQUE!furieux
>L'absence d'espaces autour des opérateurs binaires
>...mais parfois il y en a quand même

Pareil, au cas par cas selon ce que je juge le plus lisible (pour moi en tout cas). Je règle explicitement le beautifieur de Visual sur "ignore spaces around binary operators".

>La convention de nommage qui ne semble pas respecter MSDN, mais je n'arrive pas à trouver la cohérence (par exemple "IMAGE_SECTION_HEADER" vs "Debug")
C'est parce que IMAGE_SECTION_HEADER est une structure Win32 (traduite en C# manuellement ou recopiée de PInvoke.net) et non une classe de la BCL.
Tu remarqueras que le framework lui-même suit cette convention, si tu regardes par exemple le namespace System.Runtime.InteropServices.ComTypes.
>Les déréférencements multiples d'une même variable (par exemple "sortedSections[ixFoundForReal]", mais là ça sort de la seule coding style)
Ça, je pourrais le corriger en effet.

Edit: Note: Mes critères de lisibilité tendent à dépendre de la longueur d'une ligne et de celles qui l'entourent.
avatarMaintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.