Site WWW de Laurent Bloch
Slogan du site

ISSN 2271-3905
Cliquez ici si vous voulez visiter mon autre site, orienté vers des sujets moins techniques.

Pour recevoir (au plus une fois par semaine) les nouveautés de ce site, indiquez ici votre adresse électronique :

Un problème de sécurité informatique :
Décoder un logiciel de cyberattaque
Article mis en ligne le 18 janvier 2023
dernière modification le 23 juillet 2024

par Laurent Bloch

Pour déminer une cyberattaque : des compétences en programmation

Les cyberattaques récentes mettent en évidence la question de la sécurité informatique, et ce mal vient avec un bien : rappeler à tout le monde l’importance de la programmation informatique. Il ne manque en effet pas d’oracles pour annoncer la fin de la programmation grâce à l’intelligence artificielle : il n’y a guère qu’un demi-siècle que j’entends cette prophétie, dont je laisse la responsabilité à ceux qui la divulguent. Mais lorsqu’il s’agit de décrypter un logiciel dangereux pour savoir comment le désamorcer, là, rien à faire, il faut des compétences en programmation, et même des compétences approfondies.

Le programme malfaisant qu’il s’agit de comprendre afin de l’empêcher de nuire a été écrit dans un langage de programmation compréhensible par un être humain. Entendons-nous : par un être humain qui aura appris ce langage, ce qui lui aura pris des mois, et pour une connaissance approfondie, des années. Le texte de ce programme tel qu’il a été écrit, dans un langage compréhensible (enfin, relativement compréhensible), est ce que l’on appelle le programme source, qui pour être exécuté doit être traduit en langage machine, le résultat de cette traduction est ce que l’on appelle le programme binaire.

Seulement voilà : les cyberattaquants n’ont en général pas l’amabilité de fournir à leurs victimes le texte de leur programme source. Le consultant en cybersécurité qui intervient pour le déminage doit d’abord trouver sur la scène du crime le vecteur d’attaque, c’est-à-dire le même programme sous forme binaire, et, pour y comprendre quelque chose, reconstituer le programme source à partir du binaire, effectuer la traduction inverse, si l’on veut, ce qui est très difficile, et demande des compétences extrêmes, non seulement en programmation mais aussi en architecture des ordinateurs.

En fait, si le programme a été écrit initialement dans un langage de niveau d’abstraction élevé, tel que le langage C ou C++ par exemple, ou si la vulnérabilité exploitée par l’attaquant se trouve dans un logiciel écrit dans un tel langage, reconstituer le programme source est une opération complexe au résultat incertain. Il est plus facile de désassembler le programme, c’est-à-dire de traduire le code binaire en langage assembleur, un langage qui correspond mot à mot (si j’ose dire) au langage machine, mais sous une forme lisible par un humain compétent. C’est cette démarche que nous allons expliquer ci-dessous, au moyen d’un exemple simpliste mais supposément pédagogique.

Un petit aparté à l’intention des lecteurs qui hésiteraient pour le choix d’une orientation professionnelle : les études qui mènent à ce type de compétence sont longues et ardues, mais celui qui s’en sera donné la peine ne risquera guère le chômage ni la misère. Le type d’intervention dont il est question ici se paie entre 1000 et 2000 euros la journée, et l’activité des cyberattaquants ne semble pas en voie d’extinction.

Anatomie d’un programme

Pour comprendre la démarche d’analyse d’un programme binaire, qu’il soit destiné à une cyberattaque ou à tout autre chose, il faut comprendre comment il est construit. Soit un programme simple en langage C, nommé test-disasm.c, qui se contente d’afficher un texte, et dont voici le code source :

/*
  Programme simple
*/

#include <stdlib.h>
#include <stdio.h>

void afficher(void);

int main(void)
{
  afficher();
  return EXIT_SUCCESS;
}

void afficher(void)
{
  printf("printf peut afficher ceci.\n");
  printf("            --------\n");
}

Observons que le programmeur, pour rendre la lecture du programme plus intelligible, a donné un nom explicite à la fonction afficher. Remarquons aussi que le programme fait appel à deux bibliothèque externes, stdlib et stdio, qui vont ajouter au code écrit explicitement des sous-programmes (bien plus longs et bien plus compliqués que ce que l’on peut lire ici) pour accomplir des interactions avec le système d’exploitation, par exemple pour afficher des textes à l’écran.

On peut transformer ce programme source en programme exécutable par la commande gcc test-disasm.c, mais décomposons les opérations.

Traduisons ce programme source en assembleur par la commande gcc -S test-disasm.c, qui donne le texte de test-disasm.s ci-dessous. On remarque la syntaxe particulièrement biscornue de l’assembleur Intel x86 ; heureusement d’autres architectures, dont j’espère beaucoup pour l’avenir, telle l’architecture libre RISC-V, offrent des syntaxes plus lisibles.

	.file	"test-disasm.c"
	.text
	.globl	main
	.type	main, @function
main:
.LFB6:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	call	afficher
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE6:
	.size	main, .-main
	.section	.rodata
.LC0:
	.string	"printf peut afficher ceci."
.LC1:
	.string	"            --------"
	.text
	.globl	afficher
	.type	afficher, @function
afficher:
.LFB7:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	leaq	.LC0(%rip), %rax
	movq	%rax, %rdi
	call	puts@PLT
	leaq	.LC1(%rip), %rax
	movq	%rax, %rdi
	call	puts@PLT
	nop
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE7:
	.size	afficher, .-afficher
	.ident	"GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

On remarque au début de certaines sections du code assembleur la présence de l’instruction endbr64 (en clair Terminate Indirect Branch in 64 bit) : elle figure dans le jeu d’instructions des processeurs d’architecture Intel récents pour protéger le programme contre les attaques de type Return-oriented Programming (ROP) ou Jump/Call-oriented Programming (JOP/COP), qui consistent à insérer dans un sous-programme une adresse de retour frauduleuse afin d’accéder à une adresse de code normalement inaccessible.

Traduisons le code assembleur en langage machine par la commande gcc -c test-disasm.s, qui donne le fichier test-disasm.o, que l’on peut examiner par la commande od -x test-disasm.o (l’affichage est en hexadécimal, en binaire ce seraient des pages et des pages) :

0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000020 0001 003e 0001 0000 0000 0000 0000 0000
0000040 0000 0000 0000 0000 0348 0000 0000 0000
0000060 0000 0000 0040 0000 0000 0040 000e 000d
0000100 0ff3 fa1e 4855 e589 00e8 0000 b800 0000
0000120 0000 c35d 0ff3 fa1e 4855 e589 8d48 0005
0000140 0000 4800 c789 00e8 0000 4800 058d 0000
0000160 0000 8948 e8c7 0000 0000 5d90 70c3 6972
0000200 746e 2066 6570 7475 6120 6666 6369 6568
0000220 2072 6563 6963 002e 2020 2020 2020 2020
0000240 2020 2020 2d2d 2d2d 2d2d 2d2d 0000 4347
0000260 3a43 2820 6255 6e75 7574 3120 2e31 2e33
0000300 2d30 7531 7562 746e 3175 327e 2e32 3430
0000320 2029 3131 332e 302e 0000 0000 0000 0000
0000340 0004 0000 0010 0000 0005 0000 4e47 0055
0000360 0002 c000 0004 0000 0003 0000 0000 0000
0000400 0014 0000 0000 0000 7a01 0052 7801 0110
0000420 0c1b 0807 0190 0000 001c 0000 001c 0000
0000440 0000 0000 0014 0000 4500 100e 0286 0d43
0000460 4b06 070c 0008 0000 001c 0000 003c 0000
0000500 0000 0000 0029 0000 4500 100e 0286 0d43
0000520 6006 070c 0008 0000 0000 0000 0000 0000
0000540 0000 0000 0000 0000 0000 0000 0000 0000
0000560 0001 0000 0004 fff1 0000 0000 0000 0000
0000600 0000 0000 0000 0000 0000 0000 0003 0001
0000620 0000 0000 0000 0000 0000 0000 0000 0000
0000640 0000 0000 0003 0005 0000 0000 0000 0000
0000660 0000 0000 0000 0000 000f 0000 0012 0001
0000700 0000 0000 0000 0000 0014 0000 0000 0000
0000720 0014 0000 0012 0001 0014 0000 0000 0000
0000740 0029 0000 0000 0000 001d 0000 0010 0000
0000760 0000 0000 0000 0000 0000 0000 0000 0000
0001000 7400 7365 2d74 6964 6173 6d73 632e 6d00
0001020 6961 006e 6661 6966 6863 7265 7000 7475
0001040 0073 0000 0000 0000 0009 0000 0000 0000
0001060 0004 0000 0005 0000 fffc ffff ffff ffff
0001100 001f 0000 0000 0000 0002 0000 0003 0000
0001120 fffc ffff ffff ffff 0027 0000 0000 0000
0001140 0004 0000 0006 0000 fffc ffff ffff ffff
0001160 002e 0000 0000 0000 0002 0000 0003 0000
0001200 0017 0000 0000 0000 0036 0000 0000 0000
0001220 0004 0000 0006 0000 fffc ffff ffff ffff
0001240 0020 0000 0000 0000 0002 0000 0002 0000
0001260 0000 0000 0000 0000 0040 0000 0000 0000
0001300 0002 0000 0002 0000 0014 0000 0000 0000
0001320 2e00 7973 746d 6261 2e00 7473 7472 6261
0001340 2e00 6873 7473 7472 6261 2e00 6572 616c
0001360 742e 7865 0074 642e 7461 0061 622e 7373
0001400 2e00 6f72 6164 6174 2e00 6f63 6d6d 6e65
0001420 0074 6e2e 746f 2e65 4e47 2d55 7473 6361
0001440 006b 6e2e 746f 2e65 6e67 2e75 7270 706f
0001460 7265 7974 2e00 6572 616c 652e 5f68 7266
0001500 6d61 0065 0000 0000 0000 0000 0000 0000
0001520 0000 0000 0000 0000 0000 0000 0000 0000
*
0001600 0000 0000 0000 0000 0020 0000 0001 0000
0001620 0006 0000 0000 0000 0000 0000 0000 0000
0001640 0040 0000 0000 0000 003d 0000 0000 0000
0001660 0000 0000 0000 0000 0001 0000 0000 0000
0001700 0000 0000 0000 0000 001b 0000 0004 0000
0001720 0040 0000 0000 0000 0000 0000 0000 0000
0001740 0228 0000 0000 0000 0078 0000 0000 0000
0001760 000b 0000 0001 0000 0008 0000 0000 0000
0002000 0018 0000 0000 0000 0026 0000 0001 0000
0002020 0003 0000 0000 0000 0000 0000 0000 0000
0002040 007d 0000 0000 0000 0000 0000 0000 0000
0002060 0000 0000 0000 0000 0001 0000 0000 0000
0002100 0000 0000 0000 0000 002c 0000 0008 0000
0002120 0003 0000 0000 0000 0000 0000 0000 0000
0002140 007d 0000 0000 0000 0000 0000 0000 0000
0002160 0000 0000 0000 0000 0001 0000 0000 0000
0002200 0000 0000 0000 0000 0031 0000 0001 0000
0002220 0002 0000 0000 0000 0000 0000 0000 0000
0002240 007d 0000 0000 0000 0030 0000 0000 0000
0002260 0000 0000 0000 0000 0001 0000 0000 0000
0002300 0000 0000 0000 0000 0039 0000 0001 0000
0002320 0030 0000 0000 0000 0000 0000 0000 0000
0002340 00ad 0000 0000 0000 002c 0000 0000 0000
0002360 0000 0000 0000 0000 0001 0000 0000 0000
0002400 0001 0000 0000 0000 0042 0000 0001 0000
0002420 0000 0000 0000 0000 0000 0000 0000 0000
0002440 00d9 0000 0000 0000 0000 0000 0000 0000
0002460 0000 0000 0000 0000 0001 0000 0000 0000
0002500 0000 0000 0000 0000 0052 0000 0007 0000
0002520 0002 0000 0000 0000 0000 0000 0000 0000
0002540 00e0 0000 0000 0000 0020 0000 0000 0000
0002560 0000 0000 0000 0000 0008 0000 0000 0000
0002600 0000 0000 0000 0000 006a 0000 0001 0000
0002620 0002 0000 0000 0000 0000 0000 0000 0000
0002640 0100 0000 0000 0000 0058 0000 0000 0000
0002660 0000 0000 0000 0000 0008 0000 0000 0000
0002700 0000 0000 0000 0000 0065 0000 0004 0000
0002720 0040 0000 0000 0000 0000 0000 0000 0000
0002740 02a0 0000 0000 0000 0030 0000 0000 0000
0002760 000b 0000 0009 0000 0008 0000 0000 0000
0003000 0018 0000 0000 0000 0001 0000 0002 0000
0003020 0000 0000 0000 0000 0000 0000 0000 0000
0003040 0158 0000 0000 0000 00a8 0000 0000 0000
0003060 000c 0000 0004 0000 0008 0000 0000 0000
0003100 0018 0000 0000 0000 0009 0000 0003 0000
0003120 0000 0000 0000 0000 0000 0000 0000 0000
0003140 0200 0000 0000 0000 0022 0000 0000 0000
0003160 0000 0000 0000 0000 0001 0000 0000 0000
0003200 0000 0000 0000 0000 0011 0000 0003 0000
0003220 0000 0000 0000 0000 0000 0000 0000 0000
0003240 02d0 0000 0000 0000 0074 0000 0000 0000
0003260 0000 0000 0000 0000 0001 0000 0000 0000
0003300 0000 0000 0000 0000
0003310

Plus intéressant, on peut afficher face à face le texte en assembleur et le texte binaire, en utilisant le programme objdump par la commande :

objdump -d test-disasm

qui répond :

test-disasm:     format de fichier elf64-x86-64

Déassemblage de la section .init :

0000000000001000 <_init>:
    1000:	f3 0f 1e fa          	endbr64 
    1004:	48 83 ec 08          	sub    $0x8,%rsp
    1008:	48 8b 05 d9 2f 00 00 	mov    0x2fd9(%rip),%rax        # 3fe8 <__gmon_start__@Base>
    100f:	48 85 c0             	test   %rax,%rax
    1012:	74 02                	je     1016 <_init+0x16>
    1014:	ff d0                	call   *%rax
    1016:	48 83 c4 08          	add    $0x8,%rsp
    101a:	c3                   	ret    

Déassemblage de la section .plt :

0000000000001020 <.plt>:
    1020:	ff 35 9a 2f 00 00    	push   0x2f9a(%rip)        # 3fc0 <_GLOBAL_OFFSET_TABLE_+0x8>
    1026:	f2 ff 25 9b 2f 00 00 	bnd jmp *0x2f9b(%rip)        # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x10>
    102d:	0f 1f 00             	nopl   (%rax)
    1030:	f3 0f 1e fa          	endbr64 
    1034:	68 00 00 00 00       	push   $0x0
    1039:	f2 e9 e1 ff ff ff    	bnd jmp 1020 <_init+0x20>
    103f:	90                   	nop

Déassemblage de la section .plt.got :

0000000000001040 <__cxa_finalize@plt>:
    1040:	f3 0f 1e fa          	endbr64 
    1044:	f2 ff 25 ad 2f 00 00 	bnd jmp *0x2fad(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    104b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

Déassemblage de la section .plt.sec :

0000000000001050 <puts@plt>:
    1050:	f3 0f 1e fa          	endbr64 
    1054:	f2 ff 25 75 2f 00 00 	bnd jmp *0x2f75(%rip)        # 3fd0 <puts@GLIBC_2.2.5>
    105b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

Déassemblage de la section .text :

0000000000001060 <_start>:
    1060:	f3 0f 1e fa          	endbr64 
    1064:	31 ed                	xor    %ebp,%ebp
    1066:	49 89 d1             	mov    %rdx,%r9
    1069:	5e                   	pop    %rsi
    106a:	48 89 e2             	mov    %rsp,%rdx
    106d:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
    1071:	50                   	push   %rax
    1072:	54                   	push   %rsp
    1073:	45 31 c0             	xor    %r8d,%r8d
    1076:	31 c9                	xor    %ecx,%ecx
    1078:	48 8d 3d ca 00 00 00 	lea    0xca(%rip),%rdi        # 1149 <main>
    107f:	ff 15 53 2f 00 00    	call   *0x2f53(%rip)        # 3fd8 <__libc_start_main@GLIBC_2.34>
    1085:	f4                   	hlt    
    1086:	66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
    108d:	00 00 00 

0000000000001090 <deregister_tm_clones>:
    1090:	48 8d 3d 79 2f 00 00 	lea    0x2f79(%rip),%rdi        # 4010 <__TMC_END__>
    1097:	48 8d 05 72 2f 00 00 	lea    0x2f72(%rip),%rax        # 4010 <__TMC_END__>
    109e:	48 39 f8             	cmp    %rdi,%rax
    10a1:	74 15                	je     10b8 <deregister_tm_clones+0x28>
    10a3:	48 8b 05 36 2f 00 00 	mov    0x2f36(%rip),%rax        # 3fe0 <_ITM_deregisterTMCloneTable@Base>
    10aa:	48 85 c0             	test   %rax,%rax
    10ad:	74 09                	je     10b8 <deregister_tm_clones+0x28>
    10af:	ff e0                	jmp    *%rax
    10b1:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)
    10b8:	c3                   	ret    
    10b9:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)

00000000000010c0 <register_tm_clones>:
    10c0:	48 8d 3d 49 2f 00 00 	lea    0x2f49(%rip),%rdi        # 4010 <__TMC_END__>
    10c7:	48 8d 35 42 2f 00 00 	lea    0x2f42(%rip),%rsi        # 4010 <__TMC_END__>
    10ce:	48 29 fe             	sub    %rdi,%rsi
    10d1:	48 89 f0             	mov    %rsi,%rax
    10d4:	48 c1 ee 3f          	shr    $0x3f,%rsi
    10d8:	48 c1 f8 03          	sar    $0x3,%rax
    10dc:	48 01 c6             	add    %rax,%rsi
    10df:	48 d1 fe             	sar    %rsi
    10e2:	74 14                	je     10f8 <register_tm_clones+0x38>
    10e4:	48 8b 05 05 2f 00 00 	mov    0x2f05(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable@Base>
    10eb:	48 85 c0             	test   %rax,%rax
    10ee:	74 08                	je     10f8 <register_tm_clones+0x38>
    10f0:	ff e0                	jmp    *%rax
    10f2:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)
    10f8:	c3                   	ret    
    10f9:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)

0000000000001100 <__do_global_dtors_aux>:
    1100:	f3 0f 1e fa          	endbr64 
    1104:	80 3d 05 2f 00 00 00 	cmpb   $0x0,0x2f05(%rip)        # 4010 <__TMC_END__>
    110b:	75 2b                	jne    1138 <__do_global_dtors_aux+0x38>
    110d:	55                   	push   %rbp
    110e:	48 83 3d e2 2e 00 00 	cmpq   $0x0,0x2ee2(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    1115:	00 
    1116:	48 89 e5             	mov    %rsp,%rbp
    1119:	74 0c                	je     1127 <__do_global_dtors_aux+0x27>
    111b:	48 8b 3d e6 2e 00 00 	mov    0x2ee6(%rip),%rdi        # 4008 <__dso_handle>
    1122:	e8 19 ff ff ff       	call   1040 <__cxa_finalize@plt>
    1127:	e8 64 ff ff ff       	call   1090 <deregister_tm_clones>
    112c:	c6 05 dd 2e 00 00 01 	movb   $0x1,0x2edd(%rip)        # 4010 <__TMC_END__>
    1133:	5d                   	pop    %rbp
    1134:	c3                   	ret    
    1135:	0f 1f 00             	nopl   (%rax)
    1138:	c3                   	ret    
    1139:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)

0000000000001140 <frame_dummy>:
    1140:	f3 0f 1e fa          	endbr64 
    1144:	e9 77 ff ff ff       	jmp    10c0 <register_tm_clones>

0000000000001149 <main>:
    1149:	f3 0f 1e fa          	endbr64 
    114d:	55                   	push   %rbp
    114e:	48 89 e5             	mov    %rsp,%rbp
    1151:	e8 07 00 00 00       	call   115d <afficher>
    1156:	b8 00 00 00 00       	mov    $0x0,%eax
    115b:	5d                   	pop    %rbp
    115c:	c3                   	ret    

000000000000115d <afficher>:
    115d:	f3 0f 1e fa          	endbr64 
    1161:	55                   	push   %rbp
    1162:	48 89 e5             	mov    %rsp,%rbp
    1165:	48 8d 05 98 0e 00 00 	lea    0xe98(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    116c:	48 89 c7             	mov    %rax,%rdi
    116f:	e8 dc fe ff ff       	call   1050 <puts@plt>
    1174:	48 8d 05 a4 0e 00 00 	lea    0xea4(%rip),%rax        # 201f <_IO_stdin_used+0x1f>
    117b:	48 89 c7             	mov    %rax,%rdi
    117e:	e8 cd fe ff ff       	call   1050 <puts@plt>
    1183:	90                   	nop
    1184:	5d                   	pop    %rbp
    1185:	c3                   	ret    

Déassemblage de la section .fini :

0000000000001188 <_fini>:
    1188:	f3 0f 1e fa          	endbr64 
    118c:	48 83 ec 08          	sub    $0x8,%rsp
    1190:	48 83 c4 08          	add    $0x8,%rsp
    1194:	c3                   	ret    

test-disasm.o n’est pas un programme complet, il lui manque printf, qui est un programme de bibliothèque. Voici comment obtenir un programme complet, qui ressemblera au texte ci-dessus, avec des ajouts :

gcc -o test-disasm test-disasm.o

À partir d’un exécutable, reconstituer le texte source

Après avoir compris les étapes successives du processus de traduction d’un programme source en programme binaire exécutable, telles qu’exposées par les sections ci-dessus, nous pouvons étudier la démarche inverse, qui consiste, à partir d’un programme binaire exécutable suspect récupéré sur la scène du crime, à reconstituer un programme source dans un langage à peu près compréhensible. Il est relativement facile de produire le texte assembleur, nettement moins évident de reconstituer le programme C. Cette opération de traduction inverse se nomme aussi désassemblage. Outre le déminage de logiciels malfaisants, le désassemblage peut également servir à la rétro-ingénierie d’un logiciel dont on souhaite reproduire les fonctionnalités pour son propre compte.

J’ai fait des essais avec deux désassembleurs : la version gratuite d’IDA Pro, conçu et réalisé par Ilfak Guilfanov (dont Wikipédia nous apprend qu’issu d’une famille de Tatars de la Volga, il s’est installé en Belgique), et Ghidra, logiciel libre réalisé par la National Security Agency (NSA), un éditeur de bonne réputation.

IDA Pro fournit le code assembleur, mais la version gratuite ne permet pas de reconstituer le texte C, que donnerait la version payante.

Fenêtre IDA Pro 8.2

Ghidra est d’une mise en œuvre un peu plus laborieuse qu’IDA Pro, l’affichage est assez touffu mais complet, et on peut reconstituer le texte d’un programme C, qui est bien sûr différent du programme d’origine, mais censé produire le même résultat.

Fenêtre Ghidra 10.2.2