
Un script de radare2 para analizar la gopclntab con el fin de facilitar la ingeniería inversa de binarios Go.
Nota: Esta funcionalidad ha sido implementada directamente en el núcleo de radare2 como plugin de análisis gopc
Un analizador de gopclntab para Go basado en radare2 que recupera
símbolos de funciones de binarios Go, incluyendo aquellos completamente despojados. Soporta binarios ELF,
Mach-O y PE en versiones de Go 1.2, 1.16, 1.18 y 1.20+.
Cada binario Go 1.2+ incorpora una región de datos llamada gopclntab (Program Counter Line
Table) que el runtime de Go utiliza para trazas de pila, mensajes de pánico, recolección
de basura y soporte al depurador. Es una de las fuentes más valiosas de información de
símbolos en binarios Go.
r2gopclntabParser lee esta región a través de radare2, analiza las estructuras específicas de la versión, y ya sea imprime la lista de funciones recuperada (con direcciones, archivos fuente y números de línea) o aplica los nombres recuperados de vuelta a la sesión abierta de radare2 como definiciones de función, flags y comentarios.
| Dependencia | Versión mínima |
|---|---|
| Python 3 | 3.8+ |
| radare2 | 5.0+ (probado en 6.0.9) |
| r2pipe | cualquiera |
No se requieren otros paquetes de Python. El script usa solo la biblioteca
estándar (struct, json, argparse, os, sys) más r2pipe.
python3 r2_gopclntab.py -f ./mybinary -l
python3 r2_gopclntab.py -f ./mybinary -n main.main
python3 r2_gopclntab.py -f ./mybinary -v -l
python3 r2_gopclntab.py -f ./mybinary --apply
python3 r2_gopclntab.py -f ./mybinary --json
#!pipe python3 r2_gopclntab.py --r2pipe --apply -v
---
## Referencia de CLI```
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
[--apply] [--json] [--files] [--r2pipe]
| Indicador | Descripción |
|---|---|
-f ARCHIVO, --file ARCHIVO | Ruta al binario Go a analizar. El script lanza su propia instancia de r2. |
--r2pipe | Conectarse a una sesión de r2 ya en ejecución (para usar dentro de la consola de r2). |
| Indicador | Descripción |
|---|---|
-l, --list | Imprime cada función recuperada con su dirección. |
-n NOMBRE, --funcname NOMBRE | Imprime solo las funciones cuyo nombre contenga NOMBRE (coincidencia de subcadena). Si existe una coincidencia exacta, su dirección se imprime por separado. |
-v, --verbose | Imprime mensajes de progreso, campos de cabecera analizados y desplazamientos internos. |
--apply | Escribe los nombres de funciones recuperados en la sesión de radare2 como definiciones de función (af+), banderas en el espacio de banderas go. y comentarios con el nombre Go original y la ubicación del código fuente. |
--json | Genera la cabecera y la lista completa de funciones como JSON a stdout. |
--files | Imprime la lista de rutas de archivos fuente extraídas de la tabla de archivos. |
-h, --help | Muestra el mensaje de ayuda. |
Los indicadores pueden combinarse libremente. Cuando no se proporciona ningún indicador de salida, el comportamiento predeterminado es imprimir la cabecera y la lista completa de funciones.
Todos los ejemplos a continuación se ejecutaron contra un binario Go 1.26 Mach-O arm64 sin símbolos (compilado con -ldflags="-s -w"). El programa de prueba define main.main, main.fibonacci, main.helloWorld y main.addNumbers. El compilador insertó internamente helloWorld y addNumbers, por lo que no aparecen en gopclntab.
Ejecutar sin indicadores (o solo con -f) imprime la cabecera analizada seguida de la tabla completa de funciones:```
$ python3 r2_gopclntab.py -f ./gotest_stripped
(no content provided)```
============================================================
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