11cb0ef41Sopenharmony_ci#ifndef POSTJECT_API_H_ 21cb0ef41Sopenharmony_ci#define POSTJECT_API_H_ 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ci#include <stdbool.h> 51cb0ef41Sopenharmony_ci#include <stddef.h> 61cb0ef41Sopenharmony_ci#include <stdlib.h> 71cb0ef41Sopenharmony_ci#include <string.h> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#if defined(__APPLE__) && defined(__MACH__) 101cb0ef41Sopenharmony_ci#include <mach-o/dyld.h> 111cb0ef41Sopenharmony_ci#include <mach-o/getsect.h> 121cb0ef41Sopenharmony_ci#elif defined(__linux__) 131cb0ef41Sopenharmony_ci#include <elf.h> 141cb0ef41Sopenharmony_ci#include <link.h> 151cb0ef41Sopenharmony_ci#include <sys/param.h> 161cb0ef41Sopenharmony_ci#elif defined(_WIN32) 171cb0ef41Sopenharmony_ci#include <windows.h> 181cb0ef41Sopenharmony_ci#endif 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci#ifndef POSTJECT_SENTINEL_FUSE 211cb0ef41Sopenharmony_ci#define POSTJECT_SENTINEL_FUSE \ 221cb0ef41Sopenharmony_ci "POSTJECT_SENTINEL_fce680ab2cc467b6e072b8b5df1996b2" 231cb0ef41Sopenharmony_ci#endif 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_cistruct postject_options { 261cb0ef41Sopenharmony_ci const char* elf_section_name; 271cb0ef41Sopenharmony_ci const char* macho_framework_name; 281cb0ef41Sopenharmony_ci const char* macho_section_name; 291cb0ef41Sopenharmony_ci const char* macho_segment_name; 301cb0ef41Sopenharmony_ci const char* pe_resource_name; 311cb0ef41Sopenharmony_ci}; 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciinline void postject_options_init(struct postject_options* options) { 341cb0ef41Sopenharmony_ci options->elf_section_name = NULL; 351cb0ef41Sopenharmony_ci options->macho_framework_name = NULL; 361cb0ef41Sopenharmony_ci options->macho_section_name = NULL; 371cb0ef41Sopenharmony_ci options->macho_segment_name = NULL; 381cb0ef41Sopenharmony_ci options->pe_resource_name = NULL; 391cb0ef41Sopenharmony_ci} 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_cistatic inline bool postject_has_resource() { 421cb0ef41Sopenharmony_ci static const volatile char* sentinel = POSTJECT_SENTINEL_FUSE ":0"; 431cb0ef41Sopenharmony_ci return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1'; 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci#if defined(__linux__) 471cb0ef41Sopenharmony_cistatic int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, 481cb0ef41Sopenharmony_ci size_t size, 491cb0ef41Sopenharmony_ci void* data) { 501cb0ef41Sopenharmony_ci // Snag the dl_phdr_info struct for the main program, then stop iterating 511cb0ef41Sopenharmony_ci *((struct dl_phdr_info*)data) = *info; 521cb0ef41Sopenharmony_ci return 1; 531cb0ef41Sopenharmony_ci} 541cb0ef41Sopenharmony_ci#endif 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_cistatic const void* postject_find_resource( 571cb0ef41Sopenharmony_ci const char* name, 581cb0ef41Sopenharmony_ci size_t* size, 591cb0ef41Sopenharmony_ci const struct postject_options* options) { 601cb0ef41Sopenharmony_ci // Always zero out the size pointer to start 611cb0ef41Sopenharmony_ci if (size != NULL) { 621cb0ef41Sopenharmony_ci *size = 0; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci#if defined(__APPLE__) && defined(__MACH__) 661cb0ef41Sopenharmony_ci char* section_name = NULL; 671cb0ef41Sopenharmony_ci const char* segment_name = "__POSTJECT"; 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci if (options != NULL && options->macho_segment_name != NULL) { 701cb0ef41Sopenharmony_ci segment_name = options->macho_segment_name; 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci if (options != NULL && options->macho_section_name != NULL) { 741cb0ef41Sopenharmony_ci name = options->macho_section_name; 751cb0ef41Sopenharmony_ci } else if (strncmp(name, "__", 2) != 0) { 761cb0ef41Sopenharmony_ci // Automatically prepend __ to match naming convention 771cb0ef41Sopenharmony_ci section_name = (char*)malloc(strlen(name) + 3); 781cb0ef41Sopenharmony_ci if (section_name == NULL) { 791cb0ef41Sopenharmony_ci return NULL; 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci strcpy(section_name, "__"); 821cb0ef41Sopenharmony_ci strcat(section_name, name); 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci unsigned long section_size; 861cb0ef41Sopenharmony_ci char* ptr = NULL; 871cb0ef41Sopenharmony_ci if (options != NULL && options->macho_framework_name != NULL) { 881cb0ef41Sopenharmony_ci#ifdef __clang__ 891cb0ef41Sopenharmony_ci#pragma clang diagnostic push 901cb0ef41Sopenharmony_ci#pragma clang diagnostic ignored "-Wdeprecated-declarations" 911cb0ef41Sopenharmony_ci#endif 921cb0ef41Sopenharmony_ci ptr = getsectdatafromFramework(options->macho_framework_name, segment_name, 931cb0ef41Sopenharmony_ci section_name != NULL ? section_name : name, 941cb0ef41Sopenharmony_ci §ion_size); 951cb0ef41Sopenharmony_ci } else { 961cb0ef41Sopenharmony_ci ptr = getsectdata(segment_name, section_name != NULL ? section_name : name, 971cb0ef41Sopenharmony_ci §ion_size); 981cb0ef41Sopenharmony_ci#ifdef __clang__ 991cb0ef41Sopenharmony_ci#pragma clang diagnostic pop 1001cb0ef41Sopenharmony_ci#endif 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci if (ptr != NULL) { 1031cb0ef41Sopenharmony_ci // Add the "virtual memory address slide" amount to ensure a valid pointer 1041cb0ef41Sopenharmony_ci // in cases where the virtual memory address have been adjusted by the OS. 1051cb0ef41Sopenharmony_ci // 1061cb0ef41Sopenharmony_ci // NOTE - `getsectdataFromFramework` already handles this adjustment for 1071cb0ef41Sopenharmony_ci // us, which is why we only do it for `getsectdata`, see: 1081cb0ef41Sopenharmony_ci // https://web.archive.org/web/20220613234007/https://opensource.apple.com/source/cctools/cctools-590/libmacho/getsecbyname.c.auto.html 1091cb0ef41Sopenharmony_ci ptr += _dyld_get_image_vmaddr_slide(0); 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci free(section_name); 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci if (size != NULL) { 1161cb0ef41Sopenharmony_ci *size = (size_t)section_size; 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci return ptr; 1201cb0ef41Sopenharmony_ci#elif defined(__linux__) 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci if (options != NULL && options->elf_section_name != NULL) { 1231cb0ef41Sopenharmony_ci name = options->elf_section_name; 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci struct dl_phdr_info main_program_info; 1271cb0ef41Sopenharmony_ci dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr; 1301cb0ef41Sopenharmony_ci size_t n = main_program_info.dlpi_phnum; 1311cb0ef41Sopenharmony_ci uintptr_t base_addr = main_program_info.dlpi_addr; 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci // iterate program header 1341cb0ef41Sopenharmony_ci for (; n > 0; n--, p += sizeof(ElfW(Phdr))) { 1351cb0ef41Sopenharmony_ci ElfW(Phdr)* phdr = (ElfW(Phdr)*)p; 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci // skip everything but notes 1381cb0ef41Sopenharmony_ci if (phdr->p_type != PT_NOTE) { 1391cb0ef41Sopenharmony_ci continue; 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci // note segment starts at base address + segment virtual address 1431cb0ef41Sopenharmony_ci uintptr_t pos = (base_addr + phdr->p_vaddr); 1441cb0ef41Sopenharmony_ci uintptr_t end = (pos + phdr->p_memsz); 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci // iterate through segment until we reach the end 1471cb0ef41Sopenharmony_ci while (pos < end) { 1481cb0ef41Sopenharmony_ci if (pos + sizeof(ElfW(Nhdr)) > end) { 1491cb0ef41Sopenharmony_ci break; // invalid 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos; 1531cb0ef41Sopenharmony_ci if (note->n_namesz != 0 && note->n_descsz != 0 && 1541cb0ef41Sopenharmony_ci strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name, 1551cb0ef41Sopenharmony_ci sizeof(name)) == 0) { 1561cb0ef41Sopenharmony_ci *size = note->n_descsz; 1571cb0ef41Sopenharmony_ci // advance past note header and aligned name 1581cb0ef41Sopenharmony_ci // to get to description data 1591cb0ef41Sopenharmony_ci return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + 1601cb0ef41Sopenharmony_ci roundup(note->n_namesz, 4)); 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + 1641cb0ef41Sopenharmony_ci roundup(note->n_descsz, 4)); 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci return NULL; 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci#elif defined(_WIN32) 1701cb0ef41Sopenharmony_ci void* ptr = NULL; 1711cb0ef41Sopenharmony_ci char* resource_name = NULL; 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci if (options != NULL && options->pe_resource_name != NULL) { 1741cb0ef41Sopenharmony_ci name = options->pe_resource_name; 1751cb0ef41Sopenharmony_ci } else { 1761cb0ef41Sopenharmony_ci // Automatically uppercase the resource name or it won't be found 1771cb0ef41Sopenharmony_ci resource_name = (char*)malloc(strlen(name) + 1); 1781cb0ef41Sopenharmony_ci if (resource_name == NULL) { 1791cb0ef41Sopenharmony_ci return NULL; 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci strcpy_s(resource_name, strlen(name) + 1, name); 1821cb0ef41Sopenharmony_ci CharUpperA(resource_name); // Uppercases inplace 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci HRSRC resource_handle = 1861cb0ef41Sopenharmony_ci FindResourceA(NULL, resource_name != NULL ? resource_name : name, 1871cb0ef41Sopenharmony_ci MAKEINTRESOURCEA(10) /* RT_RCDATA */); 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci if (resource_handle) { 1901cb0ef41Sopenharmony_ci HGLOBAL global_resource_handle = LoadResource(NULL, resource_handle); 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci if (global_resource_handle) { 1931cb0ef41Sopenharmony_ci if (size != NULL) { 1941cb0ef41Sopenharmony_ci *size = SizeofResource(NULL, resource_handle); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci ptr = LockResource(global_resource_handle); 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci free(resource_name); 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci return ptr; 2041cb0ef41Sopenharmony_ci#else 2051cb0ef41Sopenharmony_ci return NULL; 2061cb0ef41Sopenharmony_ci#endif 2071cb0ef41Sopenharmony_ci} 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci#endif // POSTJECT_API_H_ 210