AccueilđŸ‡«đŸ‡·Chercher

Portable Executable

Le format PE (Portable Executable, exécutable portable) est un format de fichiers dérivé du COFF regroupant les exécutables et les bibliothÚques sur les systÚmes d'exploitation Windows 32 bits et 64 bits.

Portable Executable
Visualisation du début d'un fichier PE avec WinHex
Caractéristiques
Extension
.cpl, .exe, .dll, .ocx, .sys, .scr, .drv, .efi
Type MIME
application/vnd.microsoft.portable-executable, application/efi
PUID
Signatures
4D 5A (hexa)
4D5A*50450000 (PRONOM regex)
Type de format
Basé sur

Les extensions couvertes par ce format sont, l'extension .ocx (OLE et ActiveX), l'extension .dll et l'extension .cpl.

C'est également le format utilisé pour les exécutables de l'UEFI (.efi).

Historique

Microsoft a adoptĂ© le format PE avec l'introduction de Windows NT 3.1. Toutes les versions suivantes de Windows, incluant Windows 10/11, supportent ce format. Auparavant les fichiers «exĂ©cutables» Ă©taient au format NE — New Executable File Format, « New » faisant rĂ©fĂ©rence Ă  CP/M, et aux fichiers *.com —.

La création du format PE a été induite par la volonté de Microsoft de concevoir une structure de fichier qui puisse s'adapter aux différentes machines utilisant Windows NT, lequel était initialement capable de supporter d'autres architectures que le x86 d'Intel (Power PC et Motorola 68000 par exemple). L'idée fut donc de créer une structure comme ces architectures.

Schéma du format PE

Un fichier exécutable PE est structuré de la façon suivante :

Structure du Format PE

Les deux premiers octets du fichier représentent les caractÚres MZ.

En-tĂȘte MZ sous MS-DOS

L'en-tĂȘte MZ permet au systĂšme d'exploitation de reconnaĂźtre le fichier comme Ă©tant un exĂ©cutable valide dans le cas oĂč celui-ci serait lancĂ© depuis MS-DOS, afin de pouvoir exĂ©cuter son segment DOS.

Voici la structure de l'en-tĂȘte, en langage C :

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

On reconnaĂźt par exemple :

  • e_magic qui doit valoir "MZ"
  • e_lfanew qui contient l'adresse du dĂ©but de l'en-tĂȘte PE

Segment DOS

Le segment DOS est exĂ©cutĂ© lorsque Windows ne reconnaĂźt pas le fichier comme Ă©tant au format PE, ou s'il est exĂ©cutĂ© sous MS-DOS. Il affiche en gĂ©nĂ©ral un message comme This program cannot be run in DOS mode, littĂ©ralement traduit, Ce programme ne peut pas ĂȘtre exĂ©cutĂ© en mode DOS.

En-tĂȘte PE

L'en-tĂȘte PE est un ensemble de structures, regroupĂ©es dans une mĂȘme et unique structure nommĂ©e IMAGE_NT_HEADER. Voici son prototype en langage C :

typedef struct _IMAGE_NT_HEADERS {
  DWORD                 Signature;
  IMAGE_FILE_HEADER     FileHeader;
  IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
  • Signature permettant d'identifier le fichier, qui doit ĂȘtre Ă©gale Ă  0x00004550, soit "PE\0\0" (\0 Ă©tant un octet nul).
  • FileHeader est une structure nommĂ©e IMAGE_FILE_HEADER contenant des informations sur la structuration du fichier, et prototypĂ©e comme suit :
typedef struct _IMAGE_FILE_HEADER {
  WORD  Machine;
  WORD  NumberOfSections;
  DWORD TimeDateStamp;      
  DWORD PointerToSymbolTable;
  DWORD NumberOfSymbols;
  WORD  SizeOfOptionalHeader;
  WORD  Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

Voir (en) http://msdn.microsoft.com/en-us/library/windows/desktop/ms680313%28v=vs.85%29.aspx

  • OptionalHeader est une structure nommĂ©e IMAGE_OPTIONAL_HEADER

Voir (en) http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339%28v=vs.85%29.aspx pour plus de détails

Adresses physique, virtuel et mémoire

La premiÚre chose à savoir est que l'exécutable est chargé en mémoire à l'adresse ImageBase (présent dans OptionalHeader) si cette adresse est disponible. Sinon il est chargé à une autre adresse qui sera la nouvelle valeur ImageBase.

Dans l'en-tĂȘte et le corps d'un fichier PE, on trouve trois adressages diffĂ©rents :

  • Les adresses physiques reprĂ©sentent une position dans le fichier. Dans l'en-tĂȘte, leur nom commence par PointerTo
  • Les adresses virtuelles indiquent une position en mĂ©moire relative Ă  ImageBase. Dans l'en-tĂȘte, leur nom commence par Virtual
  • Les adresses mĂ©moire sont aussi une position en mĂ©moire mais cette fois absolue, ces adresses sont le plus souvent prĂ©sentes dans le code de l'application et les donnĂ©es mais pas dans les en-tĂȘtes. Dans le cas oĂč ImageBase a Ă©tĂ© modifiĂ©, la table des relocalisations indique la position des adresses mĂ©moire Ă  rectifier.

RĂ©pertoires

Les répertoires sont des parties du fichier utilisées lors de son chargement.

La position et la taille des données de ces répertoires sont indiquées dans le champ DataDirectory de OptionalHeader qui est un tableau de structures IMAGE_DATA_DIRECTORY décrit comme suit :

typedef struct _IMAGE_DATA_DIRECTORY {
	DWORD VirtualAddress;
	DWORD Size;
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;

VirtualAddress étant l'adresse du début du contenu du répertoire une fois les sections chargées en mémoire, relative à ImageBase (présent dans OptionalHeader).

Et Size sa taille.

Bien que le champ NumberOfRvaAndSizes de OptionalHeader indique leur nombre, il y en a habituellement 16 :

Position Nom Description
0 IMAGE_DIRECTORY_ENTRY_EXPORT Table des exports
1 IMAGE_DIRECTORY_ENTRY_IMPORT Table des imports
2 IMAGE_DIRECTORY_ENTRY_RESOURCE Table des ressources
3 IMAGE_DIRECTORY_ENTRY_EXCEPTION Table des exceptions
4 IMAGE_DIRECTORY_ENTRY_SECURITY Table des certificats
5 IMAGE_DIRECTORY_ENTRY_BASERELOC Table des relocalisations
6 IMAGE_DIRECTORY_ENTRY_DEBUG Informations de débogage
7 IMAGE_DIRECTORY_ENTRY_COPYRIGHT / IMAGE_DIRECTORY_ENTRY_ARCHITECTURE Données spécifiques aux droits de copies ou à l'architecture
8 IMAGE_DIRECTORY_ENTRY_GLOBALPTR pointeurs globaux
9 IMAGE_DIRECTORY_ENTRY_TLS Table de stockage des threads locaux (TLS (Thread local storage) table en anglais)
10 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG Load configuration table
11 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT Table des imports liés
12 IMAGE_DIRECTORY_ENTRY_IAT Table des adresses des imports
13 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT Descripteur des imports en différé
14 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR en-tĂȘte runtime COM+
15 - rĂ©servĂ©: doit ĂȘtre vide.

Table des sections

Les sections d'un programme vu par PEiD

La Table des Sections est situĂ©e juste derriĂšre l'en-tĂȘte PE. Il s'agit d'un tableau contenant plusieurs structures IMAGE_SECTION_HEADER.

Ces structures contiennent les informations sur les sections du binaire devant ĂȘtre chargĂ© en mĂ©moire.

Le champ NumberOfSections de la structure IMAGE_FILE_HEADER indique combien d'entrées il y a dans cette table. Le maximum supporté par Windows est de 96 sections.

La Table des Sections est prototypé comme suit :

typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
      DWORD PhysicalAddress;
      DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress;
  DWORD SizeOfRawData;
  DWORD PointerToRawData;
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

Chaque section a un nom de 8 caractÚres, ce nom n'est pas significatif mais on peut généralement trouver les suivants :

Nom Description
.text Le code (instructions) du programme
.bss Les variables non-initialisées
.reloc La table des relocalisations (le sixiÚme répertoire)
.data Les variables initialisées
.rsrc Les ressources du fichier (le troisiÚme répertoire: Curseurs, Sons, Menus
)
.rdata Les données en lectures seule
.idata La table d'import (le second répertoire)
.upx Signe d'une compression UPX, propre au logiciel UPX
.aspack Signe d'un package ASPACK, propre au logiciel ASPACK
.adata Signe d'un package ASPACK, propre au logiciel ASPACK

Table des relocalisations

La table des relocalisations est prĂ©sente dans le sixiĂšme rĂ©pertoire 'Base relocation table'. Elle indique les adresses virtuelles des valeurs reprĂ©sentant une adresse mĂ©moire. Elle permet, dans le cas oĂč l'exĂ©cutable n'a pas Ă©tĂ© chargĂ© en mĂ©moire Ă  l'adresse ImageBase, de replacer toutes les rĂ©fĂ©rences mĂ©moire pour correspondre Ă  la nouvelle valeur ImageBase.

La table des relocalisations est une suite de structures de tailles variables. Chacune est composĂ©e d'un en-tĂȘte de type IMAGE_BASE_RELOCATION puis d'un tableau de valeurs de type WORD (de taille 16 bits). Il arrive parfois que la derniĂšre valeur soit 0, dans ce cas elle ne sert que pour l'alignement sur 4 octets.

typedef struct _IMAGE_BASE_RELOCATION {
	DWORD VirtualAddress;
	DWORD SizeOfBlock;
} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
  • SizeOfBlock est la taille en octets de la structure, en-tĂȘte compris.
  • VirtualAddress est l'adresse virtuelle (relative Ă  ImageBase) de base pour les valeurs

On ne connait pas le nombre de structures prĂ©sentes dans la table des relocalisations, mais on sait sa taille et donc on s'arrĂȘte lorsque l'on a atteint la fin. De mĂȘme on ne sait pas combien de valeurs suivent chaque en-tĂȘte, mais on le dĂ©duit de la taille.

Chaque valeur est composée de 4 bits d'informations et de 12 bits de données.

La partie information peut ĂȘtre l'une de ces valeurs :

Valeur Description
IMAGE_REL_BASED_ABSOLUTE
IMAGE_REL_BASED_HIGH
IMAGE_REL_BASED_LOW
IMAGE_REL_BASED_HIGHLOW La donnée est une adresse relative à la base (adresse virtuelle = VirtualAddress + donnée)
IMAGE_REL_BASED_HIGHADJ
IMAGE_REL_BASED_MIPS_JMPADDR

Le plus souvent seul IMAGE_REL_BASED_HIGHLOW est utilisé.

La valeur de l'adresse mémoire ainsi calculée sera décalée selon la différence entre l'ImageBase d'origine et l'adresse du début de la mémoire allouée au programme.

Table d'import - IAT

Exemple d'IAT sur un programme Windows

L'IAT, qui signifie import address table, contenue dans le second répertoire import table (généralement dans la section .idata ou .rdata), indique les adresses des API importées par un logiciel, ainsi que les noms des DLL important ces fonctions. Les API, contenues dans ces DLL, permettent aux logiciels de fonctionner correctement.

Son existence est due au fait que les API sont adressées différemment en fonction des OS.

Il faut savoir en premier lieu qu'une structure nommée IMAGE_IMPORT_DESCRIPTOR est utilisée pour chaque DLL appelée; plus une derniÚre de 5 DWORD mis à zéro qui définit une terminaison.

Pour chaque DLL importée, une structure nommée IMAGE_THUNK_DATA sera utilisée pour chaque API de cette DLL ; il y aura donc autant de IMAGE_THUNK_DATA que de fonctions exportées par une DLL, plus un dernier DWORD spécifiant la terminaison de cette DLL.

Une troisiÚme structure, IMAGE_IMPORT_BY_NAME, définit le nom des API ainsi que leur numéro ORDINAL (nombre de 16 bits identifiant une fonction au sein d'une DLL). Il en existe autant qu'il y a d'API importées par DLL. Par exemple, sur l'image d'exemple ci-dessus, il y a trois IMAGE_IMPORT_BY_NAME définies pour advapi32.dll, car seulement trois de ses API sont utilisées par le programme.

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    _ANONYMOUS_UNION union {
        DWORD   Characteristics;    // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk; // It points to the first thunk IMAGE_THUNK_DATA
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;          // 0 if not bound
    DWORD   ForwarderChain;         // -1 if no forwarders
    DWORD   Name;                   // RVA of DLL Name.
    DWORD   FirstThunk;             // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;       //Ordinal Number
    BYTE    Name[1];    //Name of function
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
typedef union _IMAGE_THUNK_DATA {
    PDWORD                 Function;
    PIMAGE_IMPORT_BY_NAME  AddressOfData;
} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA;

Table d'export - EAT

EAT = Export Address Table

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;        /* 0x00 */
    DWORD   TimeDateStamp;          /* 0x04 */
    WORD    MajorVersion;           /* 0x08 */
    WORD    MinorVersion;           /* 0x0a */
    DWORD   Name;                   /* 0x0c */
    DWORD   Base;                   /* 0x10 */
    DWORD   NumberOfFunctions;      /* 0x14 */
    DWORD   NumberOfNames;          /* 0x18 */
    DWORD   AddressOfFunctions;     // 0x1c RVA from base of image
    DWORD   AddressOfNames;         // 0x20 RVA from base of image
    DWORD   AddressOfNameOrdinals;  // 0x24 RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

Le PE Loader

Le PE Loader est un élément de Windows permettant de reconnaßtre et de charger en mémoire des fichiers PE. C'est grùce à lui que Windows peut exécuter les instructions d'un tel fichier.

  • Voici son fonctionnement global :
  1. Le PE Loader examine l'en-tĂȘte MZ afin de trouver l'offset de l'en-tĂȘte PE. S'il le trouve il « saute » dessus.
  2. Le PE Loader vĂ©rifie la validitĂ© de l'en-tĂȘte PE. Si tel est le cas il « saute » Ă  la fin de cet en-tĂȘte.
  3. Le PE Loader lit les informations concernant les sections puis mappe ces sections en mémoire en employant un procédé de « File Mapping » (copie d'un fichier en mémoire).
  4. Lorsque tout a Ă©tĂ© mappĂ© en mĂ©moire, le PE Loader se comporte lui-mĂȘme comme une partie logique du PE File, en tant que table d'importation.

Reverse engineering du format PE

DĂ©finition

Le reverse engineering, parfois raccourci en Reversing, est une technique d'analyse logicielle qui permet de trouver des « bugs », des failles, de concevoir des exploits ou des cracks, ou de corriger des problÚmes dans un logiciel. Il s'agit d'une technique visant à comprendre le fonctionnement d'un logiciel, sans avoir recours à son code source.

Une autre utilisation du Reversing, consiste en l'analyse de Malware dans le but de comprendre son comportement et sa structure, afin de crĂ©er un vaccin contre ce dernier. Ces dits vaccins peuvent ensuite ĂȘtre intĂ©grĂ©s dans un anti-virus pour protĂ©ger le systĂšme Ă  l'avenir. À noter que la plupart des virus/anti-virus se concentrent sur Windows, qui est de loin l'OS le plus utilisĂ©/vendu dans le domaine du grand public. Bien qu'il existe des malwares exploitant d'autres infrastructures, comme Stuxnet, qui ciblait les systĂšmes SCADA[1].

Cette pratique consiste en une analyse poussée du Bytecode d'un programme (quel qu'en soit le format), pour en révéler son fonctionnement, son comportement. Elle fait ressortir des connaissances poussées du systÚme d'exploitation (FreeBSD, Windows, Linux, Mac), de programmation (ASM, C/C++), et architecturaux (x86, SPARC) de la part de celui qui s'y exécute, communément appelé Reverser ou Cracker.

Cet article traitant du Format PE (Portable Executable), les informations présentes ici se concentreront donc sur ce format de fichier.

Notez qu'il est bien entendu possible d'effectuer toutes les dĂ©marches suivantes dans des formats tels que ELF (Executable & Linkable Format) ou encore Mach-O (Mach Object File Format). En revanche, en changeant de format, les outils vont changer Ă  leur tour, non pas le principe mais les programmes eux-mĂȘmes ; des nuances sur les protections anti-reversing se feront sentir Ă©galement.

Analyse statique

Une analyse statique d'un logiciel consiste en une lecture du Bytecode tel qu'il existe sur le disque dur, c'est-Ă -dire sans ĂȘtre en exĂ©cution.

Une lecture du Bytecode d'un programme n'est ni plus ni moins qu'une transformation des suites d'octets présentes dans le programme, en langage ASM, langage mnémotechnique permettant une compréhension humaine de ce que doit entreprendre le programme.

Des outils ont été spécifiquement développés dans ce but, tels que Win32Dasm, ou Pydasm (Module Python).

Analyse dynamique

Une analyse dynamique comprend deux phases : lecture du code - exécution du code.

Pour entreprendre une telle démarche, il est nécessaire de posséder un outil logiciel que l'on nomme Débogueur, tel qu'OllyDbg ou GDB (GNU Debugger).

Le principe étant de désassembler le programme tout en l'exécutant, aussi appelé analyse pas à pas ou step-by-step, de maniÚre à pouvoir modifier son comportement en temps réel, afin de comprendre plus en détail son fonctionnement et les modifications possibles.

Niveaux de privilĂšges

La plupart des analyses sont effectués en Ring 3, c'est-à-dire en mode utilisateur. Au-dessus on arrive au Ring 0, soit le Kernel, mais ce genre d'analyse poussé est rare et réservé aux aventuriers (développement de driver, hacking, etc.).

Une autre méthode, un peu insolite (mais fonctionnelle) est d'utiliser la virtualisation matérielle. Damien Aumaitre a présenté au SSTIC 2010 son outil VirtDbg.

Voir (fr) http://esec-lab.sogeti.com/dotclear/public/publications/10-sstic-virtdbg_slides.pdf

Voir Anneau de protection

Protection anti-reversing

Le reversing Ă©tant vu comme une technique intrusive Ă  l'Ă©gard des logiciels closed-source (Code source propriĂ©taire et non divulguĂ©), les programmeurs ont donc eu l'idĂ©e d'inclure des routines spĂ©cifiques dans leurs programmes, qui n'auront qu'un unique but : empĂȘcher au maximum la prise d'information sur le comportement du logiciel.

Pour ce faire il existe de nombreuses méthodes, dont l'utilisation de Packer (chiffrement/compression de code), des codes détecteur de débogueur, insertion de Checksum etc.

Packers

Un packer est un petit programme dont le but est de compresser un logiciel afin de réduire sa taille initiale, tout en conservant son aspect exécutable.

Néanmoins, avec le temps, de nouveaux packers sont apparus; ces derniers possÚdent à présent la capacité de chiffrer le code du programme cible, ce qui a pour effet de réduire à la fois son poids et à la fois de modifier son code d'exécution. Un algorithme bien connu, et un des plus simples à contourner puisque la clé est généralement inscrite dans le programme, est sans conteste XOR (OU-Exclusif).

Bien entendu, la partie liée au déchiffrement - effectuée au lancement du logiciel packé/chiffré - sera effectuée de façon transparente pour l'utilisateur. Mais un reverser verra cela autrement, en visualisant un code ASM différent de la normale.

UPX est un exemple de packer; il permet de réduire de prÚs de 50 % la taille d'un exécutable.

Visualisation du ratio de compression sur notepad.exe

DĂ©tection de breakpoint

La dĂ©tection de breakpoint (Point d'ArrĂȘt), consiste Ă  dĂ©celer lors de l'exĂ©cution d'un binaire l'appel Ă  la fonction INT 3, soit 0xCC en hexadĂ©cimal. Un code similaire Ă  celui-ci permettrait d'effectuer cette opĂ©ration :

if(byte XOR 0x55 == 0x99){ // Si Byte = 0xCC -> 0xCC XOR 0x55 == 0x99
    printf("Breakpoint trouvé !!");
}

False breakpoint

La technique du false breakpoint consiste Ă  simuler dans le code du logiciel un point d'arrĂȘt comme le ferait un dĂ©bogueur, grĂące Ă  l'instruction INT 3, soit 0xCC en hexadĂ©cimal. Lorsqu'un dĂ©bogueur rencontrera cette fonction, il se stoppera tout seul par la rĂ©ception d'un signal SIGTRAP.

Par défaut, un processus se ferme lorsqu'il reçoit un signal SIGTRAP. L'astuce consiste donc à changer ce comportement par défaut grùce à la fonction signal() appliquée à SIGTRAP.

Voici un exemple de code source en langage C, pour les systĂšmes Linux :

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
void sighandler(int signal) {
    printf("Je suis une fonction ordinaire... ");
    exit(0);
}
int main(void) {
    signal(SIGTRAP,sighandler);    // On place le sighandler
    __asm__("int3");               // On place un faux Breakpoint
    printf("Pris au piÚge...");    // Le débogueur arrive ici
    return EXIT_FAILURE;
}


Détection de débogueur

En pratique, il y a différentes maniÚres de détecter un débogueur. Le plus simplement possible, avec la fonction IsDebuggerPresent(void) sous Windows :

#include <stdio.h>
#include <windows.h>
int main(int argc, char* argv[])
{
  // Attention: cette fonction vaut 0 s'il n'y a pas de débogueur.
  if(!IsDebuggerPresent())
  {
    printf("Helloworld !");
  }
  else
  {
    printf("Debogueur detecte !");
  }
  return 0;
}

Ensuite, il existe différentes astuces pour détecter le débogueur.

Par exemple:

#include <stdio.h>
#include <windows.h>
#include <time.h>
int main(int argc, char* argv[])
{
  int start = clock();
  Sleep(100);
  int DeltaTemps = abs(clock() - start - 100);
  printf("deltaTemps: %d\n", DeltaTemps);
  if(DeltaTemps < 4)
  {
    printf("Helloworld !");
  }
  else
  {
    printf("Debogueur detecte !");
  }
  return 0;
}

Ce code calcule une différence de temps. Avec un sleep de 100 ms, normalement la différence est de 100 (à quelques millisecondes prÚs). On calcule donc la différence, on retranche 100 et on obtient un résultat. On applique la fonction abs, pour toujours obtenir une valeur positive. En mode pas-à-pas, le programme sera considérablement ralenti, et ainsi, la différence sera plus élevée et le programme bloquera.

Les outils

Voir aussi

Liens externes

Notes et références

  1. « Stuxnet Worm Attack on Iranian Nuclear Facilities », sur large.stanford.edu (consulté le )
Cet article est issu de wikipedia. Text licence: CC BY-SA 4.0, Des conditions supplĂ©mentaires peuvent s’appliquer aux fichiers multimĂ©dias.