Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
r2gopclntabParser — Скрипт для radare2, который парсит gopclntab для облегчения реверс-инжиниринга Go-бинарных файлов. | Kitploit
Инструменты/GitHubGitHub/asherdll/r2gopclntabparser
Статический анализОбратная инженерияОтладчикиФорензикаАнализ вредоносных программАнализ Бинарных Файлов
GitHubasherdll/r2gopclntabparser

r2gopclntabParser

Скрипт для radare2, который парсит gopclntab для облегчения реверс-инжиниринга Go-бинарных файлов.

Репозиторий
174 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

r2gopclntabParser

Примечание: Эта функция была напрямую реализована в ядре radare2 как плагин анализа gopc

Парсер gopclntab на основе radare2 для восстановления символов функций из Go-бинарников, включая полностью лишённые символьной информации. Поддерживает ELF, Mach-O и PE бинарники для версий Go 1.2, 1.16, 1.18 и 1.20+.

Каждый Go-бинарник версии 1.2+ содержит область данных, называемую gopclntab (таблица строк программы и счётчика команд), которую рантайм Go использует для стековых трасс, сообщений паники, сборки мусора и поддержки отладчика. Это один из наиболее ценных источников информации о символах в Go-бинарниках.

r2gopclntabParser считывает эту область через radare2, анализирует версионно-зависимые структуры и либо выводит восстановленный список функций (с адресами, исходными файлами и номерами строк), либо применяет восстановленные имена обратно в открытую сессию radare2 в качестве определений функций, флагов и комментариев.


Содержание

  • Предварительные требования
  • Быстрый старт
  • Справочник по CLI
  • Режимы вывода и примеры
    • Режим по умолчанию (заголовок + список функций)
    • Подробный режим (-v)
    • Режим поиска (-n)
    • Вывод в JSON (--json)
    • Список исходных файлов (--files)
    • Режим применения (--apply)
  • Сводка результатов: Mach-O (тестовый бинарник без символов)
  • Тест PE: Greenblood, бинарник-вымогатель на Go
  • Сценарии использования для обратной разработки
  • Поддерживаемые платформы и версии Go
  • Методология
    • Стратегия поиска секций
    • textStart vs .text секция
    • Версионно-зависимый разбор структур
    • Декодирование данных PC
  • Ограничения
  • Дополнительная документация
  • Ссылки

Предварительные требования

ЗависимостьМинимальная версия
Python 33.8+
radare25.0+ (протестировано на 6.0.9)
r2pipeлюбая

Других пакетов Python не требуется. Скрипт использует только стандартную библиотеку (struct, json, argparse, os, sys) и r2pipe.


Быстрый старт```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```
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
                       [--apply] [--json] [--files] [--r2pipe]

Required (one of)

FlagDescription
-f FILE, --file FILEПуть к Go-бинарному файлу для анализа. Скрипт запускает собственный экземпляр r2.
--r2pipeПодключиться к уже запущенной сессии r2 (для использования внутри консоли r2).

Optional

Флаги можно свободно комбинировать. Если не указан флаг вывода, поведение по умолчанию — вывод заголовка и полного списка функций.


Output Modes and Examples

Все примеры ниже были запущены на обезображенном бинарном файле Go 1.26 Mach-O arm64 (собранном с -ldflags="-s -w"). Тестовая программа определяет main.main, main.fibonacci, main.helloWorld и main.addNumbers. Компилятор встроил helloWorld и addNumbers, поэтому они не появляются в gopclntab.

Default Mode (Header + Function List)

Запуск без флагов (или только с -f) выводит разобранный заголовок, а затем полную таблицу функций:``` $ python3 r2_gopclntab.py -f ./gotest_stripped

root@kitploit:~
[Вики](https://github.com/ainrm/OffensivePipelineCD/wiki) • [Установка](https://github.com/ainrm/OffensivePipelineCD/wiki/Installation) • [Загрузки](https://github.com/ainrm/OffensivePipelineCD/wiki/Downloads) • [Плагины](https://github.com/ainrm/OffensivePipelineCD/wiki/Development)```
============================================================
  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

Подробный режим (-v)

Добавляет ход сканирования разделов, детали разрешения textStart и информацию о внутренних смещениях:``` $ python3 r2_gopclntab.py -f ./gotest_stripped -v

root@kitploit:~
Please provide the Markdown content to translate.```
[*] 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+
  ...

Режим поиска (-n)

Фильтрует список функций по совпадению подстроки. Если найдено точное совпадение, его адрес выводится отдельно.

Поиск подстроки для всех функций, содержащих main.:``` $ python3 r2_gopclntab.py -f ./gotest_stripped -n "main."

root@kitploit:~
root@kitploit:~
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)
```
Точный поиск совпадений:```
$ 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
```
Поиск внутренних механизмов среды выполнения, связанных с GC:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "runtime.gc"
```
Все авторские права на этот инструмент принадлежат оригинальному автору [John Hammond](https://github.com/JohnHammond), который создал `msf-vs-mimikatz`. В этом репозитории мы улучшили исходную концепцию, добавив больше сигнатур антивируса из Microsoft Defender, а также новые типы полезной нагрузки и в целом лучшую среду разработки с `Python.````
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)
```
Поиск `fmt.` (печать из стандартной библиотеки):```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "fmt."
```
Помните, что вы должны ввести свои учетные данные в **accounts.json**. Мы также включили `accounts_example.json` в качестве примера настройки файла. Обратите внимание, что при настройке учетных записей для Microsoft Teams GraphRunner поддерживает отправку сообщений через Teams, а также чтение сообщений, но поддерживается только делегированная аутентификация.

Разрабатываются новые модули как для Teams, так и для Azure, и ожидается, что инструмент будет расти.

### Использование по умолчанию

Во-первых, если вы еще этого не сделали, вам потребуется установить **Microsoft Graph PowerShell SDK**, инструкции по установке можно найти [здесь](https://learn.microsoft.com/en-us/powershell/microsoftgraph/installation?view=graph-powershell-1.0).

Войдите в Graph Runner, выполнив команду `Connect-Graph` и введя свои учетные данные. Если вы хотите войти с помощью приложения или субъекта-службы (Service Principal), используйте модуль `Connect-ClientSecret`.

Модули разделены на две категории: `Azure` и `MicrosoftTeams`. Импортируйте модули в зависимости от ваших потребностей:```
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)
...
```
Поиск `sync.` (примитивы синхронизации):```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "sync."
```
MD5, SHA1, SHA256.
- Время автоматически генерируется **`pipal`** в формате `2020-05-21 18:33:59`.

### Вывод

Результаты pipal будут записаны в каталог `./pipal_output` в файл `HASH.output`.

Для быстрого просмотра результатов через `les`, `bat` (или `cat`):

```bash
les ./pipal_output/*.output
```

```bash
bat ./pipal_output/*.output
```

> **Примечание**: При повторном запуске с тем же файлом слов в качестве входных данных будет запрошено подтверждение на перезапись результатов pipal `[y/n]`. Если вы откажетесь от перезаписи, можно продолжить использовать предыдущие результаты.

> **Совет**: Чтобы увидеть результаты pipal, не дожидаясь завершения hashcat, вы можете запустить `pipal` непосредственно на potfile, используя:
> ```bash
> pipal potfile [другие параметры]
> ```
> Этот подход удобен, если вам нужен только статистический анализ без накладных расходов на вычисления hashcat.```
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)
...
```
### Вывод в формате JSON (--json)

Машиночитаемый вывод для интеграции со скриптами и конвейерами:```
$ python3 r2_gopclntab.py -f ./gotest_stripped --json
```
Please provide the Markdown content to translate.```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
}
```
### Список исходных файлов (--files)

Извлекает все пути к исходным файлам, внедрённые в бинарный файл:```
$ python3 r2_gopclntab.py -f ./gotest_stripped --files
```
как строки (по умолчанию), или как обобщённые примитивные **инструкции**, а также блоки (в зависимости от параметров в `parser.cpp` и предпочтений инструкций, жестко закодированных для других бэкендов в `asm.cpp`). Сохраните созданный файл как `asm.bin` на диске в текущей директории.```
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
  <autogenerated>
  /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
```
### Режим применения (--apply)

Записывает все восстановленные имена функций в сессию radare2. Ниже показано сравнение до/после для бинарного файла с удалёнными символами.

**ДО** (родной анализ r2 бинарного файла с удалёнными символами, без парсинга 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 нашёл 1913 функций, но не назвал ни одну из них (только анонимные метки `fcn.XXXXXXXX`). Поиск `main.main` или `main.fibonacci` ничего не возвращает.

**Применяя символы 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)
```
**ПОСЛЕ** (сессия r2 с примененными символами gopclntab):```
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
```
Дизассемблирование в `main.main` теперь показывает восстановленное имя и исходное местоположение:```
            ;-- 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
```
Дизассемблирование в `main.fibonacci` теперь показывает восстановленное имя и исходное расположение:```
            ;-- 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
```
Поиск по имени теперь работает в сессии r2:```
go.main.main resolves to: 0x1000a0c20
go.main.fibonacci resolves to: 0x1000a0bb0
```
---

## Сводка результатов: Mach-O (очищенный тестовый бинарник)

| Метрика | r2 Native (без символов) | После r2_gopclntab.py |
|---|---|---|
| Найдено функций | 1913 (анонимные метки `fcn.XXXX`) | 2030 (полные имена с указанием пакета Go) |
| Идентифицировано пользовательских функций | 0 | `main.main`, `main.fibonacci` с исходным кодом и строкой |
| Восстановлено исходных файлов | 0 | 261 (полные абсолютные пути) |
| Именованные символы | Только заглушки импорта C (`sym.imp.mmap` и т.д.) | Каждая функция Go помечена (`go.main.main`, `go.runtime.gcStart` и т.д.) |
| Комментарии к исходному коду | Нет | Встроенный `src: /tmp/gotest/main.go:20` в дизассемблере |
| Навигация по имени | Нет | Да (`s go.main.main`, `afl~runtime.gc`) |

---

## PE-тест: Greenblood, бинарник программы-вымогателя на Go

Парсер был протестирован на реальном PE-бинарнике Greenblood (`greenblood_1`), образце программы-вымогателя на Go, скомпилированном как PE32+ x86-64 исполняемый файл Windows. PE-бинарники не имеют выделенного раздела `.gopclntab`, поэтому здесь задействуется резервный путь сканирования магических байтов.

### Обнаружение и заголовок```
$ python3 r2_gopclntab.py -f ./greenblood_1 -v
```
Please provide the Markdown content to translate.```
[*] 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
```
Сканер обнаружил gopclntab внутри секции `.rdata` по адресу `0x568C00`.
Поскольку это стандартный PE (не PIE), `textStart` равен `0x401000` (ненулевое значение),
поэтому значение заголовка используется непосредственно для вычисления адреса.

| Поле | Значение |
|---|---|
| Формат | PE32+ x86-64 |
| Расположение gopclntab | `.rdata` по адресу `0x568C00` (найдено магическим сканированием) |
| Магическое число | `0xFFFFFFF1` (Go 1.20+) |
| Размер указателя | 8 |
| Квант (minLC) | 1 (x86) |
| textStart | `0x401000` (из заголовка) |
| Восстановлено функций | 2596 |
| Исходные файлы | 345 |

### Восстановленные функции вредоносного ПО

Поиск собственного кода вредоносного ПО (`main.`):```
$ python3 r2_gopclntab.py -f ./greenblood_1 -n "main."
```
## Основные функции

Хуки позволяют подключаться к различным событиям жизненного цикла, а асинхронные хуки — к асинхронным событиям.```
ADDRESS       FUNCTION NAME
----------------------------------------------------------------------
0x4D91E0      main.init  (<autogenerated>: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)
```
Все 43 пользовательские функции были восстановлены из одного исходного файла по адресу
`/root/victims/ransom/daf/enc.go`. Названия функций сразу раскрывают
возможности вымогателя: управление ключами, снятие отпечатков машины, шифрование
файлов с обходом каталогов, размещение записки о выкупе, отключение восстановления,
проверка привилегий, обеспечение единственного экземпляра на основе мьютекса, перечисление дисков
и самоудаление.

### Нестандартные зависимости библиотек

Извлечение исходных файлов, не входящих в стандартную библиотеку 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
```
Единственная внешняя зависимость — `golang.org/x/[email protected]` для системных вызовов, специфичных для Windows (доступ к реестру, маркеры безопасности, загрузка DLL).

### Криптографические функции

Поиск по `crypto` выявляет 137 функций, связанных с криптографией, включая:```
$ python3 r2_gopclntab.py -f ./greenblood_1 -n "crypto"
```
| Tool Name | Description | Link |
|-----------|-------------|------|
| Loki | Простой сканер IOC и реагирования на инциденты | [![GitHub stars](https://img.shields.io/github/stars/Neo23x0/Loki?style=social)](https://github.com/Neo23x0/Loki) |
| Local Exploit Suggester | Инструмент аудита повышения привилегий в Linux | [![GitHub stars](https://img.shields.io/github/stars/AlessandroZ/BeRoot?style=social)](https://github.com/AlessandroZ/BeRoot) |
| Lorg | Инструмент для расширенного логирования HTTP-ответов | [![GitHub stars](https://img.shields.io/github/stars/jensvoid/lorg?style=social)](https://github.com/jensvoid/lorg) |
| LyncSniper | Инструмент для тестирования на проникновение Lync/Skype for Business | [![GitHub stars](https://img.shields.io/github/stars/nyxgeek/lync-sniper?style=social)](https://github.com/nyxgeek/lync-sniper) |
| Lynis | Инструмент аудита безопасности для Linux, macOS и UNIX-систем | [![GitHub stars](https://img.shields.io/github/stars/CISOfy/lynis?style=social)](https://github.com/CISOfy/lynis) |
| Machinae | Инструмент для сбора разведданных из публичных сайтов/API | [![GitHub stars](https://img.shields.io/github/stars/HurricaneLabs/machinae?style=social)](https://github.com/HurricaneLabs/machinae) |
| MacQRL | Фреймворк для быстрого реагирования macOS и Linux / живого реагирования | [![GitHub stars](https://img.shields.io/github/stars/themitten/macqrl?style=social)](https://github.com/themitten/macqrl) |
| MailSniper | Инструмент для поиска по электронной почте в среде Microsoft Exchange по заданным терминам | [![GitHub stars](https://img.shields.io/github/stars/dafthack/MailSniper?style=social)](https://github.com/dafthack/MailSniper) |
| malboxes | Создаёт виртуальные машины Windows для анализа вредоносного ПО | [![GitHub stars](https://img.shields.io/github/stars/beahive/malboxes?style=social)](https://github.com/beahive/malboxes) |
| Maligner | Инструмент для обфускации вредоносного ПО Android | [![GitHub stars](https://img.shields.io/github/stars/geekspeed/maligner?style=social)](https://github.com/geekspeed/maligner) |```
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)
```
Профиль использования криптографии: AES (режимы CBC и CTR), SHA-256, SHA-512, HMAC, CSHAKE128 и DRBG (детерминированный генератор случайных битов). Это согласуется с программами-вымогателями, которые генерируют уникальные для каждого устройства ключи шифрования на основе отпечатка устройства, шифруют файлы с помощью AES-CTR и используют HMAC для целостности.

### Режим применения```
$ 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.
```
Все 2596 функций успешно применены, ни одна не пропущена.

---

## Сценарии использования для обратной разработки

### 1. Триаж и идентификация

Мгновенно определите, является ли бинарный файл Go-приложением, с какой версией он был собран и какие пакеты использует. Вывод с флагом `--files` показывает версию инструментария Go (из путей вида `/usr/local/go/1.26.1/...`) и все пути исходных файлов, включая сторонние библиотеки. Для вредоносного ПО это сразу показывает, использует ли образец `crypto/tls`, `net/http`, `os/exec` или другие интересующие пакеты.

### 2. Восстановление символов в обрезанных бинарных файлах

Основной сценарий использования. Go-бинарные файлы, обрезанные с помощью `-ldflags="-s -w"`, теряют таблицу символов, но `gopclntab` сохраняется. Этот инструмент восстанавливает имена всех функций, превращая анонимные `fcn.1000a0c20` обратно в `main.main`. Это применимо к образцам вредоносного ПО, задачам CTF, промышленным бинарным файлам и любым обрезанным исполняемым файлам Go.

### 3. Навигация по среде выполнения Go

Go-бинарные файлы включают в себя всю среду выполнения (обычно от 1500 до 2000+ функций). Без имён среда выполнения — это непроницаемая стена анонимных функций. С именами вы можете мгновенно найти `runtime.mallocgc`, `runtime.gopanic`, `runtime.newproc`, `runtime.gcStart` и понять, что делает бинарный файл в каждой точке вызова.

### 4. Отделение пользовательского кода от среды выполнения

Поиск по `main.` или пути пакета приложения позволяет изолировать только пользовательский код от среды выполнения. В приведённых выше примерах фильтрация по `main.` сразу выявляет `main.main` и `main.fibonacci` среди 2030 функций. Также можно искать по именам сторонних пакетов (например, `-n "github.com/user/repo"`), чтобы определить внешние зависимости.

### 5. Контекст на уровне исходного кода

Каждая функция сопровождается путём к исходному файлу и номером начальной строки. Это означает, что вы можете сопоставить дизассемблированный код с исходным кодом стандартной библиотеки Go (которая открыта), даже при анализе обрезанного бинарного файла. Знание того, что функция начинается со строки 733 в `runtime/mgc.go`, позволяет читать оригинальный исходный код вместе с дизассемблированным.

### 6. Конвейеры и автоматизация

Режим `--json` позволяет создавать сценарии. Передавайте вывод в импортёры IDA/Ghidra, инструменты сравнения, генераторы правил YARA или любой аналитический конвейер. Например, для извлечения всех криптографических функций:```bash
python3 r2_gopclntab.py -f sample.exe --json \
  | jq '.functions[] | select(.name | contains("crypto"))'
```
### 7. Интерактивный рабочий процесс radare2

После `--apply` вся сессия r2 становится навигационной по именам Go. Вы можете
переходить к функциям (`s go.main.main`), искать в списке функций
(`afl~runtime.gc`), просматривать перекрёстные ссылки (`axf go.main.fibonacci`) и
видеть комментарии с расположением исходного кода прямо в выводе дизассемблера (`pd`). Это
превращает r2 из обычного дизассемблера в среду анализа, понимающую Go.

---

## Поддерживаемые платформы и версии Go

### Бинарные форматы

| Формат | Метод обнаружения секции | Протестировано |
|---|---|---|
| ELF (Linux) | Имя секции `.gopclntab` или `.data.rel.ro.gopclntab` | Да |
| Mach-O (macOS) | Имя секции `__gopclntab` (внутри сегмента `__TEXT`) | Да |
| PE (Windows) | Сканирование по магическим байтам (нет выделенной секции) | Да (протестировано на Greenblood, Go-шифровальщик PE64) |

Для PE-бинарников и агрессивно обрезанных ELF/Mach-O, у которых отсутствует
заголовок секции, инструмент переключается на сканирование всех секций на наличие 4-байтовой
магии с последующими проверочными байтами (pad=0, ptrSize в {4,8}, minLC в
{1,2,4}).

### Версии Go

| Магия | Версия Go | `textStart` в заголовке | Тип `functab.entry` | Поле `startLine` | Статус |
|---|---|---|---|---|---|
| `0xFFFFFFFB` | 1.2 | Нет | `uintptr` (абсолютный) | Нет | Поддерживается |
| `0xFFFFFFFA` | 1.16 | Нет | `uintptr` (абсолютный) | Нет | Поддерживается |
| `0xFFFFFFF0` | 1.18 – 1.19 | Да | `uint32` (относительный) | Нет | Поддерживается |
| `0xFFFFFFF1` | 1.20+ | Да (может быть 0) | `uint32` (относительный) | Да | Поддерживается |

Магия `0xFFFFFFF1` используется начиная с Go 1.20 и как минимум до Go 1.26.

---

## Методология

### Стратегия поиска секции

Парсер использует двухфазный подход для поиска данных gopclntab:

**Фаза 1 (ELF/Mach-O):** Запросить список секций radare2 (`iSj`) и найти
секции с именами `.gopclntab`, `.data.rel.ro.gopclntab` или `__gopclntab`.

**Фаза 2 (PE/резервный):** Если именованная секция не найдена, просканировать все секции
на наличие 4-байтовых магических байтов. Каждый кандидат проверяется по тому, что
байты 4-7 соответствуют ожидаемому шаблону: два нулевых байта заполнения, допустимый размер
указателя (4 или 8) и допустимый квант инструкции (1, 2 или 4). Это
исключает ложные срабатывания из-за случайных совпадений байтов.

### textStart в сравнении с секцией .text

В Go >= 1.18 точки входа функций в functab хранятся как относительные
смещения. Для вычисления абсолютного виртуального адреса требуется база:```
absolute_addr = base + entryoff
```
База разрешается следующей логикой:```
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
```
Случай `textStart == 0` возникает в Go >= 1.22 для бинарных файлов Mach-O и PIE.  
В этом случае значения `entryoff` задаются относительно начала секции `.text`, поэтому анализатор запрашивает у r2 виртуальный адрес `.text` и использует его в качестве базы.

Это было проверено на бинарном файле Go 1.26 Mach-O arm64:  
- `textStart` в заголовке: `0x0`  
- `.text` vaddr секции: `0x100001000`  
- `functab[1].entryoff`: `0x70`  
- Вычисленный адрес: `0x100001000 + 0x70 = 0x100001070`  
- Нативный анализ r2 подтвердил `internal/abi.BoundsDecode` по адресу `0x100001070`

### Разбор структур с учетом версии

Макет структуры `_func` различается между Go 1.18 и Go 1.20+. Единственное изменение – вставка 4-байтового поля `startLine` со смещением 36 в Go 1.20+, что сдвигает `funcID`, `flag` и `nfuncdata` на 4 байта:

| Поле | Смещение в Go 1.18 | Смещение в Go 1.20+ |
|---|---|---|
| `entryOff` | 0 | 0 |
| `nameOff` | 4 | 4 |
| `args` | 8 | 8 |
| `cuOffset` | 32 | 32 |
| `startLine` | (отсутствует) | 36 |
| `funcID` | 36 | 40 |
| `flag` | 37 | 41 |
| `nfuncdata` | 39 | 43 |

Анализатор проверяет магическое число, чтобы определить, какой макет использовать.

### Декодирование PC-данных

Индексы исходных файлов и номера строк хранятся в виде компактных "PC-программ" в области pctab. Каждая программа кодирует последовательность пар `(value_delta, pc_delta)` с использованием целых чисел переменной длины и зигзагообразного кодирования для знаковых значений. Анализатор декодирует их для определения:

- Исходный файл: `_func.pcfile` -> программа pctab -> индекс файла -> cutab -> filetab -> строка пути к файлу
- Номер строки: `_func.pcln` -> программа pctab -> номер строки (плюс смещение `startLine` для Go 1.20+)

---

## Ограничения

1. **Встраиваемые (inlined) функции** не отображаются в таблице функций верхнего уровня. Они закодированы в структурах `FUNCDATA_InlTree` / `PCDATA_InlTreeIndex`, которые данный инструмент пока не декодирует. В тестовом бинарном файле `main.helloWorld` и `main.addNumbers` были встроены компилятором и поэтому не отображаются в выводе.

2. **Поддержка Go 1.2** реализована по мере возможностей. Формат Go 1.2 существенно отличается (нет отдельной funcnametab, нет cutab, абсолютные указатели в functab) и на практике встречается редко.

3. **Архитектуры с big-endian** поддерживаются в принципе (порядок байтов определяется из информации radare2 и используется для всех чтений структур), но не были протестированы.

4. Режим `--apply` создаёт заглушки функций с помощью `af+`, что может конфликтовать с автоанализом r2. Запуск на чистом сеансе (до `aaa` или вместо него) может дать лучшие результаты в некоторых случаях.

---

## Дополнительная документация

Подробная техническая документация доступна в каталоге `documentation/`:

- [DOCUMENTATION.md](https://github.com/asherdll/r2gopclntabparser/blob/HEAD/documentation/DOCUMENTATION.md) – Полная пользовательская документация со всеми режимами использования, форматами вывода и комбинациями флагов.
- [METHODOLOGY.md](https://github.com/asherdll/r2gopclntabparser/blob/HEAD/documentation/METHODOLOGY.md) – Проектные решения и алгоритмы: разрешение textStart vs .text, разбор с учётом версии, стратегия сканирования PE, декодирование PC-данных, детали интеграции с r2.
- [GOPCLNTAB_FORMAT.md](https://github.com/asherdll/r2gopclntabparser/blob/HEAD/documentation/GOPCLNTAB_FORMAT.md) – Двоичный формат gopclntab в разных версиях Go: побайтовые макеты структур, модель памяти, цепочки смещений, кодирование varint, сводка различий по версиям.

---

## Ссылки

- Исходный код 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)
- Линковщик Go (записывает формат): [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: [mandiant.com/resources/blog/golang-internals-symbol-recovery](https://www.mandiant.com/resources/blog/golang-internals-symbol-recovery)
- Дизайн-документ таблицы символов Go 1.2: [docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o](https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o/pub)
Скачать инструмент
FlagDescription
-l, --listВывести каждую восстановленную функцию с её адресом.
-n NAME, --funcname NAMEВывести только функции, имя которых содержит NAME (поиск по подстроке). Если существует точное совпадение, его адрес выводится отдельно.
-v, --verboseВыводить сообщения о ходе работы, разобранные поля заголовка и внутренние смещения.
--applyЗаписать восстановленные имена функций в сессию radare2 как определения функций (af+), флаги в пространстве флагов go. и комментарии с исходным именем Go и местоположением в исходном коде.
--jsonВывести заголовок и полный список функций в формате JSON в stdout.
--filesВывести список путей к исходным файлам, извлечённым из таблицы файлов.
-h, --helpПоказать справочное сообщение.