Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
r2gopclntabParser — Ein radare2-Skript zum Parsen der gopclntab, um das Reverse Engineering von Go-Binärdateien zu erleichtern. | Kitploit
Tools/GitHubGitHub/asherdll/r2gopclntabparser
Statische AnalyseReverse EngineeringDebuggerForensikMalware-AnalyseBinäranalyse
GitHubasherdll/r2gopclntabparser

r2gopclntabParser

Ein radare2-Skript zum Parsen der gopclntab, um das Reverse Engineering von Go-Binärdateien zu erleichtern.

Repository anzeigen
17vor 4 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

r2gopclntabParser

Hinweis: Diese Funktion wurde direkt in den Kern von radare2 als gopc analysis plugin implementiert.

Ein radare2-basierter Go gopclntab-Parser zum Wiederherstellen von Funktionssymbolen aus Go-Binaries, einschließlich vollständig gestrippter. Unterstützt ELF-, Mach-O- und PE-Binaries für Go-Versionen 1.2, 1.16, 1.18 und 1.20+.

Jedes Go 1.2+ Binary enthält einen Datenbereich namens gopclntab (Program Counter Line Table), den die Go-Laufzeit für Stack Traces, Panic-Meldungen, Garbage Collection und Debugger-Unterstützung verwendet. Es ist eine der wertvollsten Quellen für Symbolinformationen in Go-Binaries.

r2gopclntabParser liest diesen Bereich über radare2, parst die versionsspezifischen Strukturen und gibt entweder die wiederhergestellte Funktionsliste (mit Adressen, Quelldateien und Zeilennummern) aus oder wendet die wiederhergestellten Namen wieder in die offene radare2-Sitzung als Funktionsdefinitionen, Flags und Kommentare an.


Inhaltsverzeichnis

  • Voraussetzungen
  • Schnellstart
  • CLI-Referenz
  • Ausgabemodi und Beispiele
    • Standardmodus (Header + Funktionsliste)
    • Ausführlicher Modus (-v)
    • Suchmodus (-n)
    • JSON-Ausgabe (--json)
    • Quelldateien auflisten (--files)
    • Anwendungsmodus (--apply)
  • Ergebniszusammenfassung: Mach-O (gestripptes Test-Binary)
  • PE-Test: Greenblood, ein Go-Ransomware-Binary
  • Anwendungsfälle für Reverse Engineering
  • Unterstützte Plattformen und Go-Versionen
  • Methodik
    • Strategie zur Abschnittslokalisierung
    • textStart vs. .text-Abschnitt
    • Versionsbewusstes Struktur-Parsen
    • PC-Datendekodierung
  • Einschränkungen
  • Zusätzliche Dokumentation
  • Referenzen

Voraussetzungen

AbhängigkeitMindestversion
Python 33.8+
radare25.0+ (getestet mit 6.0.9)
r2pipebeliebig

Es werden keine weiteren Python-Pakete benötigt. Das Skript verwendet nur die Standardbibliothek (struct, json, argparse, os, sys) sowie r2pipe.


Schnellstart```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:~
## CLI-Referenz```
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
                       [--apply] [--json] [--files] [--r2pipe]

Erforderlich (eine davon)

FlagBeschreibung
-f FILE, --file FILEPfad zur zu analysierenden Go-Binärdatei. Das Skript startet eine eigene r2-Instanz.
--r2pipeAn eine bereits laufende r2-Sitzung anhängen (zur Verwendung innerhalb der r2-Konsole).

Optional

Flags können frei kombiniert werden. Wenn kein Ausgabe-Flag angegeben ist, werden standardmäßig der Header und die vollständige Funktionsliste ausgegeben.


Ausgabemodi und Beispiele

Alle untenstehenden Beispiele wurden gegen eine gestrippte Go 1.26 Mach-O arm64-Binärdatei ausgeführt (kompiliert mit -ldflags="-s -w"). Das Testprogramm definiert main.main, main.fibonacci, main.helloWorld und main.addNumbers. Der Compiler hat helloWorld und addNumbers inline eingefügt, sodass sie nicht im gopclntab erscheinen.

Standardmodus (Header + Funktionsliste)

Bei Ausführung ohne Flags (oder nur -f) wird der geparste Header gefolgt von der vollständigen Funktionstabelle ausgegeben:``` $ python3 r2_gopclntab.py -f ./gotest_stripped

root@kitploit:~
### Projektzuordnung
[COBALT](https://github.com/MobSF/mobsfscan/tree/main/mobsfscan/rules/semgrep) enthält einen robusten Satz an Regeln für Android-Sicherheit und Datenschutz.```
============================================================
  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

Ausführlicher Modus (-v)

Fügt Abschnitts-Scan-Fortschritt, textStart-Auflösungsdetails und interne Offset-Informationen hinzu:``` $ python3 r2_gopclntab.py -f ./gotest_stripped -v

root@kitploit:~
[No content provided after INPUT:]```
[*] 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+
  ...

Suchmodus (-n)

Filtert die Funktionsliste durch Teilzeichenfolgen-Übereinstimmung. Wenn eine exakte Übereinstimmung existiert, wird deren Adresse separat ausgegeben.

Teilzeichenfolgensuche nach allen Funktionen, die main. enthalten:``` $ python3 r2_gopclntab.py -f ./gotest_stripped -n "main."

root@kitploit:~
Der obige Befehl scannt das Netzwerk `192.168.1.0/24` und führt Tests nur auf Port 80 durch.```
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)

Exakte Übereinstimmungssuche:``` $ python3 r2_gopclntab.py -f ./gotest_stripped -n "main.fibonacci"

root@kitploit:~

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:~
Suche nach GC-bezogenen Laufzeitinterna:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "runtime.gc"

[No content provided in the INPUT section. Please supply the Markdown text to translate.]``` 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:~
Suche nach `fmt.` (Standardbibliothek Ausgabe):```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "fmt."

EINGABE:``` 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:~
Suche nach `sync.` (Nebenläufigkeits-Primitive):```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "sync."

Häufig gestellte Fragen

Allgemein

F: Wofür wird dieses Tool verwendet?
A: Dieses Tool wird zur Analyse des Netzwerkverkehrs und zur Erkennung potenzieller Sicherheitsbedrohungen verwendet.

F: Ist es Open-Source?
A: Ja, es ist vollständig Open-Source unter der MIT-Lizenz.``` 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:~
### JSON-Ausgabe (--json)

Maschinenlesbare Ausgabe für Skript- und Pipeline-Integration:```
$ python3 r2_gopclntab.py -f ./gotest_stripped --json

Bitte fügen Sie den zu übersetzenden Markdown-Inhalt ein.```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:~
### Auflistung der Quelldateien (--files)

Extrahiert alle im Binary eingebetteten Quelldateipfade:```
$ python3 r2_gopclntab.py -f ./gotest_stripped --files

EINGABE:``` 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:~
### Anwendungsmodus (--apply)

Schreibt alle wiederhergestellten Funktionsnamen in die radare2-Sitzung. Das Folgende zeigt einen Vorher/Nachher-Vergleich an der gestrippten Binärdatei.

**BEFORE** (r2 native analysis on stripped binary, no gopclntab parsing):```
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 fand 1913 Funktionen, benannte jedoch keine von ihnen (nur anonyme fcn.XXXXXXXX-Labels). Die Suche nach main.main oder main.fibonacci ergibt nichts.

Anwenden von gopclntab-Symbolen:``` [] 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:~
**NACH** (r2 session mit angewendeten gopclntab Symbolen):```
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

Die Disassemblierung bei main.main zeigt jetzt den wiederhergestellten Namen und den Quellort an:``` ;-- 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:~
Disassemblierung bei `main.fibonacci` zeigt jetzt den wiederhergestellten Namen und die Quellposition:```
            ;-- 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

Das Suchen nach Namen funktioniert jetzt in der r2-Sitzung:``` go.main.main resolves to: 0x1000a0c20 go.main.fibonacci resolves to: 0x1000a0bb0

root@kitploit:~
---

## Zusammenfassung der Ergebnisse: Mach-O (gestrippte Test-Binärdatei)

| Metrik | r2 nativ (gestrippt) | Nach r2_gopclntab.py |
|---|---|---|
| Gefundene Funktionen | 1913 (anonyme `fcn.XXXX`-Bezeichnungen) | 2030 (vollständige, paketqualifizierte Go-Namen) |
| Identifizierte Benutzerfunktionen | 0 | `main.main`, `main.fibonacci` mit Quelle + Zeile |
| Wiederhergestellte Quelldateien | 0 | 261 (vollständige absolute Pfade) |
| Benannte Symbole | Nur C-Import-Stubs (`sym.imp.mmap`, usw.) | Jede Go-Funktion gekennzeichnet (`go.main.main`, `go.runtime.gcStart`, usw.) |
| Quellkommentare | Keine | Inline `src: /tmp/gotest/main.go:20` in der Disassembly |
| Nach Name navigierbar | Nein | Ja (`s go.main.main`, `afl~runtime.gc`) |

---

## PE-Test: Greenblood, eine Go-Ransomware-Binärdatei

Der Parser wurde an einer echten PE-Binärdatei getestet, Greenblood (`greenblood_1`), einer Go-Ransomware-Probe, die als PE32+ x86-64 Windows-Executable kompiliert wurde. PE-Binärdateien haben keinen dedizierten `.gopclntab`-Abschnitt, daher wird hier der Magic-Byte-Scanning-Fallback-Pfad getestet.

### Erkennung und Header```
$ python3 r2_gopclntab.py -f ./greenblood_1 -v

EINGABE:``` [] 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:~
Der Scanner fand das gopclntab im Abschnitt `.rdata` bei `0x568C00`.
Da es sich um eine standardmäßige PE (nicht PIE) handelt, ist `textStart` `0x401000` (nicht Null),
daher wird der Header-Wert direkt für die Adressberechnung verwendet.

| Field | Value |
|---|---|
| Format | PE32+ x86-64 |
| gopclntab location | `.rdata` at `0x568C00` (found by magic scan) |
| Magic | `0xFFFFFFF1` (Go 1.20+) |
| Pointer size | 8 |
| Quantum (minLC) | 1 (x86) |
| textStart | `0x401000` (from header) |
| Functions recovered | 2596 |
| Source files | 345 |

### Wiederhergestellte Malware-Funktionen

Suche nach dem eigenen Code der Malware (`main.`):```
$ python3 r2_gopclntab.py -f ./greenblood_1 -n "main."

Bitte fügen Sie den zu übersetzenden Markdown-Text ein.``` 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:~
Alle 43 Benutzerfunktionen wurden aus einer einzelnen Quelldatei unter `/root/victims/ransom/daf/enc.go` wiederhergestellt. Die Funktionsnamen offenbaren sofort die Fähigkeiten der Ransomware: Schlüsselverwaltung, Maschinen-Fingerprinting, Dateiverschlüsselung mit Pfad-Traversal, Platzieren von Lösegeldforderungen, Deaktivierung der Wiederherstellung, Privilegienprüfung, Mutex-basierte Einzelinstanz-Durchsetzung, Laufwerksaufzählung und Selbstlöschung.

### Abhängigkeiten von Nicht-Standard-Bibliotheken

Extrahieren von Quelldateien, die nicht Teil der Go-Standardbibliothek sind:```
/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

Die einzige externe Abhängigkeit ist golang.org/x/[email protected] für Windows-spezifische Syscalls (Registry-Zugriff, Sicherheitstoken, DLL-Laden).

Krypto-Funktionen

Die Suche nach crypto offenbart 137 Krypto-bezogene Funktionen, darunter:``` $ python3 r2_gopclntab.py -f ./greenblood_1 -n "crypto"

root@kitploit:~
(empty response)```
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)

Das Kryptonutzungsprofil: AES (CBC- und CTR-Modi), SHA-256, SHA-512, HMAC, CSHAKE128 und DRBG (deterministischer Zufallsbitgenerator). Dies stimmt mit Ransomware überein, die pro Maschine generierte Verschlüsselungsschlüssel basierend auf einem Maschinenfingerabdruck erzeugt, Dateien mit AES-CTR verschlüsselt und HMAC für die Integrität verwendet.

Anwendungsmodus```

$ 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.

root@kitploit:~
Alle 2596 Funktionen erfolgreich angewendet, null übersprungen.

---

## Anwendungsfälle für Reverse Engineering

### 1. Triage und Identifikation

Sofort feststellen, ob eine Binärdatei Go ist, mit welcher Version sie erstellt wurde und welche Pakete sie verwendet. Die Ausgabe von `--files` zeigt die Go-Toolchain-Version (anhand von Dateipfaden wie `/usr/local/go/1.26.1/...`) und jeden Quellcodedateipfad, einschließlich Drittanbieter-Bibliotheken. Bei Malware wird dadurch sofort sichtbar, ob die Probe `crypto/tls`, `net/http`, `os/exec` oder andere interessante Pakete verwendet.

### 2. Symbolwiederherstellung bei gestrippten Binärdateien

Der zentrale Anwendungsfall. Go-Binärdateien, die mit `-ldflags="-s -w"` gestrippt wurden, verlieren ihre Symboltabelle, aber gopclntab bleibt erhalten. Dieses Tool stellt jeden Funktionsnamen wieder her und verwandelt anonyme `fcn.1000a0c20` zurück in `main.main`. Dies gilt für Malware-Beispiele, CTF-Herausforderungen, Produktionsbinärdateien und jede gestrippte Go-ausführbare Datei.

### 3. Navigation durch die Go-Laufzeitumgebung

Go-Binärdateien enthalten die gesamte Laufzeitumgebung (typischerweise 1500 bis 2000+ Funktionen). Ohne Namen ist die Laufzeitumgebung eine undurchdringliche Wand anonymer Funktionen. Mit Namen können Sie sofort `runtime.mallocgc`, `runtime.gopanic`, `runtime.newproc`, `runtime.gcStart` lokalisieren und verstehen, was die Binärdatei an jeder Aufrufstelle tut.

### 4. Trennung von Benutzercode und Laufzeitumgebung

Durch die Suche nach `main.` oder dem Paketpfad der Anwendung können Sie den Benutzercode von der Laufzeitumgebung isolieren. In den obigen Beispielen zeigt das Filtern nach `main.` sofort `main.main` und `main.fibonacci` unter insgesamt 2030 Funktionen. Sie können auch nach Drittanbieter-Paketnamen suchen (z.B. `-n "github.com/user/repo"`), um externe Abhängigkeiten zu identifizieren.

### 5. Kontext auf Quellcode-Ebene

Jede Funktion wird mit ihrem Quellcodedateipfad und der Startzeilennummer geliefert. Das bedeutet, dass Sie die Disassemblierung mit dem Quellcode der Go-Standardbibliothek (der offen ist) abgleichen können, selbst wenn Sie eine gestrippte Binärdatei analysieren. Zu wissen, dass eine Funktion in Zeile 733 von `runtime/mgc.go` beginnt, ermöglicht es Ihnen, den ursprünglichen Quellcode zusammen mit der Disassemblierung zu lesen.

### 6. Pipeline und Automatisierung

Der `--json`-Modus ermöglicht Skripting. Leiten Sie die Ausgabe an IDA/Ghidra-Importwerkzeuge, Diffing-Tools, YARA-Regelgeneratoren oder jede Analyse-Pipeline weiter. Zum Beispiel, um alle kryptobezogenen Funktionen zu extrahieren:```bash
python3 r2_gopclntab.py -f sample.exe --json \
  | jq '.functions[] | select(.name | contains("crypto"))'

7. Interaktiver radare2-Workflow

Nach --apply wird die gesamte r2-Sitzung über den Go-Namen navigierbar. Sie können zu Funktionen springen (s go.main.main), die Funktionsliste durchsuchen (afl~runtime.gc), Querverweise prüfen (axf go.main.fibonacci) und Quellortkommentare inline in der Disassemblierungsausgabe (pd) sehen. Dies verwandelt r2 von einem generischen Disassembler in eine Go-bewusste Analyseumgebung.


Unterstützte Plattformen und Go-Versionen

Binärformate

Für PE-Binärdateien und aggressiv gestrippte ELF/Mach-O-Binärdateien, denen der Abschnittsheader fehlt, greift das Tool auf das Scannen aller Abschnitte nach den 4-Byte-Magic-Bytes zurück, gefolgt von Validierungsbytes (pad=0, ptrSize in {4,8}, minLC in {1,2,4}).

Go-Versionen

Der Magic-Wert 0xFFFFFFF1 wird von Go 1.20 bis mindestens Go 1.26 verwendet.


Methodik

Strategie zur Abschnittslokalisierung

Der Parser verwendet einen zweiphasigen Ansatz, um die gopclntab-Daten zu finden:

Phase 1 (ELF/Mach-O): Fragt die radare2-Abschnittsliste ab (iSj) und sucht nach Abschnitten mit den Namen .gopclntab, .data.rel.ro.gopclntab oder __gopclntab.

Phase 2 (PE/Fallback): Wenn kein benannter Abschnitt gefunden wird, werden alle Abschnitte nach den 4-Byte-Magic-Bytes durchsucht. Jeder Kandidat wird validiert, indem überprüft wird, ob die Bytes 4-7 dem erwarteten Muster entsprechen: zwei Null-Pad-Bytes, eine gültige Zeigergröße (4 oder 8) und ein gültiges Instruktionsquantum (1, 2 oder 4). Dies eliminiert Fehlalarme durch zufällige Bytemuster.

textStart vs. .text-Abschnitt

In Go >= 1.18 werden Funktionseinstiegspunkte in der functab als relative Offsets gespeichert. Die Berechnung der absoluten virtuellen Adresse erfordert eine Basis:``` absolute_addr = base + entryoff

root@kitploit:~
Die Basis wird mit der folgenden Logik ermittelt:```
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

Der Fall textStart == 0 tritt in Go >= 1.22 für Mach-O- und PIE-Binärdateien auf. Wenn dies geschieht, sind die entryoff-Werte relativ zum Beginn des .text-Abschnitts, daher fragt der Parser r2 nach der virtuellen Adresse von .text und verwendet diese als Basis.

Dies wurde an einer Go 1.26 Mach-O arm64-Binärdatei verifiziert:

  • textStart im Header: 0x0
  • .text-Abschnitt vaddr: 0x100001000
  • functab[1].entryoff: 0x70
  • Berechnete Adresse: 0x100001000 + 0x70 = 0x100001070
  • Die native r2-Analyse bestätigte internal/abi.BoundsDecode bei 0x100001070

Versionsbewusstes Struktur-Parsing

Das Layout der _func-Struktur unterscheidet sich zwischen Go 1.18 und Go 1.20+. Die einzige Änderung ist die Einfügung eines 4-Byte-startLine-Felds bei Offset 36 in Go 1.20+, wodurch funcID, flag und nfuncdata um 4 Byte verschoben werden:

Der Parser prüft die Magische Zahl, um zu bestimmen, welches Layout verwendet werden soll.

PC-Daten-Dekodierung

Quelldatei-Indizes und Zeilennummern werden als kompakte „PC-Daten-Programme“ im pctab-Bereich gespeichert. Jedes Programm kodiert eine Sequenz von (value_delta, pc_delta)-Paaren unter Verwendung von Ganzzahlen variabler Länge mit Zig-Zag-Kodierung für vorzeichenbehaftete Werte. Der Parser dekodiert diese, um Folgendes aufzulösen:

  • Quelldatei: _func.pcfile -> pctab-Programm -> Dateiindex -> cutab -> filetab -> Dateipfad-Zeichenkette
  • Zeilennummer: _func.pcln -> pctab-Programm -> Zeilennummer (zuzüglich startLine-Offset für Go 1.20+)

Einschränkungen

  1. Inline-Funktionen erscheinen nicht in der Funktionstabelle der obersten Ebene. Sie sind in FUNCDATA_InlTree- / PCDATA_InlTreeIndex-Strukturen kodiert, die dieses Tool derzeit nicht dekodiert. Im Test-Binärprogramm wurden main.helloWorld und main.addNumbers vom Compiler inline gesetzt und erscheinen daher nicht in der Ausgabe.

  2. Go 1.2-Unterstützung erfolgt nach besten Kräften. Das Go 1.2-Format unterscheidet sich erheblich (kein separates funcnametab, kein cutab, absolute Zeiger in functab) und wird in der Praxis selten angetroffen.

  3. Big-Endian-Architekturen werden prinzipiell unterstützt (die Endianness wird aus den radare2-Binärinformationen erkannt und für alle Struktur-Lesevorgänge verwendet), wurden aber nicht getestet.

  4. Der --apply-Modus erstellt Funktions-Stubs mit af+, die mit der eigenen Autoanalyse von r2 in Konflikt geraten können. Die Ausführung in einer sauberen Sitzung (vor oder anstelle von aaa) kann in manchen Fällen bessere Ergebnisse liefern.


Zusätzliche Dokumentation

Detaillierte technische Dokumentation ist im Verzeichnis documentation/ verfügbar:

  • DOCUMENTATION.md – Vollständige Benutzerdokumentation mit allen Verwendungsmodi, Ausgabeformaten und Flag-Kombinationen.
  • METHODOLOGY.md – Entwurfsentscheidungen und Algorithmen: textStart- vs. .text-Auflösung, versionsbewusstes Parsen, PE-Scanstrategie, PC-Daten-Dekodierung, r2-Integrationsdetails.
  • GOPCLNTAB_FORMAT.md – Das gopclntab-Binärformat über Go-Versionen hinweg: Byte-Level-Strukturlayouts, Speichermodell, Offset-Ketten, Varint-Kodierung, Zusammenfassung der Versionsunterschiede.

Referenzen

  • Go-Laufzeitquellcode (pcHeader): go1.20.6/src/runtime/symtab.go#L414
  • Go-Linker (schreibt das Format): go1.20.6/src/cmd/link/internal/ld/pcln.go
  • Mandiant – Golang Internals Symbol Recovery: mandiant.com/resources/blog/golang-internals-symbol-recovery
  • Go 1.2-Symboltabellen-Entwurfsdokument: docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o
Tool herunterladen
FlagBeschreibung
-l, --listJede wiederhergestellte Funktion mit ihrer Adresse ausgeben.
-n NAME, --funcname NAMENur Funktionen ausgeben, deren Name NAME enthält (Teilstring-Übereinstimmung). Wenn eine exakte Übereinstimmung existiert, wird ihre Adresse separat ausgegeben.
-v, --verboseFortschrittsmeldungen, geparste Header-Felder und interne Offsets ausgeben.
--applyWiederhergestellte Funktionsnamen in die radare2-Sitzung als Funktionsdefinitionen (af+), Flags im go.-Flagspace und Kommentare mit dem ursprünglichen Go-Namen und Quellort schreiben.
--jsonDen Header und die vollständige Funktionsliste als JSON nach stdout ausgeben.
--filesDie Liste der aus der Dateitabelle extrahierten Quellcodedateipfade ausgeben.
-h, --helpHilfemeldung anzeigen.
FormatMethode zur AbschnittserkennungGetestet
ELF (Linux)Abschnittsname .gopclntab oder .data.rel.ro.gopclntabJa
Mach-O (macOS)Abschnittsname __gopclntab (im Segment __TEXT)Ja
PE (Windows)Magic-Byte-Scan (kein dedizierter Abschnitt)Ja (getestet auf Greenblood, einem Go-Ransomware-PE64)
MagieGo-VersiontextStart im HeaderTyp von functab.entryFeld startLineStatus
0xFFFFFFFB1.2Neinuintptr (absolut)NeinUnterstützt
0xFFFFFFFA1.16Neinuintptr (absolut)NeinUnterstützt
0xFFFFFFF01.18 - 1.19Jauint32 (relativ)NeinUnterstützt
0xFFFFFFF11.20+Ja (kann 0 sein)uint32 (relativ)JaUnterstützt
FeldGo 1.18-OffsetGo 1.20+-Offset
entryOff00
nameOff44
args88
cuOffset3232
startLine(fehlt)36
funcID3640
flag3741
nfuncdata3943