Программа молчала как рыба. А спецы по безопасности? Поверили ей на слово...

Жара стояла такая, что даже сервера, кажется, потели, когда наша команда аналитиков из солидной IT-конторы наткнулась на одну крайне подозрительную утилитку. Знаете, типа для сжатия файлов, с виду всё честно: функции на месте, код – прозрачнее горного ручья, зависимости – стандартные, как гвозди в строительном магазине. Чистюля, да и только. Уж поверьте, мы такие вещи на зубок пробовали не раз.
Но вот загвоздка: стоило запустить эту «чистюлю» под пристальным взглядом мониторинга системных вызовов и картинка поплыла. Вместо того чтобы тихо-мирно архивировать, она начала чудить! Тут тебе и сканирование всех сетевых углов и щелей, и втихую выуживание SSH-ключей прямо из домашних папок (наглость!), и попытки наладить связь с какими-то левыми серверами. Где это видано? Да ещё и системные файлы под шумок пыталась подправить. Вот это поворот, а? Статический анализ кричал: «Безопасно!» А динамический? Динамика только ехидно ухмыльнулась в ответ. И было отчего.
Как же раскусить такого цифрового лжеца?

Ах, друзья мои, некоторые тайны как и некоторые люди, раскрываются только в действии, в самой гуще событий. Этот гадкий код мог дремать месяцами, как спящая красавица, пока не наступит его «час икс»: нужная дата, конкретный пользователь, звёзды встанут в ряд. Обфускация? Да запросто! Маскируется под безобидного офисного планктона, а на деле – хищник в овечьей шкуре. Вот почему любой уважающий себя специалист обязан уметь подглядывать за программами в самый разгар их «работы». Без этого он как слепой котёнок.
За четверть часа (да-да, всего за 15 минут) вы освоите приёмы цифрового шпионажа. Не иначе как Джеймс Бонд на минималках: научитесь перехватывать шепот системных вызовов с помощью strace (это как цифровой стетоскоп), отслеживать, с какими библиотеками программа тайком водится (ltrace в помощь), и выяснять её подозрительные «родственные связи» через ldd. Эти штуковины, они как рентген, показывающий истинные намерения любой, даже самой скрытной софтины.

К финалу этой статьи вы будете вооружены до зубов. Сможете поймать любую программу с поличным, даже если она прикидывается невинным блокнотиком, в тот самый момент, когда она потянется за вашими данными. Не верите? Сейчас поверите.
С чего всё начинается? Или всё-таки... заканчивается?
В прошлый раз мы копались во внутренностях ELF-файлов, будто часовщики, разбирающие швейцарский хронометр. Команды readelf, objdump, nm... Эти штуки показали нам скелет программы: функции, зависимости, символы – всё без единого запуска. Статика – это как изучать автомобиль по чертежам. Но черт побери, кто же знает, заведётся ли двигатель?
А теперь представьте: программа подгружает код на лету как фокусник достает карты из рукава. Или её зловредная часть спит, пока не наступит пятница 13-е. А может, она ведёт себя прилично в офисе, но начинает чудить в кафе с открытым Wi-Fi? Вот тут-то динамический анализ и вступает в игру: наблюдение за программой в действии, когда она живёт. Никаких «может», а только «что творит».

Статика vs Динамика: боксёрский поединок методов
| Статический разбор (наш прошлый герой) | Динамический анализ (сегодняшний матч) |
|---|---|
| Ковыряемся в коде без запуска – безопасно, но... | Запускаем и смотрим под лупой – осторожно! |
| Видим весь код – даже мёртвые ветки | Ловим только то, что реально выполняется |
| Безопасно? Ещё бы! Вирусы не прыгают | Рискуешь – без песочницы ни шагу! |
| Быстро, автоматизируется одной левой | Медленно, зависит от сценария – адски |
| Пропускает динамику – увы, реалии | Показывает реальное поведение – без прикрас |
Когда динамика ваш спасительный круг
- Обфусцированный код – распаковывается только при запуске, как гадкий кокон.
- Условия-невидимки – вредоносное д... активируется при звёздах в Стрельце.
- Производительность – ищем узкие места, где программа «тормозит, как танк в грязи».
- Потайные двери – функциональность, спрятанная глубже правительственных секретов.
- Системное взаимодействие – что трогает, куда лезет, с кем шепчется по сети.
- НИ В КОЕМ СЛУЧАЕ не запускайте подозрительное ПО на рабочей машине – это как лизать перила в метро.
- Песочница или смерть: виртуалка (VirtualBox, QEMU), контейнеры – ваш храм.
- Отрубайте интернет – если софтина «позвонит маме», ваши дела плохи.
- Снапшоты до и после – откат спасёт от цифрового апокалипсиса.
- Следите за ВСЕМ: файлы, сеть, вызовы – паранойя ваша суперсила.
Динамический анализ – это как засунуть руку в клетку к тигру. Страшно? Ещё бы. Но иначе не увидите, как он реально охотится. В этой статье разберём, как подглядывать за программами без потери пальцев. Готовы к опасной работе?
Песочница или крематорий: как выжить в динамическом аду
Изоляция – не роскошь, а билет в один конец
Погоня за вредоносами похожа на ловлю скорпионов голыми руками. Без песочницы вы не исследователь, а лабораторная крыса. Помните ту нашу прошлую статейку с виртуалками? Так вот, сейчас это ваш единственный спасательный круг.
Сеть: индикатор №1 для параноиков
Сетевая активность хуже крика «предатель!» в тишине операционки. Вот вам два варианта контроля этого вопроса:
Вариант «Отбой тревоги»: глушим всё
# Режем провода – по-стахановски
$ sudo ip link set down eth0 # Провод? Не, не слышал
$ sudo ip link set down wlan0 # Wi-Fi? А что это?
$ ip addr show # Проверяем – тишина должна быть гробовая
Вариант «Контролируемый хаос»: следим за каждым пакетом
Мониторим сеть:
$ netstat -tuln # Кто куда шепчется?
$ ss -tuln # Дублируем, вдруг первый в сговоре с врагом
# А DNS – это же кладезь компромата:
$ sudo tcpdump -i any port 53 -w dns-analysis.pcap # Ловим сплетни на лету
Утечки данных: ваш персональный апокалипсис
Зачистка территории
На всякий случай удалим чувствительные данные из среды, в которой проводим анализ.

rm -rf ~/.ssh # Ключи? Какие ключи?
rm -rf ~/.gnupg # Шифрование? Не, не видел
rm -f ~/.netrc # Авторизации – в топку!
rm -f ~/.aws/credentials # Облака? Только дождевые
Это лишь верхушка айсберга. Ваши секреты повсюду, как тараканы.
И добавим немного подставы для трояна.
echo "hunter2" > ~/.ssh/id_rsa # Фейковый ключ – пусть мучается
echo "[default]" > ~/.aws/credentials # Ключ доступа? Держи поддельный!
echo "aws_secret = FAKE_K3Y" >> ~/.aws/credentials # На, подавись
Слежка за файлами: цифровой стукач
Ставим жучки через Auditd:
$ sudo auditctl -w /etc/passwd -p r -k passwd_read # Кто пасвд читал? Шпион!
$ sudo auditctl -w ~/.ssh -p rwa -k ssh_access # В мои ssh? Только через мой труп!
# Потом разбор полётов:
$ sudo ausearch -k passwd_read # Ага, попался, гад!
Вредоносный код: инструкция по разминированию
- Копии, а не оригиналы – как в кино: «подрывник всегда ошибется один раз».
- Read-only монтирование – чтобы гадина не сожрала системные файлы.
- Никакого root! – запускайте под ограниченным юзером, будто на минном поле.
- Ресурсы под колпаком – CPU/RAM/диск мониторим как ястреб.
- Таймауты – чтоб вечные циклы не сожрали ваше время жизни.
Скрипт-телохранитель:
#!/bin/bash
# safe_execute.sh - цифровой ковбой с таймером
BINARY=""
TIMEOUT="${2:-30}"
LOG_FOLDER="output"
LOG_FILE="analysis_$(date +%Y%m%d_%H%M%S).log"
if [[ ! -f "$BINARY" ]]; then
echo "Файл не найден: $BINARY"
exit 1
fi
if [[ ! -d "$LOG_FOLDER" ]]; then
echo "Папка output не найдена"
exit 1
fi
echo "=== НАЧАЛО АНАЛИЗА $(date) ===" | tee "$LOG_FOLDER/$LOG_FILE"
echo "Бинарный файл: $BINARY" | tee -a "$LOG_FOLDER/$LOG_FILE"
echo "Таймаут: $TIMEOUT секунд" | tee -a "$LOG_FOLDER/$LOG_FILE"
# Проверка сетевой изоляции
if ping -c 1 8.8.8.8 &>/dev/null; then
echo "⚠️ ВНИМАНИЕ: Сеть доступна! Рекомендуется отключить." | tee -a "$LOG_FOLDER/$LOG_FILE"
fi
# Создание ограниченной среды
exec timeout "$TIMEOUT" \
strace -f -o "$LOG_FOLDER/strace_$LOG_FILE" \
"$BINARY" 2>&1 | tee -a "$LOG_FOLDER/$LOG_FILE"
echo "=== КОНЕЦ АНАЛИЗА $(date) ===" | tee -a "$LOG_FOLDER/$LOG_FILE"
Команда strace здесь наш главный свидетель. О нём – ниже по тексту.
Попробуем запустить на какой-нибудь подозрительной программе:
sh scripts/safe_execute.sh build/hello_program
Инструменты ldd и lddtree: разведка боем
«Доверяй, но проверяй пути как это делает телохранитель президента. Особенно – в /tmp»
ldd – экзорцист, который служит дьяволу
Инструмент ldd (List Dynamic Dependencies) похож на доверчивого следователя, который отпускает подозреваемого, чтобы узнать его связи. Библиотеки? Кровеносная система программы. Но кто знает, не впрыснут ли они вам яд?

Что выудит ldd
Утилита ldd нам может дать следующую полезную информацию:
- пути к
.so-файлам (адреса подпольных встреч); - адреса в памяти (где орудует шайка);
- версии зависимостей («паспорта» соучастников);
- пропавшие библиотеки («сбежавшие свидетели»).
Анализ динамических библиотек
Попробуем проанализировать какую-нибудь программу из CTF:
$ ldd build/strace_ctf # Рискнём?
linux-vdso.so.1 (0x0000729d10a7a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000729d10800000)
/lib64/ld-linux-x86-64.so.2 (0x0000729d10a7c000)
Инструмент ldd может быть небезопасен для анализа подозрительных файлов!
Почему ldd опасен? Утилита ldd фактически запускает исполняемый файл с специальными переменными окружения. Это означает, что вредоносный код может выполниться!
Злоумышленники отлично понимают, что их ПО рано или поздно будет подвержено анализу. Поэтому они могут попытаться украсть данные исследователя или установить бекдор.
Визуализация дерева зависимостей с помощью lddtree
Утилита lddtree визуализирует дерево зависимостей разделяемых библиотек (.so) для ELF-бинарников в Linux. В отличие от ldd, она показывает иерархическую структуру загрузки библиотек, включая:
- рекурсивные зависимости – «кто кому зять»;
- влияние
RPATH/RUNPATH– скрытые тропы; LD_LIBRARY_PATH– чёрные входы.
$ lddtree build/strace_ctf
build/strace_ctf (interpreter => /lib64/ld-linux-x86-64.so.2)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
Инструмент lddtree может помочь проанализировать полную цепочку зависимостей, найти подмену библиотек и выявить анти-отладочные техники.
Проверка на подмену библиотек
# Сохраняем эталонное дерево на чистой системе
lddtree /bin/ls > clean_ls_deps.txt
# На подозрительной системе
lddtree /bin/ls > infected_ls_deps.txt
# Сравниваем
diff clean_ls_deps.txt infected_ls_deps.txt
Безопасные альтернативы ldd: анализ трупа без вскрытия
С инструментами objdump, readelf и nm вы знакомились ранее, еще раз вспомним их.
objdump – криминалист без эмоций
Безопасный инструмент для получения детальной информации о динамических зависимостях на основе статического анализа. Инструмент objdump является линейным дизассемблером, что делает его менее точным в выполнении этой задачи.
$ objdump -p bin/math_calc | grep NEEDED
NEEDED libc.so.6
Детальная информация о динамических зависимостях:
$ objdump -x build/$(TARGET) | grep -A 20 "Динамический раздел"
Динамический раздел:
NEEDED libc.so.6
INIT 0x0000000000001000
FINI 0x00000000000018ac
INIT_ARRAY 0x0000000000003d48
INIT_ARRAYSZ 0x0000000000000008
FINI_ARRAY 0x0000000000003d50
FINI_ARRAYSZ 0x0000000000000008
GNU_HASH 0x00000000000003b0
...
readelf – архивный сыщик
В предыдущей статье мы активно использовали readelf для различных целей, включая определение необходимых программе библиотек.
Список всех необходимых библиотек:
$ readelf -d build/strace_ctf | grep NEEDED
0x0000000000000001 (NEEDED) Совм. исп. библиотека: [libc.so.6]
Информация о динамическом загрузчике:
$ readelf -l build/strace_ctf | grep "интерпретатор"
[Запрашиваемый интерпретатор программы: /lib64/ld-linux-x86-64.so.2]
nm – расшифровка переговоров
Кто с кем шепчется (анализ импортируемых функций):
$ nm -D build/strace_ctf
U close@GLIBC_2.2.5
w __cxa_finalize@GLIBC_2.2.5
U execvp@GLIBC_2.2.5
U _exit@GLIBC_2.2.5
U fork@GLIBC_2.2.5
U __fprintf_chk@GLIBC_2.3.4
U free@GLIBC_2.2.5
U fwrite@GLIBC_2.2.5
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main@GLIBC_2.34
U malloc@GLIBC_2.2.5
U open@GLIBC_2.2.5
U __stack_chk_fail@GLIBC_2.4
0000000000004020 B stderr@GLIBC_2.2.5
U strlen@GLIBC_2.2.5
U strncmp@GLIBC_2.2.5
U system@GLIBC_2.2.5
U wait@GLIBC_2.2.5
U write@GLIBC_2.2.5
Практика анализа зависимостей: где собака зарыта?

Любые нестандартные зависимости должны вызывать подозрения: библиотека во временной папке, отсутствующий файл и так далее:
$ ldd build/strace_ctf | grep -v -E "(libc|ld-linux|linux-vdso)"
super_puper_lib.so.1 => not found # Подозрительно!
/tmp/hidden.so (0x000077...) # Очень подозрительно!
LD_LIBRARY_PATH: троянский конь в вашей крепости
Переменная LD_LIBRARY_PATH определяет дополнительные пути поиска библиотек и может использоваться для атак.
Как вас взломают через переменную
Например, злоумышленник может подсунуть вредоносную библиотеку:
export LD_LIBRARY_PATH="/tmp/malicious:$LD_LIBRARY_PATH"
./build/strace_ctf # Загрузит библиотеки из помойки!
Как ловить диверсантов?
Проверяйте пути. Сейчас же!
echo $LD_LIBRARY_PATH # Не завёлся ли хамелеон?
Вышибайте дверь переменной перед анализом:
unset LD_LIBRARY_PATH # Нет пути – нет проблемы!
ldd build/strace_ctf # Теперь чистая проба
Любые пути вне /lib и /usr/lib должны вызывать подозрения, поэтому проверим, откуда загружаются библиотеки:
$ ldd build/strace_ctf | grep -v "/lib"
Проверяйте целостность эталонов:
$ dpkg -V libc6 # Debian/Ubuntu
$ rpm -V glibc # Red Hat/CentOS
ldd– дьявол в вашем терминале. Не верьте ему слепо!lddtree– ваш надёжный картограф подполья.readelf/objdump– криминалисты без риска.LD_LIBRARY_PATH– чёрный ход. Заварите его наглухо!
Инструмент strace: чем занимается программа по ночам?
«Хочешь спрятать дерево? Спрячь в лесу. Хочешь спрятать зловредный вызов? Засыпь его тысячами close!»

Системные вызовы: криминальные улики ОС
Представьте: программы – это жильцы многоэтажки, а ядро системы – управдом. Системные вызовы? Это записи в журнале: «кто куда залез», «что украл», «кому звонил». Единственный способ выполнить что-то важное, оставить подпись в этом журнале. Без вариантов.
Системные вызовы – это интерфейс между программами пользовательского пространства и ядром операционной системы. Это единственный способ для программы выполнить привилегированные операции: работа с файлами, сетью, процессами и памятью.
Почему это ваш детектор лжи №1:
- раскрывает истинные намерения программы независимо от обфускации;
- показывает реальное поведение, то есть что программа фактически делает;
- выявляет скрытую функциональность: бэкдоры, кейлоггеры, сетевую активность;
- помогает в отладке: поиск ошибок и узких мест производительности.
Категории вызовов – досье на преступника
Файловые операции:
open, openat, read, write, close # Роется в ваших файлах
stat, chmod, chown # Меняет замки и права
Процессы и сигналы:
fork, exec, wait, kill # Рождает/убивает процессы
signal # Шлёт анонимные угрозы
Сетевые операции:
socket, bind, listen # Организует «прослушку»
accept, connect # Принимает звонки от «друзей»
send, recv # Шлёт компромат куда не надо
Память:
mmap, munmap, mprotect # Прячет улики в памяти
brk # Расширяет «криминальную зону»
Системная информация:
getpid, getuid, uname # Узнаёт кто вы и чем дышите
time # Сверяет часы перед ограблением
Основные опции strace: настройки для параноика
Синтаксис утилиты strace достаточно простой:
strace [опции] программа [аргументы]
Так же можно подключиться к работающему процессу по его PID:
strace [опции] -p PID
Основные опции:
-f, --follow-forks # Следим за всей «семьёй» (дочерние процессы)
-e EXPR # Фильтр системных вызовов
-o FILE # Пишем донос в файл (а то в терминале сбежит)
-c # Статистика вызовов
-t # Время преступления с точностью до микросекунды
-T # Показать время выполнения вызова
-s SIZE # Максимальная длина строк в выводе
-x # Шестнадцатеричный вывод строк
-y # Показывает пути файлов – «куда именно лезли»
Фильтрация вызовов: глушим информационный шум
Вывод strace льётся как вода из прорванной трубы, поэтому полезно научиться его фильтровать. Это можно сделать как после получения результатов (grep, awk), так и перед запуском strace:
# Только файловые операции
$ strace -e trace=file build/strace_ctf
# Только сетевые операции
$ strace -e trace=network build/strace_ctf
# Только операции с процессами
$ strace -e trace=process build/strace_ctf
# Только операции с памятью
$ strace -e trace=memory build/strace_ctf
Точечный отлов конкретных вызовов:
# Только нужные системные вызовы
$ strace -e trace=openat,close,read,write build/strace_ctf
# Исключить определенные вызовы (убрать "шум")
$ strace -e trace=\!write,close build/strace_ctf
Файловые махинации: как программы роются в ваших секретах
Слежка за файлами: цифровой детектив в действии
$ strace -e trace=openat,read,write,close build/strace_ctf 2>&1
Что увидим в логах (классика жанра):
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 # Шерстит системный кеш
close(3) = 0 # Притворился невиновным
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 # Ищет сообщника
read(3, "7ELF{{TEXT}}..."..., 832) = 832 # Читает досье
close(3) = 0
write(2, "Usage: build/strace_ctf <flag>\n", 31Usage: build/strace_ctf <flag>
) = 31 # Сливает улики в stderr
Поиск подозрительного поведения
# Ловим за руку у системных файлов:
$ strace -e trace=openat build/strace_ctf 2>&1 | grep -E "(passwd|shadow|sudoers|ssh)"
# Следим за шакалами в /tmp и /dev:
$ strace -e trace=openat,write build/strace_ctf 2>&1 | grep -E "(tmp|dev|proc|sys)"
# Мониторинг изменения прав файлов
$ strace -e trace=chmod,chown build/strace_ctf 2>&1
Сетевые операции и соединения
Анализ программы, которая подозревается в передаче данных на удаленный сервер:
# Отслеживание сетевой активности
$ strace -e trace=socket,connect,send,recv,sendto build/strace_network_ctf 2>&1
# Ожидаемый вывод:
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
sendto(3, "PASSWORD{{TEXT}}", 15, 0, {sa_family=AF_INET, sin_port=htons(55330), sin_addr=inet_addr("192.10.10.10")}, 16) = 15 # Отправил пароль в никуда!
Детальный анализ сетевых операций:
# Полная трассировка сетевой активности
$ strace -e trace=network -s 200 build/strace_network_ctf 2>&1
# Анализ с расшифровкой адресов
$ strace -y -e trace=socket,connect,bind,listen build/strace_network_ctf
# Поиск DNS запросов
$ strace -e trace=openat build/strace_network_ctf 2>&1 | grep resolv.conf # Кто спрашивает про домены?
Выявление подозрительной сетевой активности:
# Поиск подключений к необычным портам
$ strace -e trace=connect build/strace_network_ctf 2>&1 | grep -v ":80\|:443\|:53"
# Поиск bind на привилегированных портах (меньше 1024)
$ strace -e trace=bind build/strace_network_ctf 2>&1 | grep -E ":[0-9]{1,3}[^0-9]"
# Мониторинг отправки данных
$ strace -e trace=send,sendto -s 100 build/strace_network_ctf 2>&1
Тайминги: где программа тормозит
С помощью strace можно измерить время выполнения каждого системного вызова:
strace -T build/strace_ctf 2>&1 | grep "<.*>" # Ищем задумчивых улиток
Это может помочь:
- найти утечки производительности – где виснет как студент перед сессией;
- обнаружить антиотладку – искусственные задержки («сплю 5 сек, чтобы вас запутать»);
- поймать маяки – таймеры для скрытых соединений («звоню боссу каждые 10 минут»).
Криминальные инстинкты программ: поиск подозрительного поведения
Признаки хронического вредительства
Механизмы закрепления
# Поиск записи в автозапуск
$ strace -e trace=openat,write build/strace_ctf 2>&1 | grep -E "(\.bashrc|\.profile|crontab|systemd)"
# Поиск создания системных сервисов
$ strace -e trace=openat build/strace_ctf 2>&1 | grep -E "(systemd|init\.d|rc\.)"
Попытки эскалации привилегий
# Попытки смены пользователя
$ strace -e trace=setuid,setgid,setreuid build/strace_ctf 2>&1
# Попытки доступа к sudo/su
$ strace -e trace=execve build/strace_ctf 2>&1 | grep -E "(sudo|su)"
Скрытие активности
# Удаление логов
$ strace -e trace=unlink,unlinkat build/strace_ctf 2>&1 | grep -E "(log|var)"
# Изменение временных меток файлов
$ strace -e trace=utimensat build/strace_ctf 2>&1
Сбор информации о системе
# Чтение системной информации
$ strace -e trace=openat build/strace_ctf 2>&1 | grep -E "(proc|sys|passwd|group)"
# Поиск сетевых интерфейсов и конфигурации
$ strace -e trace=openat build/strace_ctf 2>&1 | grep -E "(network|resolv|hosts)"
Производительность: когда strace душит программу
Утилита strace значительно влияет на производительность и может замедлить работу программы в десятки раз. Рассмотрим способы оптимизации:
# Фильтруем по минимуму
# Только критичные для текущего анализа вызовы
$ strace -e trace=openat,write -o output.log build/strace_ctf
# Пишем в файл (быстрее терминала в разы)
$ strace -o output.log build/strace_ctf
Инструмент ltrace: подслушивание в баре динамических библиотек
«Представьте, что вы подглядываете за чужой перепиской. Именно это делает ltrace в мире динамических библиотек»

strace vs ltrace: война слонов и китов
Когда strace ковыряется в ядре (типа детектива на уровне железа), ltrace сидит в кафе с подносом библиотек. Если strace показывает взаимодействие с ядром, то ltrace отслеживает вызовы функций динамических библиотек. Это дает нам представление о том, какие высокоуровневые функции использует программа.
Команда ltrace использует механизм LD_PRELOAD для перехвата вызова функций из динамических библиотек. Для этого механизма необходимы .dynsym (динамическая таблица символов с именами импортируемых/экспортируемых функций) и .dynstr (таблица строк с названиями функций). Если .dynsym и .dynstr отсутствуют – ltrace не сможет сопоставить адреса функций с их именами.
При удалении отладочных символов стираются таблицы .symtab и .strtab, но остаются .dynsym и .dynstr. Что касается статически слинкованных программ – ltrace бесполезен.
| strace | ltrace |
|---|---|
| Системные вызовы (работает с ядром, как шпион) | Высокоуровневые функции (психолог, анализирующий разговоры в баре) |
open(), write(), socket() – скучно, но важно |
fopen(), printf(), malloc() – драма на уровне приложений |
| Низкий уровень | Высокий уровень |
| Всегда работает (даже когда библиотеки «спят») | Требует, чтобы библиотеки не прятали свои имена (символы) |
| Медленный, как черепаха с пинцетом | Быстрый, но только если библиотеки не упрямые |
Как подглядывать за библиотеками?
Просто запустите ltrace:
# Смотрим все вызовы, как в замочную скважину
$ ltrace build/strace_ctf
# Сохраняем лог, чтобы потом притвориться, что мы профессионалы
$ ltrace -o trace.log build/strace_ctf
Практика: ищем то, что прячут
Криптография? Держите:
# Ищем OpenSSL-функции (они всегда подозрительны)
$ ltrace -e 'AES_*,RSA_*,SHA*,MD5*' build/strace_ctf
# Или ищем слова в логе, как в детективном романе
$ ltrace build/strace_ctf 2>&1 | grep -i -E "(crypt|hash|encrypt|decrypt|cipher)"
Сетевые штуки? Легко:
# Высокоуровневые вызовы — типа "кто звонит?"
$ ltrace -e connect,send,recv,gethostbyname build/strace_ctf
# DNS-резолвинг: где программа ищет друзей?
$ ltrace -e gethostbyname,getaddrinfo build/strace_ctf
Подозрительные функции? Держите список:
# Выполнение команд — красный флаг!
$ ltrace -e system,exec,popen build/strace_ctf
# Процессы-зомби? Ищем `fork` и `waitpid`
$ ltrace -e fork,waitpid build/strace_ctf
Когда ltrace не работает: или как обмануть умную программу
Статические библиотеки: программа – как подросток, который все делает сам
Если программа слинкована статически (функции встроены в программу), то могут возникнуть сложности. В качестве альтернативы можно использовать objdump и поискать вызовы функций и переходы (но это как читать инструкцию на китайском):
objdump -M intel -d build/strace_ctf | grep -E "(call|jmp)" | head -10
Антиотладочные приколы: программа кричит «Обнаружена отладка!»
Программы могут обнаружить использование ltrace, strace и gdb. В нашем примере, программа явно сообщит, что она обнаружила попытку отладки (в реальности такого не бывает). Рассмотрим на примере ltrace:
$ ltrace build/anti_strace 2>&1 | grep -i "отладка"
exit(1Обнаружена отладка! Завершение работы.
Ну, теперь мы знаем, что она стесняется. Обходим через LD_PRELOAD (маленькая подсказка: напишите shared-библиотеку, которая обманывает проверки):
# Обход через LD_PRELOAD
$ cat > bypass_ptrace.c << 'EOF'
// Код обхода
// Рассматривать его в этом уроке не будем
// В целом, он простой, главное не сломать ltrace (маленькая подсказка)
EOF
$ gcc -shared -fPIC /src/bypass_ptrace.c -o /tmp/bypass_ptrace.so
$ LD_PRELOAD=/tmp/bypass_ptrace.so ltrace build/anti_strace

Если программа всё равно не дает себя отлаживать, возможно, пора вспомнить, что вы не в 90-х, и перейти на более современные методы. Но это уже другая история...
Динамическая загрузка: программа подключает библиотеки «на лету»
# Программы могут загружать функции через dlopen/dlsym
$ ltrace -e dlopen build/hello_lib
hello_lib->dlopen("/tmp/libmylib.so", 1) = 0x5683925c92c0
# Дополнительный анализ через strace
$ strace -e trace=openat build/hello_lib 2>&1 | grep "\.so"
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/libmylib.so", O_RDONLY|O_CLOEXEC) = 3
Практический анализ подозрительного поведения
«Хороший анализ как приготовление стейка: 30% инструменты, 70% чутьё. И никогда не верьте первому выводу – он всегда лжёт»

Разбор strace_ctf: как вскрыть программу за 3 шага
Давайте проведем комплексный анализ программы strace_ctf, используя все изученные инструменты:
Шаг 1: Статический анализ (быстрый обзор)
Быстро сканируем внутренности без запуска:
# Что программа может делать
$ strings build/strace_ctf | grep -E "(file|password|key)" # Ищем улики в строках
# Какие функции использует
$ nm build/strace_ctf | grep " U " # Смотрим, с кем общается (импорты)
Шаг 2: Динамический анализ файловых операций
#!/bin/bash
# analyze_file_dynamic.sh
echo "=== ПРОСТОЙ АНАЛИЗ ==="
BINARY=""
echo -e "\n1. АНАЛИЗ СИСТЕМНЫХ ВЫЗОВОВ:"
strace -e trace=openat,write,close $BINARY 2>&1 | grep -v lib
echo -e "\n2. АНАЛИЗ БИБЛИОТЕЧНЫХ ВЫЗОВОВ:"
ltrace -e fopen,fprintf,fclose $BINARY 2>&1
Шаг 3: Временной анализ
Анализ времени выполнения операций:
$ strace -tt -T build/strace_ctf 2>&1 | grep -E "(openat|write)"
# Поиск задержек (потенциальные network timeouts)
$ strace -T build/strace_ctf 2>&1 | awk '$NF ~ /<.*>/ && $NF > "<0.001>" {print}'
Обнаружение попыток доступа к системным файлам
Мониторинг доступа к критическим файлам:
#!/bin/bash
# monitor_system_access.sh
PROGRAM=""
echo "=== МОНИТОРИНГ ДОСТУПА К СИСТЕМНЫМ ФАЙЛАМ ==="
echo "Программа: $PROGRAM"
echo "Время начала: $(date)"
# Отслеживание доступа к критическим системным файлам
strace -e trace=openat "$PROGRAM" 2>&1 | \
while read line; do
case "$line" in
*"/etc/passwd"*|*"/etc/shadow"*|*"/etc/sudoers"*)
echo "🚨 КРИТИЧНО: Доступ к системному файлу: $line"
;;
*"/home/"*|*"/root/"*)
echo "⚠️ Доступ к домашней директории: $line"
;;
*"/tmp/"*|*"/var/tmp/"*)
echo "ℹ️ Доступ к временным файлам: $line"
;;
*"/proc/"*|*"/sys/"*)
echo "ℹ️ Чтение системной информации: $line"
;;
esac
done
Анализ сетевой активности
Детальный анализ сетевой активности:
#!/bin/bash
# analyze_network_client.sh
PROGRAM=""
echo "=== АНАЛИЗ СЕТЕВОЙ АКТИВНОСТИ ==="
echo "Программа: $PROGRAM"
echo "Время начала: $(date)"
echo "1. СТАТИЧЕСКИЙ АНАЛИЗ СЕТЕВЫХ ФУНКЦИЙ:"
strings $PROGRAM | grep -E "(192\.168|10\.|172\.|connect|socket)"
echo -e "\n2. ДИНАМИЧЕСКИЙ АНАЛИЗ - СИСТЕМНЫЕ ВЫЗОВЫ:"
echo "Отслеживание socket операций:"
timeout 10 strace -e trace=socket,connect,send,recv,close $PROGRAM 2>&1
echo -e "\n3. АНАЛИЗ БИБЛИОТЕЧНЫХ ВЫЗОВОВ:"
echo "Высокоуровневые сетевые функции:"
timeout 10 ltrace -e connect,send,recv,gethostbyname $PROGRAM 2>&1
echo -e "\n4. ПРОВЕРКА СЕТЕВЫХ ПОРТОВ:"
echo "Активные соединения во время выполнения:"
(timeout 5 $PROGRAM &
sleep 2
netstat -tuln | grep -E "(192\.168|LISTEN)"
kill %1 2>/dev/null
)
Поиск следов механизмов закрепления (persistence)
Обнаружение попыток закрепления в системе:
#!/bin/bash
# detect_persistence.sh
PROGRAM=""
TMP_DIR="/tmp/persistence_test"
echo "=== ОБНАРУЖЕНИЕ МЕХАНИЗМОВ ЗАКРЕПЛЕНИЯ ==="
echo "Программа: $PROGRAM"
echo "Время начала: $(date)"
echo "Тестовая директория: $TMP_DIR"
# Создание временной среды
mkdir -p "$TMP_DIR/.config/autostart"
touch "$TMP_DIR/.bashrc" "$TMP_DIR/.profile" "$TMP_DIR/crontab"
mkdir -p "$TMP_DIR/systemd" "$TMP_DIR/init.d"
# Запуск с мониторингом
strace -e trace=openat,write,unlink,execve -f -o strace.log \
env HOME="$TMP_DIR" XDG_CONFIG_HOME="$TMP_DIR/.config" \
"$PROGRAM"
# Анализ результатов
echo -e "\n1. Автозапуск:"
grep -E "\.bashrc|\.profile|\.bash_profile|crontab|\.config/autostart" strace.log || \
echo "Не обнаружено"
echo -e "\n2. Системные сервисы:"
grep -E "systemd|init\.d|rc\.local" strace.log || \
echo "Не обнаружено"
echo -e "\n3. Переменные PATH:"
grep -i "path" strace.log | grep -E "\.bashrc|\.profile" || \
echo "Не обнаружено"
echo -e "\n4. Скрытые файлы:"
grep 'openat.*/\.[^/]*"' strace.log || \
echo "Не обнаружено"
# Очистка
rm -r "$TMP_DIR" strace.log
echo -e "\nТестовая среда удалена"
Создание временной активности программы
Временная последовательность действий:
#!/bin/bash
# create_timeline.sh
PROGRAM=""
echo "=== TIMELINE АКТИВНОСТИ ПРОГРАММЫ ==="
echo "Программа: $PROGRAM"
echo "Начало анализа: $(date)"
# Временные метки для всех операций
strace -tt -T -f "$PROGRAM" 2>&1 | \
awk '/^[0-9]/ {
time =
duration = $NF
gsub(/[<>]/, "", duration)
if ({{TEXT}} ~ /openat/) print time " [FILE] " {{TEXT}} " (" duration ")"
else if ({{TEXT}} ~ /(socket|connect)/) print time " [NET] " {{TEXT}} " (" duration ")"
else if ({{TEXT}} ~ /(write|read)/) print time " [I/O] " {{TEXT}} " (" duration ")"
else if ({{TEXT}} ~ /execve/) print time " [EXEC] " {{TEXT}} " (" duration ")"
}' | head -50
Автоматизация и фильтрация
Рассмотрим пару примеров, которые можно будет доработать под ваши нужды.
Скрипт для автоматического анализа
#!/bin/bash
# Комплексный анализ программ
PROGRAM=""
OUTPUT_DIR="analysis_$(basename "$PROGRAM")_$(date +%Y%m%d_%H%M%S)"
if [[ ! -f "$PROGRAM" ]]; then
echo "Использование: {{TEXT}} <program>"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
cd "$OUTPUT_DIR"
echo "=== УНИВЕРСАЛЬНЫЙ АНАЛИЗАТОР ПРОГРАММ ==="
echo "Программа: $PROGRAM"
echo "Директория результатов: $OUTPUT_DIR"
echo "Время: $(date)"
# 1. Статический анализ
echo "1. Проведение статического анализа..."
{
echo "=== ИНФОРМАЦИЯ О ФАЙЛЕ ==="
file "$PROGRAM"
ls -lh "$PROGRAM"
echo -e "\n=== ELF ЗАГОЛОВОК ==="
readelf -h "$PROGRAM" 2>/dev/null | grep -E "(Type|Entry point|Machine)"
echo -e "\n=== ЗАВИСИМОСТИ (БЕЗОПАСНО) ==="
readelf -d "$PROGRAM" 2>/dev/null | grep NEEDED
echo -e "\n=== СИМВОЛЫ ==="
nm "$PROGRAM" 2>/dev/null | head -20
echo -e "\n=== СТРОКИ ==="
strings "$PROGRAM" | grep -E "(http|ftp|password|secret|admin|config)" | head -20
} > static_analysis.txt
# 2. Динамический анализ системных вызовов
echo "2. Анализ системных вызовов..."
timeout 30 strace -f -o syscalls.log -e trace=openat,write,read,socket,connect,execve "$PROGRAM" &>/dev/null
if [[ -f syscalls.log ]]; then
{
echo "=== СТАТИСТИКА СИСТЕМНЫХ ВЫЗОВОВ ==="
cut -d'(' -f1 syscalls.log | sort | uniq -c | sort -nr | head -10
echo -e "\n=== ФАЙЛОВЫЕ ОПЕРАЦИИ ==="
grep -E "(openat|write|read)" syscalls.log | head -20
echo -e "\n=== СЕТЕВЫЕ ОПЕРАЦИИ ==="
grep -E "(socket|connect)" syscalls.log
echo -e "\n=== ПОДОЗРИТЕЛЬНЫЕ ОПЕРАЦИИ ==="
grep -E "(etc/passwd|etc/shadow|tmp/|\.ssh/)" syscalls.log
} > dynamic_analysis.txt
fi
# 3. Анализ библиотечных вызовов
echo "3. Анализ библиотечных вызовов..."
timeout 30 ltrace -o library_calls.log "$PROGRAM" &>/dev/null
if [[ -f library_calls.log ]]; then
{
echo "=== БИБЛИОТЕЧНЫЕ ФУНКЦИИ ==="
grep -E "(fopen|printf|malloc|free|connect)" library_calls.log | head -20
echo -e "\n=== ПОТЕНЦИАЛЬНО ОПАСНЫЕ ФУНКЦИИ ==="
grep -E "(system|exec|popen)" library_calls.log
} > library_analysis.txt
fi
# 4. Создание итогового отчета
{
echo "ИТОГОВЫЙ ОТЧЕТ АНАЛИЗА"
echo "======================"
echo "Программа: $PROGRAM"
echo "Дата: $(date)"
echo "Аналитик: $(whoami)"
echo
echo "ОЦЕНКА РИСКА:"
RISK_SCORE=0
# Проверка на подозрительные строки
if strings "$PROGRAM" | grep -qi -E "(password|admin|secret)"; then
echo "⚠️ Обнаружены потенциально чувствительные строки"
((RISK_SCORE++))
fi
# Проверка на сетевую активность
if grep -q -E "(socket|connect)" syscalls.log 2>/dev/null; then
echo "🌐 Программа имеет сетевую активность"
((RISK_SCORE++))
fi
# Проверка на системные файлы
if grep -q -E "(etc/passwd|etc/shadow)" syscalls.log 2>/dev/null; then
echo "🚨 ВЫСОКИЙ РИСК: Доступ к системным файлам!"
((RISK_SCORE+=3))
fi
echo "Общий счет риска: $RISK_SCORE"
if [[ $RISK_SCORE -ge 3 ]]; then
echo "🚨 ВЫСОКИЙ РИСК - Требуется детальное расследование"
elif [[ $RISK_SCORE -ge 1 ]]; then
echo "⚠️ СРЕДНИЙ РИСК - Рекомендуется дополнительный анализ"
else
echo "✅ НИЗКИЙ РИСК - Программа выглядит безопасной"
fi
} > final_report.txt
echo "Анализ завершен. Файлы результатов:"
ls -la
echo
echo "Итоговый отчет:"
cat final_report.txt
Фильтрация шума и фокус на важном
#!/bin/bash
# filter_important.sh - Фильтр важных событий из strace логов
STRACE_LOG=""
if [[ ! -f "$STRACE_LOG" ]]; then
echo "Использование: {{TEXT}} <strace_log_file>"
exit 1
fi
echo "=== ФИЛЬТРАЦИЯ ВАЖНЫХ СОБЫТИЙ ==="
echo "1. КРИТИЧЕСКИЕ ФАЙЛОВЫЕ ОПЕРАЦИИ:"
grep -E "(etc/passwd|etc/shadow|etc/sudoers|\.ssh/|\.gnupg/)" "$STRACE_LOG" | \
head -10 || echo "Не обнаружено"
echo -e "\n2. СЕТЕВЫЕ СОЕДИНЕНИЯ:"
grep -E "(socket|connect|bind|listen)" "$STRACE_LOG" | \
head -10 || echo "Не обнаружено"
echo -e "\n3. ВЫПОЛНЕНИЕ КОМАНД:"
grep -E "(execve|system)" "$STRACE_LOG" | \
head -10 || echo "Не обнаружено"
echo -e "\n4. ОПЕРАЦИИ С ВРЕМЕННЫМИ ФАЙЛАМИ:"
grep -E "(tmp/|var/tmp/)" "$STRACE_LOG" | \
head -10 || echo "Не обнаружено"
echo -e "\n5. ИЗМЕНЕНИЕ ПРАВ И ВЛАДЕЛЬЦЕВ:"
grep -E "(chmod|chown|setuid|setgid)" "$STRACE_LOG" | \
head -10 || echo "Не обнаружено"
echo -e "\n6. СТАТИСТИКА АКТИВНОСТИ:"
echo "Всего системных вызовов: $(wc -l < "$STRACE_LOG")"
echo "Уникальных вызовов: $(cut -d'(' -f1 "$STRACE_LOG" | sort -u | wc -l)"
echo "Самые частые вызовы:"
cut -d'(' -f1 "$STRACE_LOG" | sort | uniq -c | sort -nr | head -5
$ strace -o strace.log build/strace_ctf
$ sh scripts/filter_important.sh strace.log
=== ФИЛЬТРАЦИЯ ВАЖНЫХ СОБЫТИЙ ===
1. КРИТИЧЕСКИЕ ФАЙЛОВЫЕ ОПЕРАЦИИ:
-e
2. СЕТЕВЫЕ СОЕДИНЕНИЯ:
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
-e
3. ВЫПОЛНЕНИЕ КОМАНД:
execve("build/strace_ctf", ["build/strace_ctf"], 0x7fffee6ba250 /* 29 vars */) = 0
-e
4. ОПЕРАЦИИ С ВРЕМЕННЫМИ ФАЙЛАМИ:
-e
5. ИЗМЕНЕНИЕ ПРАВ И ВЛАДЕЛЬЦЕВ:
-e
6. СТАТИСТИКА АКТИВНОСТИ:
Всего системных вызовов: 40
Уникальных вызовов: 21
Самые частые вызовы:
8 mmap
6 sendto
3 mprotect
3 close
2 pread64
Итоговое слово: не всё так просто, как кажется
Вот мы и добрались до финала нашего путешествия в мир динамического анализа, того самого, когда программы бегают и прыгают прямо у вас под носом, а вы наблюдаете за этим, как за цирковым представлением. Этот навык, между прочим, не просто «крутой фокус», а настоящее искусство понимания того, что творится под капотом софта. Статический анализ – это всё равно что читать меню в ресторане, а динамический – пробовать блюдо на вкус и понимать, что там внутри.

Борьба с зависимостями или как ldd стал моим лучшим другом
Инструмент ldd словно фонарик в темном подвале библиотек. Помните, мы разбирались с ним? Вот что нужно вынести из этого:
- Динамические библиотеки – это как «кирпичики» для программистов, из которых они строят свои домики-приложения.
- Когда
lddне хочет работать (например, файл подозрительный), приходится искать обходные пути (вспомнилиreadelfиobjdump). LD_LIBRARY_PATH– это как GPS-навигатор для программы, указывающий, где искать библиотеки. И злоумышленники этим пользуются, как вор – отмычкой.- Статические программы – это как самодостаточные отшельники, а динамические – как общительные люди, постоянно бегающие к друзьям за помощью.
Команда strace: как подглядывать за тем, что программа шепчет ядру
Инструмент strace – моя любимая игрушка. С ним я чувствую себя как шпион с подслушивающим устройством:
- Понимаешь, что программа делает с операционной системой.
- Фильтрация данных – это как поиск иголки в стоге сена. Иногда приходится часами разбираться в логах, которые больше, чем «Война и мир».
- Подозрительное поведение – это когда программа пытается открыть файлы, к которым ей не положено, или лезет в сеть, когда должна считать числа.
- Создание timeline – это как составление карты преступления. Видишь, что программа в 10:05 открыла файл, в 10:06 подключилась к сети, и понимаешь – что-то здесь не чисто.
Кстати, вчера сосед пытался починить свой ноутбук и нажимал на все кнопки подряд. strace помог мне понять, какие системные вызовы он случайно активировал – хоть какая-то польза от его экспериментов! 😉
Команда ltrace: как подслушивать разговоры в баре библиотек
- Анализ высокоуровневых операций – это когда не просто слышишь, что кто-то звонит, а понимаешь, что он говорит «Привет, давай встретимся в парке».
- Криптографические функции – это как красные флажки, которые кричат: «Осторожно, здесь может быть что-то интересное!».
- Ограничения
ltrace– это как правила в игре. Иногда приходится хитрить и обходить их, как мы это делали сLD_PRELOAD.
Кстати, вчера моя дочь спрашивала, почему программы не хотят, чтобы их отлаживали. Я объяснил ей на примере: представь, что ты пишешь дневник, а мама подглядывает. Программы тоже хотят немного приватности!
Практические навыки или как не утонуть в море данных
Автоматизация анализа похожа на найм помощника, который будет сортировать ваши бумаги, пока вы пьете кофе. Без скриптов я бы сошел с ума от объема информации!
Создание отчетов напоминает составление детективного досье. Всё по полочкам, ищешь закономерности, как Шерлок Холмс.
Фильтрация близка к настройке радиоприемника. Крутишь частоты (данные), пока не найдешь ту самую станцию (информацию), которую ищешь.
Знаете, иногда я чувствую себя как Нео из «Матрицы», когда смотрю на эти логи. Только вместо зеленого кода вижу кучу непонятных системных вызовов. Но со временем начинаешь видеть закономерности – вот это и есть настоящая магия!
Что дальше?
В следующей статье я расскажу о том, как плохие программы прячутся от наших любопытных глаз:
- Стеганография в изображениях – это когда злоумышленники прячут вредоносный код внутри картинки, как шпион запихивает микрофильм в зубную щетку.
- Техники маскировки – это когда программа притворяется чем-то другим.
- Архивирование и сжатие – используют необычные форматы, как преступники – тайники в самых неожиданных местах.
- Кодирование данных – это когда информация зашифрована, как секретное послание, и нужно найти ключ.
- Составные файлы – это когда в одном файле смешано хорошее и плохое, как ядовитая конфета в красивой обертке.
Я научу вас не только находить эти уловки, но и понимать, почему злоумышленники их используют. Знание – это сила!
- Динамический анализ всегда проводится в изолированной среде – это как работа с биологическими образцами в лаборатории.
- Делайте снапшоты перед каждым экспериментом – на всякий случай, как делают бэкапы в фильмах про хакеров.
- Отключайте сеть при анализе неизвестного кода – не будете же вы разворачивать парашют, выпрыгивая из окна?
- Мониторьте все активности программы – как родители следят за ребенком, который первый раз пошел в школу.
- Документируйте каждый шаг анализа. Детектив без записок – не детектив вовсе!
Динамический анализ – это мощное оружие в руках аналитика безопасности. Используйте его разумно и всегда помните о безопасности!
До встречи в следующей статье, где мы изучим темную сторону: техники, которые используют злоумышленники для сокрытия своих программ!
Безопасность через понимание. Знание техник атаки – лучшая защита.