Как читать авторский курс и нормативные материалы
Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.
LIEF как программный анализ ELF
Почему это важно для SCA/OSA
Ручные readelf/objdump хороши для одного бинаря, но конвейер SCA разбирает десятки и сотни артефактов: все исполняемые файлы образа, каждую .so в /usr/lib, бинарники из нескольких сборок. Парсить их через grep по текстовому выводу утилит — хрупко: формат вывода меняется между версиями binutils, поля приходится вытаскивать регулярками, а нестандартные или слегка повреждённые ELF ломают разбор. LIEF — библиотека (Python/C++), которая читает ELF (а также PE/Mach-O) как объект: секции, DT_NEEDED, символы, RPATH становятся полями, а не строками для парсинга.
Для SCA это даёт повторяемость и масштаб: один скрипт извлекает динамические зависимости из всего дерева бинарей и сразу складывает их в структуру для маппинга на пакеты. Это превращает разовый ручной анализ в воспроизводимый шаг пайплайна.
Как это проявляется
Та же информация, что даёт readelf -d, но как программные поля — и сразу по множеству файлов:
import lief
binary = lief.parse("./app")
# DT_NEEDED как список строк, без парсинга текста
needed = [e.name for e in binary.dynamic_entries
if e.tag == lief.ELF.DynamicEntry.TAG.NEEDED]
# RPATH/RUNPATH — отдельными тегами
runpath = [e.runpath for e in binary.dynamic_entries
if e.tag == lief.ELF.DynamicEntry.TAG.RUNPATH]
print(needed) # ['libssl.so.3', 'libcrypto.so.3', 'libc.so.6']
print(runpath) # ['$ORIGIN/../lib']
# признак stripped: пустая таблица символов .symtab при наличии .dynsym
has_symtab = any(s.name == ".symtab" for s in binary.sections)
Дальше этот список напрямую идёт в маппинг .so → пакет без промежуточного текста. Прогон по дереву (os.walk + lief.parse) даёт инвентаризацию всех бинарей образа за один запуск.
Когда LIEF, а когда
readelfОдин-два бинаря, интерактивно —readelf/objdumpбыстрее (см. ldd readelf objdump). Пачка артефактов, повторяемый шаг CI, нестандартные/частично битые ELF, нужно складывать результат в JSON/SBOM — LIEF: он не зависит от формата вывода утилит и устойчивее к краевым случаям.
Слепая зона или приём
Важная граница: LIEF — это парсинг, а не резолвинг. Он прочитает DT_NEEDED = libssl.so.3 из файла, но не скажет, какой именно файл и версия подставятся в рантайме на конкретном хосте — это задача загрузчика (ldd) и пакетного менеджера. Поэтому LIEF закрывает извлечение фактов из бинаря, но не отменяет шаг «soname → файл → пакет → версия» (см. динамическая линковка).
Приём — использовать LIEF как сборщик evidence в масштабе: пройти все ELF, вытащить NEEDED/RPATH/RUNPATH/признак stripped, нормализовать в таблицу и только потом маппить на пакеты и версии. И помнить, что статически вшитый код LIEF тоже не видит как зависимость — для него остаётся анализ символов/строк и build-scan (статическая линковка).
Что делать на проекте
- Для массового разбора (образ, дерево
/usr/lib, набор сборок) использовать программный парсер, а не grep поreadelf. - Извлекать единым проходом:
DT_NEEDED,DT_SONAME,RPATH/RUNPATH, наличие.symtab(признак stripped) — и складывать в структуру. - Результат парсинга не считать финальным составом: добавлять отдельный шаг резолвинга
.so → пакет → версия. - Обрабатывать ошибки парсинга как сигнал, а не как сбой: нераспознанный ELF — кандидат в реестр неопознанных, а не «пропустить молча».
- Встраивать скрипт в CI как воспроизводимый шаг и сохранять его вывод как аудиторский артефакт (см. build logs как аудиторский артефакт).
- Не пытаться через LIEF восстановить статику — для неё уходить в build-scan и анализ символов.
Связь
- Модуль: М09. C/C++ legacy
- Практики: П22. ELF dynamic dependencies · П19. C C++ make build inventory
- Нормативка: ГОСТ Р 56939-2024 · NIST SP 800-218 SSDF (RV.1) · BSI TR-03183-2 v2.1.0
- Внешний источник: проект LIEF — https://lief.re/
- Смежные заметки 06: ELF и разделы dynamic · ldd readelf objdump · динамическая линковка · stripped binaries · hash-based identification