-
Notifications
You must be signed in to change notification settings - Fork 493
/
Copy pathbinary_linux.c
134 lines (113 loc) · 4.54 KB
/
binary_linux.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "binary.h"
#if defined(FF_HAVE_ELF) || defined(__sun) || (defined(__FreeBSD__) && !defined(__DragonFly__)) || defined(__OpenBSD__) || defined(__NetBSD__)
#include "common/io/io.h"
#include "common/library.h"
#include "util/stringUtils.h"
#include <libelf.h> // #1254
#include <fcntl.h>
/**
* 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;
/**
* 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.
*/
const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength)
{
// Initialize libelf if not already done
if (!elfData.inited)
{
elfData.inited = true;
FF_LIBRARY_LOAD(libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_version)
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed";
// 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;
}
if (elfData.ffelf_end == NULL)
return "load libelf failed";
// Open the ELF file
FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY, 0);
if (fd < 0) return "open() failed";
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL);
if (elf == NULL) return "elf_begin() failed";
// Get the section header string table index
size_t shstrndx = 0;
if (elfData.ffelf_getshdrstrndx(elf, &shstrndx) < 0)
{
elfData.ffelf_end(elf);
return "elf_getshdrstrndx() failed";
}
// Iterate through all sections, looking for .rodata which contains string literals
Elf_Scn* scn = NULL;
while ((scn = elfData.ffelf_nextscn(elf, scn)) != NULL)
{
// Try 64-bit section header first, then 32-bit if that fails
Elf64_Shdr* shdr64 = elfData.ffelf64_getshdr(scn);
Elf32_Shdr* shdr32 = NULL;
if (shdr64 == NULL)
{
shdr32 = elfData.ffelf32_getshdr(scn);
if (shdr32 == NULL) continue;
}
// 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);
if (name == NULL || !ffStrEquals(name, ".rodata")) continue;
// Get the section data
Elf_Data* data = elfData.ffelf_getdata(scn, NULL);
if (data == NULL) continue;
// Scan the section for string literals
for (size_t off = 0; off < data->d_size; ++off)
{
const char* p = (const char*) data->d_buf + off;
if (*p == '\0') continue;
uint32_t len = (uint32_t) strlen(p);
if (len < minLength) continue;
// Only process printable ASCII characters
if (*p >= ' ' && *p <= '~') // Ignore control characters
{
if (!cb(p, len, userdata)) break;
}
off += len;
}
break;
}
elfData.ffelf_end(elf);
return NULL;
}
#else
/**
* Fallback implementation when libelf is not available
*/
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);
return "Fastfetch was built without libelf support";
}
#endif