Files
fastfetch/src/common/impl/binary_linux.c
T

147 lines
4.8 KiB
C
Raw Normal View History

2026-01-06 09:48:38 +08:00
#include "common/binary.h"
2024-08-08 15:03:10 +08:00
2024-11-03 08:35:11 +08:00
#if defined(FF_HAVE_ELF) || defined(__sun) || (defined(__FreeBSD__) && !defined(__DragonFly__)) || defined(__OpenBSD__) || defined(__NetBSD__)
2024-08-08 15:03:10 +08:00
2026-03-29 09:28:49 +08:00
# include "common/io.h"
# include "common/library.h"
# include "common/stringUtils.h"
2024-08-08 15:03:10 +08:00
2026-03-29 09:28:49 +08:00
# include <libelf.h> // #1254
# include <fcntl.h>
2024-08-08 15:03:10 +08:00
2025-04-02 10:27:25 +08:00
/**
* Structure to hold dynamically loaded libelf function pointers
*/
struct FFElfData {
FF_LIBRARY_SYMBOL(elf_version)
FF_LIBRARY_SYMBOL(elf_begin)
FF_LIBRARY_SYMBOL(elf_getshdrstrndx)
FF_LIBRARY_SYMBOL(elf_nextscn)
FF_LIBRARY_SYMBOL(elf64_getshdr)
FF_LIBRARY_SYMBOL(elf32_getshdr)
FF_LIBRARY_SYMBOL(elf_getdata)
FF_LIBRARY_SYMBOL(elf_strptr)
FF_LIBRARY_SYMBOL(elf_end)
bool inited;
} elfData;
2025-04-02 10:27:25 +08:00
/**
* Extracts string literals from an ELF (Linux/Unix) binary file
*
* This function loads the libelf library dynamically, opens the ELF file,
* locates the .rodata section (which contains string literals), and
* scans it for valid strings. Each string found is passed to the
* callback function for processing.
*
* The function supports both 32-bit and 64-bit ELF formats.
*/
2026-03-29 09:28:49 +08:00
const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
2025-04-02 10:27:25 +08:00
// Initialize libelf if not already done
2026-03-29 09:28:49 +08:00
if (!elfData.inited) {
elfData.inited = true;
FF_LIBRARY_LOAD_MESSAGE(libelf, "libelf" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_version)
2026-03-29 09:28:49 +08:00
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) {
return "elf_version() failed";
}
2025-04-02 10:27:25 +08:00
// Load all required libelf functions
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_begin)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_getshdrstrndx)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_nextscn)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf64_getshdr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf32_getshdr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_getdata)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_strptr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_end)
libelf = NULL;
}
2026-03-29 09:28:49 +08:00
if (elfData.ffelf_end == NULL) {
return "load libelf failed";
2026-03-29 09:28:49 +08:00
}
2024-08-08 15:03:10 +08:00
2025-04-02 10:27:25 +08:00
// Open the ELF file
2025-06-19 22:41:30 +08:00
FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY | O_CLOEXEC);
2026-03-29 09:28:49 +08:00
if (fd < 0) {
return "open() failed";
}
2024-08-08 15:03:10 +08:00
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL);
2026-03-29 09:28:49 +08:00
if (elf == NULL) {
return "elf_begin() failed";
}
2024-08-08 15:03:10 +08:00
2025-04-02 10:27:25 +08:00
// Get the section header string table index
2024-08-08 15:03:10 +08:00
size_t shstrndx = 0;
2026-03-29 09:28:49 +08:00
if (elfData.ffelf_getshdrstrndx(elf, &shstrndx) < 0) {
elfData.ffelf_end(elf);
2024-08-08 15:03:10 +08:00
return "elf_getshdrstrndx() failed";
}
2025-04-02 10:27:25 +08:00
// Iterate through all sections, looking for .rodata which contains string literals
2024-08-08 15:03:10 +08:00
Elf_Scn* scn = NULL;
2026-03-29 09:28:49 +08:00
while ((scn = elfData.ffelf_nextscn(elf, scn)) != NULL) {
2025-04-02 10:27:25 +08:00
// Try 64-bit section header first, then 32-bit if that fails
Elf64_Shdr* shdr64 = elfData.ffelf64_getshdr(scn);
2024-08-08 15:03:10 +08:00
Elf32_Shdr* shdr32 = NULL;
2026-03-29 09:28:49 +08:00
if (shdr64 == NULL) {
shdr32 = elfData.ffelf32_getshdr(scn);
2026-03-29 09:28:49 +08:00
if (shdr32 == NULL) {
continue;
}
2024-08-08 15:03:10 +08:00
}
2025-04-02 10:27:25 +08:00
// Get the section name and check if it's .rodata
const char* name = elfData.ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name);
2026-03-29 09:28:49 +08:00
if (name == NULL || !ffStrEquals(name, ".rodata")) {
continue;
}
2024-08-08 15:03:10 +08:00
2025-04-02 10:27:25 +08:00
// Get the section data
Elf_Data* data = elfData.ffelf_getdata(scn, NULL);
2026-03-29 09:28:49 +08:00
if (data == NULL) {
continue;
}
2024-08-08 15:03:10 +08:00
2025-04-02 10:27:25 +08:00
// Scan the section for string literals
2026-03-29 09:28:49 +08:00
for (size_t off = 0; off < data->d_size; ++off) {
2024-08-08 15:03:10 +08:00
const char* p = (const char*) data->d_buf + off;
2026-03-29 09:28:49 +08:00
if (*p == '\0') {
continue;
}
2024-08-08 15:03:10 +08:00
uint32_t len = (uint32_t) strlen(p);
2026-03-29 09:28:49 +08:00
if (len < minLength) {
continue;
}
2025-04-02 10:27:25 +08:00
// Only process printable ASCII characters
2024-08-08 15:03:10 +08:00
if (*p >= ' ' && *p <= '~') // Ignore control characters
{
2026-03-29 09:28:49 +08:00
if (!cb(p, len, userdata)) {
break;
}
2024-08-08 15:03:10 +08:00
}
off += len;
}
break;
}
elfData.ffelf_end(elf);
2024-08-08 15:03:10 +08:00
return NULL;
}
#else
2025-04-02 10:27:25 +08:00
/**
* Fallback implementation when libelf is not available
*/
2026-03-29 09:28:49 +08:00
const char* ffBinaryExtractStrings(const char* file, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
FF_UNUSED(file, cb, userdata, minLength);
2024-08-08 15:03:10 +08:00
return "Fastfetch was built without libelf support";
}
#endif