mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
Binary: add comments
This commit is contained in:
@@ -2,4 +2,17 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
/**
|
||||
* Extracts string literals from a binary file
|
||||
*
|
||||
* @param file Path to the binary file to extract strings from
|
||||
* @param cb Callback function that will be called for each string found
|
||||
* Return false from callback to stop extraction
|
||||
* @param userdata User-provided data passed to the callback function
|
||||
* @param minLength Minimum length of strings to extract
|
||||
*
|
||||
* @return NULL on success, error message on failure.
|
||||
* @note This function won't return an error if no strings are found.
|
||||
* Always check if strings are correctly extracted after this function all.
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char* file, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength);
|
||||
|
||||
@@ -14,12 +14,28 @@
|
||||
|
||||
// Ref: https://github.com/AlexDenisov/segment_dumper/blob/master/main.c
|
||||
|
||||
/**
|
||||
* Helper function to read data from a file at a specific offset
|
||||
*/
|
||||
static inline bool readData(FILE *objFile, void *buf, size_t size, off_t offset)
|
||||
{
|
||||
fseek(objFile, offset, SEEK_SET);
|
||||
return fread(buf, 1, size, objFile) == size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a Mach-O section by extracting strings from the __cstring section
|
||||
*
|
||||
* @param objFile File handle to the Mach-O object file
|
||||
* @param name Section name to check
|
||||
* @param offset Offset of the section in the file
|
||||
* @param size Size of the section
|
||||
* @param cb Callback function to process strings
|
||||
* @param userdata User data for the callback
|
||||
* @param minLength Minimum string length to extract
|
||||
*
|
||||
* @return true to continue processing, false to stop
|
||||
*/
|
||||
static bool handleMachSection(FILE *objFile, const char *name, off_t offset, size_t size, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
if (!ffStrEquals(name, "__cstring")) return true;
|
||||
@@ -43,6 +59,22 @@ static bool handleMachSection(FILE *objFile, const char *name, off_t offset, siz
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a Mach-O header (32-bit or 64-bit)
|
||||
*
|
||||
* This function parses the load commands in a Mach-O header, looking for
|
||||
* LC_SEGMENT or LC_SEGMENT_64 commands that contain the __TEXT segment.
|
||||
* It then processes the sections within that segment to extract strings.
|
||||
*
|
||||
* @param objFile File handle to the Mach-O object file
|
||||
* @param offset Offset of the Mach header in the file
|
||||
* @param is_64 Whether this is a 64-bit Mach-O header
|
||||
* @param cb Callback function to process strings
|
||||
* @param userdata User data for the callback
|
||||
* @param minLength Minimum string length to extract
|
||||
*
|
||||
* @return NULL on success, error message on failure
|
||||
*/
|
||||
static const char* dumpMachHeader(FILE *objFile, off_t offset, bool is_64, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
uint32_t ncmds;
|
||||
@@ -117,6 +149,20 @@ static const char* dumpMachHeader(FILE *objFile, off_t offset, bool is_64, bool
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a Fat binary header (Universal binary)
|
||||
*
|
||||
* This function handles the fat header of a universal binary, which can contain
|
||||
* multiple Mach-O binaries for different architectures. It extracts and processes
|
||||
* each embedded Mach-O file.
|
||||
*
|
||||
* @param objFile File handle to the universal binary
|
||||
* @param cb Callback function to process strings
|
||||
* @param userdata User data for the callback
|
||||
* @param minLength Minimum string length to extract
|
||||
*
|
||||
* @return NULL on success, error message on failure
|
||||
*/
|
||||
static const char* dumpFatHeader(FILE *objFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
struct fat_header header;
|
||||
@@ -165,21 +211,32 @@ static const char* dumpFatHeader(FILE *objFile, bool (*cb)(const char *str, uint
|
||||
return "Unsupported fat header";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts string literals from a Mach-O (Apple) binary file
|
||||
*
|
||||
* This function supports both single-architecture Mach-O files and
|
||||
* universal binaries (fat binaries) containing multiple architectures.
|
||||
* It locates the __cstring section in the __TEXT segment which contains
|
||||
* the string literals used in the program.
|
||||
*/
|
||||
const char *ffBinaryExtractStrings(const char *machoFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
FF_AUTO_CLOSE_FILE FILE *objFile = fopen(machoFile, "rb");
|
||||
if (objFile == NULL)
|
||||
return "File could not be opened";
|
||||
|
||||
// Read the magic number to determine the type of binary
|
||||
uint32_t magic;
|
||||
if (!readData(objFile, &magic, sizeof(magic), 0))
|
||||
return "read magic number failed";
|
||||
|
||||
// Check for supported formats
|
||||
// MH_CIGAM and MH_CIGAM_64 seem to be no longer used, as `swap_mach_header` is marked as deprecated.
|
||||
// However FAT_CIGAM and FAT_CIGAM_64 are still used (/usr/bin/vim).
|
||||
if (magic != MH_MAGIC && magic != MH_MAGIC_64 && magic != FAT_CIGAM && magic != FAT_CIGAM_64 && magic != FAT_MAGIC && magic != FAT_MAGIC_64)
|
||||
return "Unsupported format or big endian mach-o file";
|
||||
|
||||
// Process either a fat binary or a regular Mach-O binary
|
||||
if (magic == FAT_MAGIC || magic == FAT_MAGIC_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64)
|
||||
return dumpFatHeader(objFile, cb, userdata, minLength);
|
||||
else
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#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)
|
||||
@@ -23,8 +26,19 @@ struct FFElfData {
|
||||
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;
|
||||
@@ -32,6 +46,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
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)
|
||||
@@ -47,12 +62,14 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
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)
|
||||
{
|
||||
@@ -60,9 +77,11 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
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)
|
||||
@@ -71,18 +90,22 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
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;
|
||||
@@ -99,6 +122,9 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
|
||||
#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);
|
||||
|
||||
@@ -8,25 +8,37 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Extracts string literals from a PE (Windows) executable
|
||||
*
|
||||
* This function maps the PE file into memory, locates the .rdata section
|
||||
* (which typically contains string literals), and scans it for valid strings.
|
||||
* Each string found is passed to the callback function for processing.
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
// Use MapAndLoad with cleanup attribute to ensure proper unloading
|
||||
__attribute__((__cleanup__(UnMapAndLoad))) LOADED_IMAGE loadedImage = {};
|
||||
if (!MapAndLoad(peFile, NULL, &loadedImage, FALSE, TRUE))
|
||||
return "File could not be loaded";
|
||||
|
||||
// Iterate through all sections in the PE file
|
||||
for (ULONG i = 0; i < loadedImage.NumberOfSections; ++i)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER section = &loadedImage.Sections[i];
|
||||
// Look for initialized data sections with the name ".rdata" which typically contains string literals
|
||||
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata"))
|
||||
{
|
||||
uint8_t *data = (uint8_t *) loadedImage.MappedAddress + section->PointerToRawData;
|
||||
|
||||
// Scan the section for string literals
|
||||
for (size_t off = 0; off < section->SizeOfRawData; ++off)
|
||||
{
|
||||
const char* p = (const char*) data + 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;
|
||||
|
||||
Reference in New Issue
Block a user