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

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

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

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

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

Категории

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

r2gopclntabParser

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

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

Популярное

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

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

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

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

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

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

    FlagDescription
    -l, --listВывести каждую восстановленную функцию с её адресом.
    -n NAME, --funcname NAMEВывести только функции, имя которых содержит NAME (поиск по подстроке). Если существует точное совпадение, его адрес выводится отдельно.
    -v, --verboseВыводить сообщения о ходе работы, разобранные поля заголовка и внутренние смещения.
    --applyЗаписать восстановленные имена функций в сессию radare2 как определения функций (af+), флаги в пространстве флагов go. и комментарии с исходным именем Go и местоположением в исходном коде.
    --jsonВывести заголовок и полный список функций в формате JSON в stdout.
    --filesВывести список путей к исходным файлам, извлечённым из таблицы файлов.
    -h, --helpПоказать справочное сообщение.

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


    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/main/documentation/DOCUMENTATION.md) – Полная пользовательская документация со всеми режимами использования, форматами вывода и комбинациями флагов.
    - [METHODOLOGY.md](https://github.com/asherdll/r2gopclntabparser/blob/main/documentation/METHODOLOGY.md) – Проектные решения и алгоритмы: разрешение textStart vs .text, разбор с учётом версии, стратегия сканирования PE, декодирование PC-данных, детали интеграции с r2.
    - [GOPCLNTAB_FORMAT.md](https://github.com/asherdll/r2gopclntabparser/blob/main/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)
    
    Скачать инструмент