# Анализ исполняемого файла

ldd ./program

```
$ ldd /bin/ls
        linux-vdso.so.1 (0x00007fff2b9fe000)
        libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f3cdd5b3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3cdd1b0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3cdd7e0000)
```

Показывает список динамических библиотек, которые будут загружены при запуске программы.  
ldd фактически выполняет часть программы через загрузчик, нельзя запускать ldd на подозрительных бинарниках.

readelf -d  
Читает динамическую таблицу ELF-файла и показывает список библиотек, от которых он зависит.

```
$ readelf -d /usr/bin/mate-calc | grep NEEDED
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libgtk-3.so.0]
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libgdk-3.so.0]
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libpango-1.0.so.0]
 0x0000000000000001 (NEEDED)             Совм. исп. библиотека: [libatk-1.0.so.0]
```

objdump -p

Аналогично readelf, но может показать больше контекста.

```
objdump -p /usr/bin/mate-calc | grep NEEDED                                                                                 
  NEEDED               libgtk-3.so.0
  NEEDED               libgdk-3.so.0
  NEEDED               libpango-1.0.so.0
  NEEDED               libatk-1.0.so.0
```

В рантайме — strace

Если вы хотите узнать, какие библиотеки реально подгружаются при запуске (в том числе через dlopen() во время работы):

```
strace -e open ./program 2>&1 | grep '\.so'
```

Если программа статически слинкована (т.е. все зависимости включены внутрь ELF), то ни ldd, ни readelf не покажут зависимостей.

Проверить это можно так:

```
file ./program
```

**Пример:**

```
# динамическая линковка
file /usr/bin/mate-calc                                                                                                     
/usr/bin/mate-calc: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=58d991a9b15b10d59d235c79b2132fde101cf1fc, for GNU/Linux 3.2.0, stripped

# статическая линковка
... statically linked ...
```

Пример анализа зависимостей для /usr/bin/grep.

1\. Проверим, какой это тип ELF-файла

```
file /usr/bin/grep
/usr/bin/grep: ELF 64-bit LSB executable, x86-64, dynamically linked, interpreter \
/lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped
```

Значит, это динамически слинкованный ELF, и у него есть внешние зависимости.

2\. Смотрим список зависимостей через ldd

```
ldd /usr/bin/grep
        linux-vdso.so.1 (0x00007fff43dfe000)
        libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f3f5a8b0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3f5a4a0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3f5aaf0000)
```

Интерпретация:

- libpcre2-8.so.0 — библиотека регулярных выражений PCRE2.
- libc.so.6 — стандартная библиотека C (glibc).
- ld-linux-x86-64.so.2 — динамический загрузчик ELF.

3\. Альтернатива: readelf -d

```
readelf -d /usr/bin/grep | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libpcre2-8.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
```

Это подтверждает те же зависимости.

4\. Проверим, какие библиотеки реально подгружаются при запуске (в том числе через dlopen())

```
strace -e openat /usr/bin/grep "test" /etc/passwd 2>&1 | grep '\.so'
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
```

5\. Проверим динамический загрузчик (интерпретатор ELF)

```
readelf -l /usr/bin/grep | grep 'interpreter'
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
```

Это та программа, которая первым делом загружает бинарь и его библиотеки.

Итог:

<table id="bkmrk-%D0%A2%D0%B8%D0%BF-%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B8-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC"><thead><tr><th>Тип проверки</th><th>Инструмент</th><th>Что показывает</th></tr></thead><tbody><tr><td>Тип ELF</td><td>`file`</td><td>Статически или динамически слинкован</td></tr><tr><td>Динамические зависимости</td><td>`ldd`, `readelf -d`, `objdump -p`</td><td>Список библиотек</td></tr><tr><td>Реальные загрузки во время работы</td><td>`strace`</td><td>Библиотеки, подгружаемые во время исполнения</td></tr><tr><td>ELF-интерпретатор</td><td>`readelf -l`</td><td>Путь к динамическому загрузчику</td></tr></tbody></table>

Можно проверить, какие именно функции приложение импортирует из библиотек.

Теперь углубимся на уровень **символов (функций)**, которые исполняемый файл импортирует из библиотек — например, какие функции `grep` реально использует из `libc`, `libpcre2` и других.

**1. Проверим импортированные символы (динамически загружаемые функции)**

Для этого можно использовать:

```bash
readelf -Ws /usr/bin/grep | grep ' UND '

```

или короче:

```bash
readelf -Ws /usr/bin/grep | grep UND | less

```

- `-W` — показывает полные строки.
- `-s` — выводит таблицу символов.
- `UND` означает *undefined symbol* — то есть функция **определена в внешней библиотеке** (т.е. импортируется).

---

Пример вывода (сокращённо)

```
Num:    Value  Size Type    Bind   Vis      Ndx Name
  45: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strcmp@GLIBC_2.2.5
  72: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND malloc@GLIBC_2.2.5
  89: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND regexec@LIBPCRE2_8
 114: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.2.5
 132: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fprintf@GLIBC_2.2.5

```

**Расшифровка:**

- `strcmp`, `malloc`, `free`, `fprintf` → из `libc`
- `regexec` → из `libpcre2-8.so.0`

---

2\. Посчитать, сколько внешних символов программа импортирует

Можно примерно оценить так:

```bash
readelf -Ws /usr/bin/grep | grep ' UND ' | wc -l

```

Например, может вывести:

```
125

```

значит, `grep` использует около 125 внешних функций из библиотек.

---

3\. Уточнить, из какой именно библиотеки берётся символ

Команда `ldd` показывает пути библиотек, а `readelf` — имена функций, но если ты хочешь **увидеть, какой именно `.so` экспортирует нужную функцию**, можно воспользоваться `objdump` или `nm`.

Пример: узнать, где определена функция `regexec`

```bash
for lib in /lib/x86_64-linux-gnu/*.so*; do
    nm -D $lib 2>/dev/null | grep ' regexec$' && echo "→ $lib"
done

```

**Результат:**

```
000000000001f230 T regexec
→ /lib/x86_64-linux-gnu/libpcre2-8.so.0

```

---

4\. Альтернатива: `objdump -T`

Если хочешь посмотреть **все экспортируемые символы библиотеки**:

```bash
objdump -T /lib/x86_64-linux-gnu/libc.so.6 | grep printf

```

Это покажет строку вроде:

```
0000000000054350 g    DF .text  00000000000001a5  GLIBC_2.2.5 printf

```

 Резюме

<table id="bkmrk-%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0-%D0%9A%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-%D0%A7%D1%82%D0%BE-%D0%BF"><thead><tr><th>Задача</th><th>Команда</th><th>Что показывает</th></tr></thead><tbody><tr><td>Список импортированных функций</td><td>`readelf -Ws program</td><td>grep UND`</td></tr><tr><td>Кол-во импортов</td><td>`readelf -Ws program</td><td>grep UND</td></tr><tr><td>Где определён символ</td><td>`nm -D /lib/...</td><td>grep &lt;имя&gt;`</td></tr><tr><td>Все экспортируемые символы из .so</td><td>`objdump -T libname.so`</td><td>Список функций, предоставляемых библиотекой</td></tr></tbody></table>

---