Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

File formats reverse engineering: Difference between revisions

No edit summary
No edit summary
Line 1: Line 1:
= Reverse de formats =
= Reverse de formats =
Cette page est destinée aux recherches sur les méthodes de reverse de fichiers de formats et aux essais en cours.
Cette page est destinée aux recherches sur le reverse de fichiers et aux essais en cours.
== Tailles de fichiers ==
== Tailles de fichiers ==
=== PGCD ===
=== PGCD et taille de fichier ===
L'utilisation du PGCD de l'ensemble des tailles du format de fichier utilisé permet de voir si le fichier a une taille particulière. Si le PGCD est très grand 0x800 par exemple, ça peut vouloir dire que le header et l'ensemble du fichier est composé de CHUNKs de taille fixe.
L'idée, c'est d'observer les tailles de fichiers pour retrouver des caractéristiques de certaines archives, telles que la taille du header, et l'éventuelle utilisations de "conteneurs"/chunks de taille fixe.
 
Pour cela, on prend l'ensemble des tailles en octets de chaque fichier du format étudié. On réalise le PGCD sur ces tailles et si le PGCD est conséquent, c'est qu'on a potentiellement un header et des chunks de la taille du PGCD.
 
=== PGCD et taille de header variable ===
=== PGCD et taille de header variable ===
L'objectif est de trouver un header de taille 1 fixe et des CHUNKs de taille 2 fixe :
Dans le cas on on aurait un fichier avec une taille différente de la taille des chunks, on peut tester les PGCD en soustrayant la taille d'un header que l'on augmente.
 
La structure du fichier recherché serait la suivante :


|---- HEADER ----|------------ CHUNK 1 ------------|------------ CHUNK 2 ------------|------------ CHUNK N ------------|
|---- HEADER ----|------------ CHUNK 1 ------------|------------ CHUNK 2 ------------|------------ CHUNK N ------------|


Le script python affiche la taille de header pour lequel le PGCD des tailles de corps de fichiers est supérieur à un seuil donné :
On utilisera alors un seuil au dessus duquel nous afficherons la taille du header et la taille du PGCD.
 
== Recherche de propriétés et clair connu ==
=== Bruteforce d'un offset fixe ===
Dans le cas ou on peut rassembler un ensemble de caractéristiques que l'on peut clairement attribuer à un groupe de fichiers, il est alors envisageable de bruteforcer pour retrouver l'endroit dans le fichier où ces propriétés sont stockées.
 
La première étape est de rechercher un ensemble de données pour les réunir dans un csv. Ces données devront être associées à un nom de fichier. On pourra par exemple scraper ces données sur des sites de fans par exemple.
 
La seconde étape, c'est de programmer la recherche de nombreux encodages cohérents pour chaque propriétés du csv recherchée. On recherchera tous ces encodages dans l'ensemble des fichier de la position 0 à la fin du plus petit des fichiers du lot. On vérifiera alors si la propriété apparait à la position donnée, et si elle n'est pas présente, on passera alors à la position suivante.
 
=== Ensembles et masque ===
Ici aussi, on dispose d'un dataset avec des propriétés en lien avec les fichiers étudiés. Il s'agit de regrouper les propriétés par valeurs et d'étudier les changements dans les fichiers associés pour identifier la position potentielle d'une propriété.
 
Pour les fichiers :
A = Ensemble(fichiers AVEC valeur A de la propriété)
B = Ensemble(fichiers SANS valeur A de la propriété)
D = Fichier # de la taille du fichier remplis de 0x00


<code class="mwt-code" >#!/usr/bin/env python3</code><br><code class="mwt-code" ># -*- coding: utf-8 -*-</code>
Pour tous les A si l'octet à l'offset étudié est identique, on met l'octet dans D à sa valeur, 00 sinon # on ne retient pas les octets à 00 - on en trouve dans le padding donc ce n'est pas significatif ...
Pour tous les B s'il existe un B identique à l'octet correspondant dans D alors on met l'octet dans D à 0x00


<code class="mwt-code" ># contient les tailles de fichiers</code><br><code class="mwt-code" >_list = [928, 3712, 4704, 11648, 14464, 16448, 20576, 32832, 32896, 38528, 77888, 115296, 143424, 573504, 2293888]</code>
Tester avec le même D pour tous les A (toutes les valeurs que prend la propriété dans le dataset)


<code class="mwt-code" >def pgcd(a,b):</code><br><code class="mwt-code" >&nbsp; &nbsp; """pgcd(a,b): calcul du 'Plus Grand Commun Diviseur' entre les 2 nombres entiers a et b"""</code><br><code class="mwt-code" >&nbsp; &nbsp; while b != 0:</code><br><code class="mwt-code" >&nbsp; &nbsp; &nbsp; &nbsp; r= a % b</code><br><code class="mwt-code" >&nbsp; &nbsp; &nbsp; &nbsp; a, b=b, r</code><br><code class="mwt-code" >&nbsp; &nbsp; return a</code>


<code class="mwt-code" >def pgcd_list(_list, _pgcd = 0):</code><br><code class="mwt-code" >&nbsp; &nbsp; if _pgcd == 0:</code><br><code class="mwt-code" >&nbsp; &nbsp; &nbsp; &nbsp; _pgcd = _list.pop()</code><br><code class="mwt-code" >&nbsp; &nbsp; if len(_list) == 0 or _pgcd == 1:</code><br><code class="mwt-code" >&nbsp; &nbsp; &nbsp; &nbsp; return _pgcd</code>


<code class="mwt-code" >&nbsp; &nbsp; _pgcd = pgcd(_pgcd, _list.pop())</code><br><code class="mwt-code" >&nbsp; &nbsp; return pgcd_list(_list, _pgcd)</code>


<code class="mwt-code" >_list.sort()</code><br><code class="mwt-code" >max_header_len = _list[0]</code><br><code class="mwt-code" >header_len = 8</code><br><code class="mwt-code" >while header_len &lt; max_header_len:</code><br><code class="mwt-code" >&nbsp; &nbsp; tmp_list = _list.copy()</code><br><code class="mwt-code" >&nbsp; &nbsp; for i in range(len(tmp_list)):</code><br><code class="mwt-code" >&nbsp; &nbsp; &nbsp; &nbsp; tmp_list[i]-=header_len</code><br><code class="mwt-code" >&nbsp; &nbsp; tmp_pgcd = pgcd_list(tmp_list)</code><br><code class="mwt-code" >&nbsp; &nbsp; if tmp_pgcd &gt; 30 :</code><br><code class="mwt-code" >&nbsp; &nbsp; &nbsp; &nbsp; print("Header_len:"+str(header_len)+" &nbsp;PGCD:"+str(tmp_pgcd))</code><br><code class="mwt-code" >&nbsp; &nbsp; header_len+=1</code>


== Outils à tester ==
== Outils à tester ==

Revision as of 19:00, 24 November 2021

Reverse de formats

Cette page est destinée aux recherches sur le reverse de fichiers et aux essais en cours.

Tailles de fichiers

PGCD et taille de fichier

L'idée, c'est d'observer les tailles de fichiers pour retrouver des caractéristiques de certaines archives, telles que la taille du header, et l'éventuelle utilisations de "conteneurs"/chunks de taille fixe.

Pour cela, on prend l'ensemble des tailles en octets de chaque fichier du format étudié. On réalise le PGCD sur ces tailles et si le PGCD est conséquent, c'est qu'on a potentiellement un header et des chunks de la taille du PGCD.

PGCD et taille de header variable

Dans le cas on on aurait un fichier avec une taille différente de la taille des chunks, on peut tester les PGCD en soustrayant la taille d'un header que l'on augmente.

La structure du fichier recherché serait la suivante :

|---- HEADER ----|------------ CHUNK 1 ------------|------------ CHUNK 2 ------------|------------ CHUNK N ------------|

On utilisera alors un seuil au dessus duquel nous afficherons la taille du header et la taille du PGCD.

Recherche de propriétés et clair connu

Bruteforce d'un offset fixe

Dans le cas ou on peut rassembler un ensemble de caractéristiques que l'on peut clairement attribuer à un groupe de fichiers, il est alors envisageable de bruteforcer pour retrouver l'endroit dans le fichier où ces propriétés sont stockées.

La première étape est de rechercher un ensemble de données pour les réunir dans un csv. Ces données devront être associées à un nom de fichier. On pourra par exemple scraper ces données sur des sites de fans par exemple.

La seconde étape, c'est de programmer la recherche de nombreux encodages cohérents pour chaque propriétés du csv recherchée. On recherchera tous ces encodages dans l'ensemble des fichier de la position 0 à la fin du plus petit des fichiers du lot. On vérifiera alors si la propriété apparait à la position donnée, et si elle n'est pas présente, on passera alors à la position suivante.

Ensembles et masque

Ici aussi, on dispose d'un dataset avec des propriétés en lien avec les fichiers étudiés. Il s'agit de regrouper les propriétés par valeurs et d'étudier les changements dans les fichiers associés pour identifier la position potentielle d'une propriété.

Pour les fichiers : A = Ensemble(fichiers AVEC valeur A de la propriété) B = Ensemble(fichiers SANS valeur A de la propriété) D = Fichier # de la taille du fichier remplis de 0x00

Pour tous les A si l'octet à l'offset étudié est identique, on met l'octet dans D à sa valeur, 00 sinon # on ne retient pas les octets à 00 - on en trouve dans le padding donc ce n'est pas significatif ... Pour tous les B s'il existe un B identique à l'octet correspondant dans D alors on met l'octet dans D à 0x00

Tester avec le même D pour tous les A (toutes les valeurs que prend la propriété dans le dataset)



Outils à tester

https://hexinator.com/

tester l'entropie avec binwalk (1. dans doku)

Doku

1. https://archive.fosdem.org/2021/schedule/event/reverse_engineering/attachments/slides/4518/export/events/attachments/reverse_engineering/slides/4518/Reverse_Engineering_of_binary_File_Formats.pdf

https://en.wikibooks.org/wiki/Reverse_Engineering/File_Formats