Если я посмотрю на байты файла, то определенно увижу там имена некоторых функций. Есть ли какой-нибудь инструмент, который перечислит их для меня? Может быть, даже их параметры?
Это должно напечатать все определенные символы в вашем объектном файле или библиотеке.
nm -C --defined-only file.o
nm
имеет довольно много параметров, которые вы можно использовать для фильтрации символов, таких как -g
для отображения только глобальных символов
, -l
для печати номера строки (если вы использовали gcc -g
для включения символов отладки) и так далее.
Если у вас есть двоичный файл формата ELF (похоже, ваш случай), вы также можете использовать readelf
readelf -Ws file.o
Номер столбца 8 в этом выводе содержит имя символа, которое представляет интерес. Вы можете использовать c ++ filter
, чтобы распутать имя:
readelf -Ws file.o | awk '{print $ 8}' | c ++ filter
Как такие инструменты, как objdump, находят имена функций и их начальный адрес в двоичных файлах ELF?
Я написал парсер ELF, который разбирает раздел .text с помощью Capstone
моя проблема в том, что я не знаю, как сегментировать текстовый раздел на основе функций и распечатать имя функции. точно так же, как вывод objdump -d
, потому что objdump выводит так:
0x01000 func1:
0x01000 ..
0x01001 ..
как я могу узнать имя и начальный адрес каждой функции в .text, чтобы я мог выводить что-то вроде objdump?
Я попытался использовать строку, чтобы увидеть, хранятся ли имена где-нибудь в двоичном файле, например, в таблице символов, но не смог найти их где-нибудь в ней!
(примечание что я не говорю о функциях импорта и тому подобном, а только о функциях внутри фактического основного кода в разделе .text)
Для этого вам понадобятся некоторые знания о файлах ELF. Я не собираюсь подробно рассказывать о файлах ELF, так как их много, поэтому я постараюсь быть максимально точным.
ПРИМЕЧАНИЕ № 01: Я буду используйте radare2 для анализа файла, но вы можете сделать это с помощью любого шестнадцатеричного редактора.
ПРИМЕЧАНИЕ № 02: Вот ссылка на файл cpp, который я скомпилировать, чтобы объяснить вам файлы ELF. Не стесняйтесь брать или создавать свои собственные.
Во-первых, вам нужно знать структуру заголовков в файлах ELF. Здесь вы можете увидеть структуру заголовков.
Первое, что мы хотим найти, это e_ident
, который представляет формат файла (32-битный или 64-битный) поскольку заголовок файла будет отличаться в зависимости от формата файла.
e_ident offset = 0x04, size = 1byte
Перейдите к смещению файла 0x04 и проверьте один байт. ( s
означает поиск)
:> s 0x040x00000004 02
e_ident = 0x02 означает 64-битный формат.
Теперь, когда мы выбрали формат файла, нам нужно знать смещение заголовка раздела ( e_shoff
), размер каждой записи ( e_shentsize
) и количество записей в заголовке раздела ( e_shnum
).
e_shoff смещение = 0x28 size = 8 байтов
e_shentsize смещение = 0x3A size = 2 байта
e_shnum смещение = 0x3C size = 2 байта
:> s 0x280x00000028 e03b 0000 0000 0000:> s 0x3A0x0000003a 4000:> s 0x3C0x0000003c 1d00
e_shoff = 0x3be0 Это смещение заголовка раздела.
e_shentsize = 0x40 (64 байта)
e_shnum = 0x1d (29 записей)
Нам также понадобится индекс заголовка раздела, который содержит имена каждого заголовка раздела. Это хранилище в e_shstrndx
e_shstrndx offset = 0x3E size = 2bytes
:> s 0x3e0x0000003e 1c00
e_shstrndx = 0x1c (запись 28)
С номером записи вы можете получить адрес shstrtab:
//e_shoff + (e_shentsize * e_shstrndx) + sh_offset:> s 0x3be0 + (0x40 * 0x1c) + 0x180x000042f8 df3a 0000 0000 0000
shstrtab = 0x3adf
Теперь, когда у вас есть эта информация, вы можете запустить цикл, который проверяет все записи раздела:
//псевдокод для (i = 0; i
ПРИМЕЧАНИЕ # 03: I я не буду печатать эти значения здесь, потому что мне нужно объяснить больше, но это даст вам нечто похожее на команду readelf -W -l [program]
Каждая запись имеет структуру, подобную заголовку раздела. Чтобы получить имя каждой записи, добавьте sh_name
в shstrtab
Я просто покажу вам, как я получил .text
, но идея будет одинаковой для любой записи раздела. В моем случае .text
был записью 0x0e (14). Мне понадобится sh_name
, смещение в файле sh_offset
и размер sh_size
sh_name смещение = 0x00 size = 4 байта
sh_offset смещение = 0x18 size = 8 байтов
sh_size смещение = 0x20 размер = 8 байт
//e_shoff + (e_shentsize * e_shstrndx) + sh_name:> s 0x3be0 + (0x40 * 0x0e) + 0x000x00003f60 9d00 0000//Получаем имя:> s 0x3adf + 0x9d0x00003b7c 2e74 6578 7400 2e66 696e 6900 2e72 6f64 .text..fini..rod//e_shoff + (e_shentsize * e_shstrndset> + 0_shstrndset) (0x40 * 0x0e) + 0x180x00003f78 9010 0000 0000 0000//e_shoff + (e_shentsize * e_shstrndx) + sh_size:> s 0x3be0 + (0x40 * 0x0e) + 0x200x00003f80 3102 0000 0000 0000
entry = 0x3be0//.text
sh_offset = 0x1090
sh_size = 0x0231 (561bytes)
Если вы не можете найти его таким образом, тогда ваш ELF-файл должен быть поврежден. Вы можете взять тот, который я собрал, чтобы следовать этому объяснению. Удачи.