Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
r2gopclntabParser — Un script radare2 pour parser le gopclntab afin de faciliter la rétro-ingénierie des binaires Go. | Kitploit
Outils/GitHubGitHub/asherdll/r2gopclntabparser
Analyse StatiqueRétro-ingénierieDébogueursAnalyse ForensiqueAnalyse de MalwareAnalyse de Binaires
GitHubasherdll/r2gopclntabparser

r2gopclntabParser

Un script radare2 pour parser le gopclntab afin de faciliter la rétro-ingénierie des binaires Go.

Voir le dépôt
17il y a 4 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

r2gopclntabParser

Note : Cette fonctionnalité a été implémentée directement dans le cœur de radare2 sous la forme du plugin d'analyse gopc

Un analyseur gopclntab basé sur radare2 pour récupérer les symboles de fonctions de binaires Go, y compris ceux entièrement strippés. Prend en charge les binaires ELF, Mach-O et PE pour les versions Go 1.2, 1.16, 1.18 et 1.20+.

Chaque binaire Go 1.2+ intègre une région de données appelée gopclntab (Program Counter Line Table) que le runtime Go utilise pour les traces de pile, les messages de panique, le ramasse-miettes et le support du débogueur. C'est l'une des sources d'information les plus précieuses sur les symboles dans les binaires Go.

r2gopclntabParser lit cette région via radare2, analyse les structures spécifiques à la version, et soit affiche la liste des fonctions récupérées (avec adresses, fichiers sources et numéros de ligne), soit applique les noms récupérés dans la session radare2 ouverte en tant que définitions de fonctions, flags et commentaires.


Table des matières

  • Prérequis
  • Démarrage rapide
  • Référence CLI
  • Modes de sortie et exemples
    • Mode par défaut (En-tête + Liste des fonctions)
    • Mode verbeux (-v)
    • Mode recherche (-n)
    • Sortie JSON (--json)
    • Liste des fichiers sources (--files)
    • Mode application (--apply)
  • Résumé des résultats : Mach-O (Binaire de test strippé)
  • Test PE : Greenblood, un binaire de ransomware Go
  • Cas d'utilisation pour la rétro-ingénierie
  • Plateformes et versions Go prises en charge
  • Méthodologie
    • Stratégie de localisation des sections
    • textStart vs section .text
    • Analyse des structures selon la version
    • Décodage des données PC
  • Limitations
  • Documentation supplémentaire
  • Références

Prérequis

DépendanceVersion minimale
Python 33.8+
radare25.0+ (testé sur 6.0.9)
r2pipetoute

Aucun autre paquet Python n'est requis. Le script utilise uniquement la bibliothèque standard (struct, json, argparse, os, sys) ainsi que r2pipe.


Démarrage rapide```bash

List all functions recovered from a Go binary

python3 r2_gopclntab.py -f ./mybinary -l

Search for a specific function (substring match)

python3 r2_gopclntab.py -f ./mybinary -n main.main

Verbose header + function list

python3 r2_gopclntab.py -f ./mybinary -v -l

Apply recovered names into an r2 session

python3 r2_gopclntab.py -f ./mybinary --apply

JSON output

python3 r2_gopclntab.py -f ./mybinary --json

From within r2 (attach to running session)

#!pipe python3 r2_gopclntab.py --r2pipe --apply -v

root@kitploit:~
---

## Référence CLI```
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
                       [--apply] [--json] [--files] [--r2pipe]

Requis (un parmi)

FlagDescription
-f FILE, --file FILEChemin vers le binaire Go à analyser. Le script lance sa propre instance r2.
--r2pipeSe connecter à une session r2 déjà en cours (pour une utilisation dans la console r2).

Optionnel

Les flags peuvent être combinés librement. Lorsqu'aucun flag de sortie n'est donné, le comportement par défaut est d'afficher l'en-tête et la liste complète des fonctions.


Modes de sortie et exemples

Tous les exemples ci-dessous ont été exécutés sur un binaire Go 1.26 Mach-O arm64 élagué (construit avec -ldflags="-s -w"). Le programme de test définit main.main, main.fibonacci, main.helloWorld et main.addNumbers. Le compilateur a intégré helloWorld et addNumbers, donc ils n'apparaissent pas dans le gopclntab.

Mode par défaut (en-tête + liste de fonctions)

En exécutant sans flag (ou juste -f), on obtient l'en-tête analysé suivi de la table complète des fonctions :``` $ python3 r2_gopclntab.py -f ./gotest_stripped

root@kitploit:~
.

To be precise, I'll just not write anything. However, the API might require a message. I'll send an empty string.```
============================================================
  Go pclntab Header
============================================================
  Magic:           0xFFFFFFF1
  Go version:      1.20+
  Pointer size:    8
  Min LC (quantum):4
  Num functions:   2030
  Num files:       261
  funcnameOffset:  0x48
  cuOffset:        0x14D20
  filetabOffset:   0x158D8
  pctabOffset:     0x19A98
  pclnOffset:      0x55E40
============================================================

ADDRESS       FUNCTION NAME
----------------------------------------------------------------------
0x100001000   go:buildid
0x100001070   internal/abi.BoundsDecode  (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go:86)
0x100001150   internal/abi.NoEscape  (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/escape.go:19)
0x100001160   internal/abi.Kind.String  (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:143)
0x1000011E0   internal/abi.TypeOf  (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:181)
0x1000011F0   internal/abi.(*Type).ExportedMethods  (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:453)
...
0x1000A0BB0   main.fibonacci  (/tmp/gotest/main.go:13)
0x1000A0C20   main.main  (/tmp/gotest/main.go:20)
0x1000A0D20   go:textfipsstart
0x1000A0D30   go:textfipsend

[+] 2030 function(s) shown

Mode verbose (-v)

Ajoute la progression de l'analyse des sections, les détails de résolution de textStart et les informations de décalage interne :``` $ python3 r2_gopclntab.py -f ./gotest_stripped -v

root@kitploit:~
### Documentation

Pour des instructions d'utilisation complètes et la documentation, consultez : [NetDoc Documentation](https://github.com/```
[*] Running radare2 analysis...
[*] Binary format: mach0, endian: little, arch: arm, bits: 64
[*] Scanning binary for gopclntab magic bytes...
[*]   Scanning section '0.__TEXT.__text' (0x100001000, 0x9FD44)...
[*]   Scanning section '1.__TEXT.__symbol_stub1' (0x1000A0D60, 0x2B8)...
[*]   Scanning section '2.__TEXT.__rodata' (0x1000A1020, 0xACC2)...
[*]   Scanning section '3.__TEXT.__gopclntab' (0x1000ABCE8, 0xA48AE)...
[*]   Found magic at vaddr=0x1000ABCE8
[*] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ptrSize=8, minLC=4,
    nfunc=2030, nfiles=261, textStart=0x0)
[*] textStart is 0, using .text section vaddr: 0x100001000
[*] Parsed 2030 functions

============================================================
  Go pclntab Header
============================================================
  Magic:           0xFFFFFFF1
  Go version:      1.20+
  ...

Mode de recherche (-n)

Filtre la liste des fonctions par correspondance de sous-chaîne. Si une correspondance exacte existe, son adresse est imprimée séparément.

Recherche de sous-chaîne pour toutes les fonctions contenant main. :``` $ python3 r2_gopclntab.py -f ./gotest_stripped -n "main."

root@kitploit:~
VERSION = "2.0"
    DESCRIPTION = "Find vulnerabilities easily."

[![GitHub Issues](https://img.shields.io/badge/issues-0-brightgreen)](https://github.com/example/issues)

- [Fonctionnalités](#features)
- [Installation](#installation)
- [Utilisation](#usage)
- [Exemples](#examples)

## Fonctionnalités

- **Analyse rapide** avec multithreading.
- **Rapports complets** aux formats HTML et PDF.
- **Interface en ligne de commande conviviale** avec sortie colorée.

## Installation

```bash
pip install vulnscanner

Utilisation

root@kitploit:~
vulnscanner scan --target example.com --output report.html

Exemples

Cet outil est conçu pour les équipes rouges et les chercheurs en sécurité.

Pour commencer, exécutez la commande suivante :

root@kitploit:~
vulnscanner --help

Pour plus de détails, consultez la documentation.

Remarque : Cet outil nécessite Python 3.8 ou supérieur.

Python Version

Support

Si vous rencontrez des problèmes, veuillez ouvrir un problème sur GitHub.

---``` ADDRESS FUNCTION NAME

0x100041920 runtime.main.func2 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:207) 0x10006CE30 runtime.main.func1 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:174) 0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13) 0x1000A0C20 main.main (/tmp/gotest/main.go:20)

[+] 4 function(s) shown (filtered from 2030 total)

root@kitploit:~
Recherche de correspondance exacte :```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "main.fibonacci"

?``` ADDRESS FUNCTION NAME

0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13)

[+] 1 function(s) shown (filtered from 2030 total)

[+] Exact match: main.fibonacci @ 0x1000A0BB0

root@kitploit:~
Recherche des internes du runtime liés au GC :```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "runtime.gc"

ENTRÉE:``` ADDRESS FUNCTION NAME

0x10001F310 runtime.gcinit (/opt/homebrew/.../src/runtime/mgc.go:179) 0x10001F3C0 runtime.gcenable (/opt/homebrew/.../src/runtime/mgc.go:211) 0x10001F730 runtime.gcStart (/opt/homebrew/.../src/runtime/mgc.go:733) 0x10001FFE0 runtime.gcMarkDone (/opt/homebrew/.../src/runtime/mgc.go:1015) 0x100020A50 runtime.gcMarkTermination (/opt/homebrew/.../src/runtime/mgc.go:1344) 0x100021C10 runtime.gcBgMarkWorker (/opt/homebrew/.../src/runtime/mgc.go:1750) 0x1000223D0 runtime.gcMark (/opt/homebrew/.../src/runtime/mgc.go:1956) 0x1000227A0 runtime.gcSweep (/opt/homebrew/.../src/runtime/mgc.go:2049) ... 0x100076C60 runtime.gcWriteBarrier1 (/opt/homebrew/.../src/runtime/asm_arm64.s:1533)

[+] 73 function(s) shown (filtered from 2030 total)

root@kitploit:~
Recherche de `fmt.` (impression de la bibliothèque standard):```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "fmt."

Veuillez fournir le contenu Markdown à traduire.``` ADDRESS FUNCTION NAME

0x100098AA0 fmt.(*fmt).writePadding (/opt/homebrew/.../src/fmt/format.go:66) 0x100098BF0 fmt.(*fmt).pad (/opt/homebrew/.../src/fmt/format.go:93) 0x100099590 fmt.(*fmt).fmtInteger (/opt/homebrew/.../src/fmt/format.go:197) 0x10009ADF0 fmt.Fprintf (/opt/homebrew/.../src/fmt/print.go:222) 0x10009AED0 fmt.Fprintln (/opt/homebrew/.../src/fmt/print.go:303) 0x10009D3F0 fmt.(*pp).printArg (/opt/homebrew/.../src/fmt/print.go:721) 0x10009D950 fmt.(*pp).printValue (/opt/homebrew/.../src/fmt/print.go:797) 0x10009FA60 fmt.(*pp).doPrintf (/opt/homebrew/.../src/fmt/print.go:1018) ...

root@kitploit:~
Recherche de `sync.` (primitives de concurrence):```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "sync."

|

Collation sur Windows 10 - 100 est le nouveau 1000, et l'invite UAC est le nouveau calc.exe``` ADDRESS FUNCTION NAME

0x10006FFE0 sync.runtime_registerPoolCleanup (/opt/homebrew/.../src/runtime/mgc.go:2150) 0x100070BA0 sync.fatal (/opt/homebrew/.../src/runtime/panic.go:1160) 0x1000714E0 sync.runtime_procPin (/opt/homebrew/.../src/runtime/proc.go:7912) 0x10007B290 internal/sync.(*Mutex).lockSlow (/opt/homebrew/.../src/internal/sync/mutex.go:95) 0x10007B570 internal/sync.(*Mutex).Unlock (/opt/homebrew/.../src/internal/sync/mutex.go:187) ...

root@kitploit:~
### Sortie JSON (--json)

Sortie lisible par machine pour l'intégration de scripts et de pipelines :```
$ python3 r2_gopclntab.py -f ./gotest_stripped --json

alert
!! Ceci est un travail en cours - loin d'être terminé !!```json { "header": { "magic": "0xFFFFFFF1", "version": "1.20+", "ptrSize": 8, "minLC": 4, "nfunc": 2030, "nfiles": 261, "textStart": "0x0" }, "functions": [ { "name": "go:buildid", "addr": "0x100001000", "args": 0, "source_file": "", "start_line": 0 }, { "name": "internal/abi.BoundsDecode", "addr": "0x100001070", "args": 8, "source_file": "/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go", "start_line": 86 }, { "name": "main.fibonacci", "addr": "0x1000A0BB0", "args": 0, "source_file": "/tmp/gotest/main.go", "start_line": 13 }, { "name": "main.main", "addr": "0x1000A0C20", "args": 0, "source_file": "/tmp/gotest/main.go", "start_line": 20 } ], "num_source_files": 261 }

root@kitploit:~
### Liste des fichiers sources (--files)

Extrait tous les chemins des fichiers sources intégrés dans le binaire :```
$ python3 r2_gopclntab.py -f ./gotest_stripped --files

Préparer l'environnement et exécuter le conteneur Volatility 3```

Source files (261):

/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/escape.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/cpu/cpu.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/cpu/cpu_arm64.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/mgc.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/malloc.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/panic.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/fmt/print.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/fmt/format.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/reflect/value.go /opt/homebrew/Cellar/go/1.26.1/libexec/src/reflect/type.go /tmp/gotest/main.go ... ... and 61 more

root@kitploit:~
### Apply Mode (--apply)

Écrit tous les noms de fonctions récupérés dans la session radare2. Ce qui suit montre une comparaison avant/après sur le binaire dépouillé.

**AVANT** (analyse native r2 sur binaire dépouillé, sans analyse gopclntab) :```
Functions found by r2 natively: 1913

Disassembly at 0x1000a0c20 (main.main, unnamed):

            ; CODE XREF from fcn.1000a0c20 @ 0x1000a0d14(r)
  24: fcn.1000a0c20 (int64_t arg1);
           0x1000a0c20      900b40f9       ldr x16, [x28, 0x10]
           0x1000a0c24      ff6330eb       cmp sp, x16
           0x1000a0c28      29070054       b.ls 0x1000a0d0c

Disassembly at 0x1000a0bb0 (main.fibonacci, unnamed):

  112: fcn.1000a0bb0 (signed int64_t arg1, int64_t arg_8h);
           0x1000a0bb0      900b40f9       ldr x16, [x28, 0x10]
           0x1000a0bb4      ff6330eb       cmp sp, x16
           0x1000a0bb8      a9020054       b.ls 0x1000a0c0c

r2 a trouvé 1913 fonctions mais n'en a nommé aucune (seulement des étiquettes anonymes fcn.XXXXXXXX). Chercher main.main ou main.fibonacci ne renvoie rien.

Application des symboles gopclntab :``` [] Binary format: mach0, endian: little, arch: arm, bits: 64 [] Found magic at vaddr=0x1000ABCE8 [] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ...) [] textStart is 0, using .text section vaddr: 0x100001000 [*] Parsed 2030 functions [+] Applied 2030 function names to radare2 (0 skipped)

root@kitploit:~
**APRÈS** (session r2 avec symboles gopclntab appliqués):```
r2 function list matching "main" (after --apply):

0x100041510    0      0 runtime.main
0x100041920    0      0 runtime.main.func2
0x10006ce30    0      0 runtime.main.func1

Flags in go.* flagspace (last 20):

0x10009fa60 1 go.fmt._ptr_pp_.doPrintf
0x1000a0930 1 go.fmt._ptr_pp_.doPrintln
0x1000a0bb0 1 go.main.fibonacci
0x1000a0c20 1 go.main.main
0x1000a0d20 1 go.go:textfipsstart
0x1000a0d30 1 go.go:textfipsend

Le désassemblage au niveau de main.main montre maintenant le nom et l'emplacement source récupérés :``` ;-- go.main.main: 24: fcn.1000a0c20 (int64_t arg1); 0x1000a0c20 900b40f9 ldr x16, [x28, 0x10] ; " src: /tmp/gotest/main.go:20" 0x1000a0c24 ff6330eb cmp sp, x16 0x1000a0c28 29070054 b.ls 0x1000a0d0c

root@kitploit:~
Le désassemblage à `main.fibonacci` montre désormais le nom et l'emplacement source récupérés:```
            ;-- go.main.fibonacci:
  112: fcn.1000a0bb0 (signed int64_t arg1, int64_t arg_8h);
           0x1000a0bb0      900b40f9       ldr x16, [x28, 0x10]       ; " src: /tmp/gotest/main.go:13"
           0x1000a0bb4      ff6330eb       cmp sp, x16
           0x1000a0bb8      a9020054       b.ls 0x1000a0c0c

La recherche par nom fonctionne désormais dans la session r2 :``` go.main.main resolves to: 0x1000a0c20 go.main.fibonacci resolves to: 0x1000a0bb0

root@kitploit:~
---

## Résumé des résultats : Mach-O (binaire de test ébarbé)

| Métrique | r2 natif (ébarbé) | Après r2_gopclntab.py |
|---|---|---|
| Fonctions trouvées | 1913 (étiquettes anonymes `fcn.XXXX`) | 2030 (noms complets qualifiés par paquet Go) |
| Fonctions utilisateur identifiées | 0 | `main.main`, `main.fibonacci` avec source + ligne |
| Fichiers source récupérés | 0 | 261 (chemins absolus complets) |
| Symboles nommés | Uniquement les stubs d'importation C (`sym.imp.mmap`, etc.) | Chaque fonction Go étiquetée (`go.main.main`, `go.runtime.gcStart`, etc.) |
| Commentaires source | Aucun | Dans le désassemblage, en ligne `src: /tmp/gotest/main.go:20` |
| Navigable par nom | Non | Oui (`s go.main.main`, `afl~runtime.gc`) |

---

## Test PE : Greenblood, un binaire ransomware Go

L'analyseur a été testé avec un binaire PE réel, Greenblood (`greenblood_1`), un
échantillon de ransomware Go compilé en tant qu'exécutable Windows PE32+ x86-64.
Les binaires PE n'ont pas de section `.gopclntab` dédiée, ce qui met en œuvre le
chemin de repli par balayage des octets magiques.

### Détection et en-tête```
$ python3 r2_gopclntab.py -f ./greenblood_1 -v

No content provided for translation.``` [] Binary format: pe, endian: little, arch: x86, bits: 64 [] Scanning binary for gopclntab magic bytes... [] Scanning section '.text' (0x401000, 0xF4000)... [] Scanning section '.rdata' (0x4F5000, 0x127000)... [] Found magic at vaddr=0x568C00 [] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ptrSize=8, minLC=1, nfunc=2596, nfiles=345, textStart=0x401000) [] textStart from header: 0x401000 [] Parsed 2596 functions

root@kitploit:~
Le scanner a trouvé le gopclntab dans la section `.rdata` à `0x568C00`.
Comme il s'agit d'un PE standard (pas PIE), `textStart` est `0x401000` (non nul),
donc la valeur de l'en-tête est utilisée directement pour le calcul d'adresse.

| Champ | Valeur |
|---|---|
| Format | PE32+ x86-64 |
| gopclntab location | `.rdata` à `0x568C00` (trouvé par magic scan) |
| Magic | `0xFFFFFFF1` (Go 1.20+) |
| Pointer size | 8 |
| Quantum (minLC) | 1 (x86) |
| textStart | `0x401000` (depuis l'en-tête) |
| Functions recovered | 2596 |
| Source files | 345 |

### Fonctions du malware récupérées

Recherche du code propre au malware (`main.`) :```
$ python3 r2_gopclntab.py -f ./greenblood_1 -n "main."

Une fois la construction générée, le jeu commence ; le processus est que l'application web (kibana:5601) envoie des alertes aléatoires à la passerelle (gateway:30443) et à la console (console:3000) tout en affichant le scénario total déployé et une table des matières de tous les scénarios disponibles. Après la configuration initiale, les seules options qui doivent être configurées pour chaque utilisateur sont les variables d'environnement Docker suivantes :

  • ES_USER: par défaut admin
  • ES_PASSWORD: par défaut admin
  • KIBANA_URL: par défaut http://kibana:5601
  • KIBANA_USER: par défaut admin
  • KIBANA_PASSWORD: par défaut admin
  • CLOUD_ID: par défaut none
  • AIOPS_PLUGIN_URL: par défaut http://caddy:8080
  • APISERVER_PORT: par défaut

Toutes les valeurs suivantes peuvent être définies en tant que variables d'environnement, mais sont également calculées automatiquement à partir des précédentes ou à partir du conteneur lancé :``` ADDRESS FUNCTION NAME

0x4D91E0 main.init (:1) 0x4D9200 main.map.init.0 (/root/victims/ransom/daf/enc.go:59) 0x4D92C0 main.map.init.1 (/root/victims/ransom/daf/enc.go:126) 0x4D95C0 main.NewKeyManager (/root/victims/ransom/daf/enc.go:146) 0x4D97E0 main.getMachineFingerprint (/root/victims/ransom/daf/enc.go:173) 0x4DA2C0 main.getBIOSUUID (/root/victims/ransom/daf/enc.go:249) 0x4DA3C0 main.NewEncryptionEngine (/root/victims/ransom/daf/enc.go:287) 0x4DA560 main.(*EncryptionEngine).fileWorker (/root/victims/ransom/daf/enc.go:303) 0x4DA660 main.(*EncryptionEngine).processFile (/root/victims/ransom/daf/enc.go:319) 0x4DA740 main.(*EncryptionEngine).encryptFile (/root/victims/ransom/daf/enc.go:334) 0x4DB2A0 main.(*EncryptionEngine).EncryptPath (/root/victims/ransom/daf/enc.go:446) 0x4DB620 main.(*EncryptionEngine).shouldSkipDirectory (/root/victims/ransom/daf/enc.go:495) 0x4DB7C0 main.(*EncryptionEngine).shouldEncryptFile (/root/victims/ransom/daf/enc.go:522) 0x4DB9A0 main.(*EncryptionEngine).placeRansomNote (/root/victims/ransom/daf/enc.go:560) 0x4DBB60 main.(*EncryptionEngine).recordSuccess (/root/victims/ransom/daf/enc.go:636) 0x4DBFA0 main.(*EncryptionEngine).Wait (/root/victims/ransom/daf/enc.go:664) 0x4DC3C0 main.formatBytes (/root/victims/ransom/daf/enc.go:689) 0x4DC500 main.disableRecovery (/root/victims/ransom/daf/enc.go:706) 0x4DC720 main.isAdmin (/root/victims/ransom/daf/enc.go:732) 0x4DC8C0 main.main (/root/victims/ransom/daf/enc.go:760) 0x4DD260 main.getLogicalDrives (/root/victims/ransom/daf/enc.go:863) 0x4DD4A0 main.isAlreadyRunning (/root/victims/ransom/daf/enc.go:892) 0x4DD660 main.getDesktopPath (/root/victims/ransom/daf/enc.go:911) 0x4DD780 main.removeExecutable (/root/victims/ransom/daf/enc.go:932) ...

[+] 43 function(s) shown (filtered from 2596 total)

root@kitploit:~
Toutes les 43 fonctions utilisateur ont été récupérées à partir d'un seul fichier source situé à
`/root/victims/ransom/daf/enc.go`. Les noms des fonctions révèlent immédiatement les
capacités du rançongiciel : gestion des clés, empreinte de la machine, chiffrement
des fichiers avec traversée de chemin, placement de la note de rançon, désactivation des
restaurations, vérification des privilèges, limitation à une seule instance via mutex,
énumération des lecteurs et auto-suppression.

### Dépendances non issues de la bibliothèque standard

Extraction des fichiers sources qui ne font pas partie de la bibliothèque standard Go :```
/root/go/pkg/mod/golang.org/x/[email protected]/windows/dll_windows.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/registry/key.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/registry/value.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/security_windows.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/str.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/syscall.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/syscall_windows.go
/root/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go
/root/victims/ransom/daf/enc.go

La seule dépendance externe est golang.org/x/[email protected] pour les appels système spécifiques à Windows (accès au registre, jetons de sécurité, chargement de DLL).

Fonctions Cryptographiques

La recherche de crypto révèle 137 fonctions liées à la cryptographie, notamment :``` $ python3 r2_gopclntab.py -f ./greenblood_1 -n "crypto"

root@kitploit:~
- 🪟 [**pivotnacci**](https://github.com/blackarrowsec/pivotnacci): Outil qui permet de faire un tunnel socks vers un serveur HTTP, modélisant les agents en tant que machines à états.

  Utilisateurs de FreeBSD

- Si vous avez installé via le port git :
  ```bash
  sudo pkg upgrade git
  • Pour mettre à jour vers la dernière version :
    root@kitploit:~
    sudo pkg update
    sudo pkg upgrade
    

ADDRESS FUNCTION NAME

0x4AEC00 crypto/cipher.NewCTR (/usr/local/go/src/crypto/cipher/ctr.go:41) 0x4AF520 crypto/cipher.StreamWriter.Write (/usr/local/go/src/crypto/cipher/io.go:36) 0x4AF840 crypto/aes.NewCipher (/usr/local/go/src/crypto/aes/aes.go:36) 0x4C3760 crypto/rand.(*reader).Read (/usr/local/go/src/crypto/rand/rand.go:45) 0x4DE6C0 crypto/internal/fips140/sha256.New (.../sha256/sha256.go:138) 0x4E3EC0 crypto/internal/fips140/sha3.NewCShake128 (.../sha3/shake.go:134) 0x4EED60 crypto/internal/fips140/hmac.New (.../hmac/hmac.go:131) 0x4EF800 crypto/internal/fips140/aes.newBlock (.../aes/aes_asm.go:59) 0x4F0800 crypto/internal/fips140/aes.(*CBCEncrypter).CryptBlocks (.../aes/cbc.go:26) 0x4F0FE0 crypto/internal/fips140/aes.(*CTR).XORKeyStream (.../aes/ctr.go:41) ...

[+] 137 function(s) shown (filtered from 2596 total)

root@kitploit:~
Le profil d'utilisation cryptographique : AES (modes CBC et CTR), SHA-256, SHA-512, HMAC, CSHAKE128 et DRBG (générateur de bits aléatoires déterministe). Ceci est cohérent avec les ransomwares qui génèrent des clés de chiffrement par machine dérivées d'une empreinte de la machine, chiffrent les fichiers avec AES-CTR et utilisent HMAC pour l'intégrité.

### Mode d'Application```
$ python3 r2_gopclntab.py -f ./greenblood_1 --apply
[+] Applied 2596 function names to radare2 (0 skipped)
[+] Function names applied. Use 'afl' in r2 to see them.

Les 2596 fonctions ont été appliquées avec succès, sans aucune omission.


Cas d'utilisation pour la rétro-ingénierie

1. Triage et identification

Déterminez instantanément si un binaire est écrit en Go, avec quelle version il a été compilé et quels packages il utilise. La sortie --files révèle la version de la toolchain Go (à partir de chemins comme /usr/local/go/1.26.1/...) et tous les chemins des fichiers sources, y compris les bibliothèques tierces. Pour les malwares, cela révèle immédiatement si l'échantillon utilise crypto/tls, net/http, os/exec ou d'autres packages d'intérêt.

2. Récupération de symboles sur les binaires stripés

Le cas d'usage central. Les binaires Go stripés avec -ldflags="-s -w" perdent leur table de symboles, mais gopclntab survit. Cet outil restaure chaque nom de fonction, transformant les fonctions anonymes fcn.1000a0c20 en main.main. Cela s'applique aux échantillons de malwares, aux défis CTF, aux binaires de production et à tout exécutable Go stripé.

3. Navigation dans le runtime Go

Les binaires Go embarquent l'intégralité du runtime (généralement 1500 à 2000+ fonctions). Sans noms, le runtime est un mur impénétrable de fonctions anonymes. Avec des noms, vous pouvez localiser instantanément runtime.mallocgc, runtime.gopanic, runtime.newproc, runtime.gcStart et comprendre ce que fait le binaire à chaque point d'appel.

4. Séparation du code utilisateur du runtime

En recherchant main. ou le chemin du package de l'application, vous pouvez isoler uniquement le code utilisateur du runtime. Dans les exemples ci-dessus, filtrer sur main. révèle immédiatement main.main et main.fibonacci parmi 2030 fonctions au total. Vous pouvez également rechercher par noms de packages tiers (par exemple -n "github.com/user/repo") pour identifier les dépendances externes.

5. Contexte au niveau du code source

Chaque fonction est accompagnée de son chemin de fichier source et du numéro de ligne de début. Cela signifie que vous pouvez recouper le désassemblage avec le code source de la bibliothèque standard Go (qui est ouverte), même lors de l'analyse d'un binaire stripé. Savoir qu'une fonction commence à la ligne 733 de runtime/mgc.go vous permet de lire le code source original en parallèle du désassemblage.

6. Pipeline et automatisation

Le mode --json permet l'écriture de scripts. Injectez la sortie dans des importateurs IDA/Ghidra, des outils de comparaison, des générateurs de règles YARA ou toute pipeline d'analyse. Par exemple, pour extraire toutes les fonctions liées à la cryptographie :```bash python3 r2_gopclntab.py -f sample.exe --json
| jq '.functions[] | select(.name | contains("crypto"))'

root@kitploit:~
### 7. Workflow interactif radare2

Après `--apply`, la session r2 entière devient navigable par nom Go. Vous pouvez vous rendre à des fonctions (`s go.main.main`), chercher dans la liste des fonctions (`afl~runtime.gc`), inspecter les références croisées (`axf go.main.fibonacci`), et voir les commentaires d'emplacement source en ligne dans le résultat du désassemblage (`pd`). Cela transforme r2 d'un désassembleur générique en un environnement d'analyse sensible à Go.

---

## Plateformes supportées et versions de Go

### Formats binaires

| Format | Méthode de découverte de section | Testé |
|---|---|---|
| ELF (Linux) | Nom de section `.gopclntab` ou `.data.rel.ro.gopclntab` | Oui |
| Mach-O (macOS) | Nom de section `__gopclntab` (à l'intérieur du segment `__TEXT`) | Oui |
| PE (Windows) | Scan par octets magiques (pas de section dédiée) | Oui (testé sur Greenblood, un ransomware Go PE64) |

Pour les binaires PE et les binaires ELF/Mach-O agressivement stripés qui manquent l'en-tête de section, l'outil se rabat sur le scan de toutes les sections pour les 4 octets magiques suivis des octets de validation (pad=0, ptrSize dans {4,8}, minLC dans {1,2,4}).

### Versions de Go

| Magique | Version de Go | `textStart` dans l'en-tête | Type de `functab.entry` | Champ `startLine` | Statut |
|---|---|---|---|---|---|
| `0xFFFFFFFB` | 1.2 | Non | `uintptr` (absolu) | Non | Supporté |
| `0xFFFFFFFA` | 1.16 | Non | `uintptr` (absolu) | Non | Supporté |
| `0xFFFFFFF0` | 1.18 - 1.19 | Oui | `uint32` (relatif) | Non | Supporté |
| `0xFFFFFFF1` | 1.20+ | Oui (peut être 0) | `uint32` (relatif) | Oui | Supporté |

La magie `0xFFFFFFF1` est utilisée par Go 1.20 jusqu'à au moins Go 1.26.

---

## Méthodologie

### Stratégie de localisation de section

L'analyseur utilise une approche en deux phases pour trouver les données gopclntab :

**Phase 1 (ELF/Mach-O) :** Interroger la liste des sections de radare2 (`iSj`) et rechercher les sections nommées `.gopclntab`, `.data.rel.ro.gopclntab` ou `__gopclntab`.

**Phase 2 (PE/fallback) :** Si aucune section nommée n'est trouvée, scanner toutes les sections pour les 4 octets magiques. Chaque candidat est validé en vérifiant que les octets 4-7 correspondent au motif attendu : deux octets de padding zéro, une taille de pointeur valide (4 ou 8) et un quantum d'instruction valide (1, 2 ou 4). Cela élimine les faux positifs provenant de motifs d'octets fortuits.

### textStart par rapport à la section .text

À partir de Go >= 1.18, les points d'entrée des fonctions dans le functab sont stockés comme des décalages relatifs. Le calcul de l'adresse virtuelle absolue nécessite une base :```
absolute_addr = base + entryoff

La base est résolue avec la logique suivante :``` Is magic 0xFFFFFFFB (Go 1.2)? YES -> base = 0 (entries are absolute addresses) NO -> Is magic 0xFFFFFFFA (Go 1.16)? YES -> base = .text section vaddr (entries are absolute) NO -> (Go 1.18 / 1.20+) Is header.textStart != 0? YES -> base = header.textStart NO -> base = .text section vaddr

root@kitploit:~
Le cas `textStart == 0` se produit dans Go >= 1.22 pour les binaires Mach-O et PIE.
Lorsque cela se produit, les valeurs `entryoff` sont relatives au début de la section `.text`,
donc l'analyseur interroge r2 pour l'adresse virtuelle de `.text` et l'utilise comme base.

Cela a été vérifié sur un binaire Go 1.26 Mach-O arm64 :
- `textStart` dans l'en-tête : `0x0`
- `.text` section vaddr : `0x100001000`
- `functab[1].entryoff` : `0x70`
- Adresse calculée : `0x100001000 + 0x70 = 0x100001070`
- L'analyse native de r2 a confirmé `internal/abi.BoundsDecode` à l'adresse `0x100001070`

### Analyse de structure adaptée à la version

La disposition de la structure `_func` diffère entre Go 1.18 et Go 1.20+. La seule
modification est l'insertion d'un champ `startLine` de 4 octets au décalage 36 dans Go
1.20+, ce qui décale `funcID`, `flag` et `nfuncdata` de 4 octets :

| Champ | Décalage Go 1.18 | Décalage Go 1.20+ |
|---|---|---|
| `entryOff` | 0 | 0 |
| `nameOff` | 4 | 4 |
| `args` | 8 | 8 |
| `cuOffset` | 32 | 32 |
| `startLine` | (absent) | 36 |
| `funcID` | 36 | 40 |
| `flag` | 37 | 41 |
| `nfuncdata` | 39 | 43 |

L'analyseur vérifie le nombre magique pour déterminer quelle disposition utiliser.

### Décodage des données PC

Les indices de fichiers source et les numéros de ligne sont stockés sous forme de
« programmes de données PC » compacts dans la région pctab. Chaque programme encode une
séquence de paires `(value_delta, pc_delta)` en utilisant des entiers de longueur variable
avec un encodage zig-zag pour les valeurs signées. L'analyseur décode ceux-ci pour résoudre :

- Fichier source : `_func.pcfile` -> programme pctab -> index de fichier -> cutab ->
  filetab -> chaîne de chemin de fichier
- Numéro de ligne : `_func.pcln` -> programme pctab -> numéro de ligne (plus
  le décalage `startLine` pour Go 1.20+)

---

## Limitations

1. **Les fonctions inline** n'apparaissent pas dans la table des fonctions de premier
   niveau. Elles sont encodées dans les structures `FUNCDATA_InlTree` / `PCDATA_InlTreeIndex`,
   que cet outil ne décode pas actuellement. Dans le binaire de test,
   `main.helloWorld` et `main.addNumbers` ont été inline par le compilateur et
   n'apparaissent donc pas dans la sortie.

2. **Le support Go 1.2** est fourni au mieux. Le format Go 1.2 est sensiblement
   différent (pas de funcnametab séparé, pas de cutab, pointeurs absolus dans functab)
   et est rarement rencontré en pratique.

3. **Les architectures big-endian** sont gérées en principe (l'endianness est
   détectée à partir des informations binaires de radare2 et utilisée pour toutes les
   lectures de structures) mais n'ont pas été testées.

4. Le mode `--apply` crée des stubs de fonctions avec `af+` qui peuvent entrer
   en conflit avec l'auto-analyse de r2. L'exécuter sur une session propre (avant ou
   à la place de `aaa`) peut donner de meilleurs résultats dans certains cas.

---

## Documentation complémentaire

Une documentation technique détaillée est disponible dans le répertoire `documentation/` :

- [DOCUMENTATION.md](https://github.com/asherdll/r2gopclntabparser/blob/HEAD/documentation/DOCUMENTATION.md) - Documentation complète de l'utilisateur avec tous les modes d'utilisation, formats de sortie et combinaisons de drapeaux.
- [METHODOLOGY.md](https://github.com/asherdll/r2gopclntabparser/blob/HEAD/documentation/METHODOLOGY.md) - Décisions de conception et algorithmes : résolution textStart vs .text, analyse adaptée à la version, stratégie de numérisation PE, décodage des données PC, détails d'intégration r2.
- [GOPCLNTAB_FORMAT.md](https://github.com/asherdll/r2gopclntabparser/blob/HEAD/documentation/GOPCLNTAB_FORMAT.md) - Le format binaire gopclntab à travers les versions de Go : dispositions de structure au niveau octet, modèle mémoire, chaînes de décalages, encodage varint, résumé des différences de version.

---

## Références

- Source du runtime Go (pcHeader) : [go1.20.6/src/runtime/symtab.go#L414](https://github.com/golang/go/blob/go1.20.6/src/runtime/symtab.go#L414)
- Éditeur de liens Go (écrit le format) : [go1.20.6/src/cmd/link/internal/ld/pcln.go](https://github.com/golang/go/blob/go1.20.6/src/cmd/link/internal/ld/pcln.go)
- Mandiant - Golang Internals Symbol Recovery : [mandiant.com/resources/blog/golang-internals-symbol-recovery](https://www.mandiant.com/resources/blog/golang-internals-symbol-recovery)
- Document de conception de la table des symboles Go 1.2 : [docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o](https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o/pub)
Télécharger l’outil
FlagDescription
-l, --listAfficher chaque fonction récupérée avec son adresse.
-n NAME, --funcname NAMEAfficher uniquement les fonctions dont le nom contient NAME (correspondance de sous-chaîne). Si une correspondance exacte existe, son adresse est affichée séparément.
-v, --verboseAfficher les messages de progression, les champs d'en-tête analysés et les décalages internes.
--applyÉcrire les noms de fonctions récupérés dans la session radare2 en tant que définitions de fonctions (af+), flags dans l'espace de flags go., et commentaires avec le nom Go d'origine et l'emplacement source.
--jsonSortir l'en-tête et la liste complète des fonctions au format JSON sur stdout.
--filesAfficher la liste des chemins de fichiers sources extraits de la table des fichiers.
-h, --helpAfficher le message d'aide.
30445
  • APISERVER_HOST: par défaut https://gateway.herodotus.dev
  • MAX_CONCURRENT_API_CALLS: par défaut 100
  • AIOPS_CONSOLE_TROUBLESHOOTING_MODE: par défaut false