Skip to content

Commit

Permalink
Refactor build configuration and update injection options
Browse files Browse the repository at this point in the history
  • Loading branch information
xicilion committed Oct 16, 2024
1 parent 22c9d84 commit 589b4cc
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 432 deletions.
272 changes: 135 additions & 137 deletions include/postject-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,192 +18,190 @@
#endif

#ifndef POSTJECT_SENTINEL_FUSE
#define POSTJECT_SENTINEL_FUSE \
"POSTJECT_SENTINEL_fce680ab2cc467b6e072b8b5df1996b2"
#define POSTJECT_SENTINEL_FUSE "FIBINJECT_SENTINEL_d0695dd05effa072dcb0b1f8f807ac40"
#endif

struct postject_options {
const char* elf_section_name;
const char* macho_framework_name;
const char* macho_section_name;
const char* macho_segment_name;
const char* pe_resource_name;
const char* elf_section_name;
const char* macho_framework_name;
const char* macho_section_name;
const char* macho_segment_name;
const char* pe_resource_name;
};

inline void postject_options_init(struct postject_options* options) {
options->elf_section_name = NULL;
options->macho_framework_name = NULL;
options->macho_section_name = NULL;
options->macho_segment_name = NULL;
options->pe_resource_name = NULL;
inline void postject_options_init(struct postject_options* options)
{
options->elf_section_name = NULL;
options->macho_framework_name = NULL;
options->macho_section_name = NULL;
options->macho_segment_name = NULL;
options->pe_resource_name = NULL;
}

static inline bool postject_has_resource() {
static const volatile char* sentinel = POSTJECT_SENTINEL_FUSE ":0";
return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1';
static inline bool postject_has_resource()
{
static const volatile char* sentinel = POSTJECT_SENTINEL_FUSE ":0";
return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1';
}

#if defined(__linux__)
static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info,
size_t size,
void* data) {
// Snag the dl_phdr_info struct for the main program, then stop iterating
*((struct dl_phdr_info*)data) = *info;
return 1;
size_t size,
void* data)
{
// Snag the dl_phdr_info struct for the main program, then stop iterating
*((struct dl_phdr_info*)data) = *info;
return 1;
}
#endif

static const void* postject_find_resource(
const char* name,
size_t* size,
const struct postject_options* options) {
// Always zero out the size pointer to start
if (size != NULL) {
*size = 0;
}
const struct postject_options* options)
{
// Always zero out the size pointer to start
if (size != NULL) {
*size = 0;
}

#if defined(__APPLE__) && defined(__MACH__)
char* section_name = NULL;
const char* segment_name = "__POSTJECT";

if (options != NULL && options->macho_segment_name != NULL) {
segment_name = options->macho_segment_name;
}

if (options != NULL && options->macho_section_name != NULL) {
name = options->macho_section_name;
} else if (strncmp(name, "__", 2) != 0) {
// Automatically prepend __ to match naming convention
section_name = (char*)malloc(strlen(name) + 3);
if (section_name == NULL) {
return NULL;
char* section_name = NULL;
const char* segment_name = "__FIBINJECT";

if (options != NULL && options->macho_segment_name != NULL) {
segment_name = options->macho_segment_name;
}
strcpy(section_name, "__");
strcat(section_name, name);
}

unsigned long section_size;
char* ptr = NULL;
if (options != NULL && options->macho_framework_name != NULL) {
if (options != NULL && options->macho_section_name != NULL) {
name = options->macho_section_name;
} else if (strncmp(name, "__", 2) != 0) {
// Automatically prepend __ to match naming convention
section_name = (char*)malloc(strlen(name) + 3);
if (section_name == NULL) {
return NULL;
}
strcpy(section_name, "__");
strcat(section_name, name);
}

unsigned long section_size;
char* ptr = NULL;
if (options != NULL && options->macho_framework_name != NULL) {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
ptr = getsectdatafromFramework(options->macho_framework_name, segment_name,
section_name != NULL ? section_name : name,
&section_size);
} else {
ptr = getsectdata(segment_name, section_name != NULL ? section_name : name,
&section_size);
ptr = getsectdatafromFramework(options->macho_framework_name, segment_name,
section_name != NULL ? section_name : name,
&section_size);
} else {
ptr = getsectdata(segment_name, section_name != NULL ? section_name : name,
&section_size);
#ifdef __clang__
#pragma clang diagnostic pop
#endif

if (ptr != NULL) {
// Add the "virtual memory address slide" amount to ensure a valid pointer
// in cases where the virtual memory address have been adjusted by the OS.
//
// NOTE - `getsectdataFromFramework` already handles this adjustment for
// us, which is why we only do it for `getsectdata`, see:
// https://web.archive.org/web/20220613234007/https://opensource.apple.com/source/cctools/cctools-590/libmacho/getsecbyname.c.auto.html
ptr += _dyld_get_image_vmaddr_slide(0);
if (ptr != NULL) {
// Add the "virtual memory address slide" amount to ensure a valid pointer
// in cases where the virtual memory address have been adjusted by the OS.
//
// NOTE - `getsectdataFromFramework` already handles this adjustment for
// us, which is why we only do it for `getsectdata`, see:
// https://web.archive.org/web/20220613234007/https://opensource.apple.com/source/cctools/cctools-590/libmacho/getsecbyname.c.auto.html
ptr += _dyld_get_image_vmaddr_slide(0);
}
}
}

free(section_name);
free(section_name);

if (size != NULL) {
*size = (size_t)section_size;
}
if (size != NULL) {
*size = (size_t)section_size;
}

return ptr;
return ptr;
#elif defined(__linux__)

if (options != NULL && options->elf_section_name != NULL) {
name = options->elf_section_name;
}

struct dl_phdr_info main_program_info;
dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info);

uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr;
size_t n = main_program_info.dlpi_phnum;
uintptr_t base_addr = main_program_info.dlpi_addr;

// iterate program header
for (; n > 0; n--, p += sizeof(ElfW(Phdr))) {
ElfW(Phdr)* phdr = (ElfW(Phdr)*)p;

// skip everything but notes
if (phdr->p_type != PT_NOTE) {
continue;
if (options != NULL && options->elf_section_name != NULL) {
name = options->elf_section_name;
}

// note segment starts at base address + segment virtual address
uintptr_t pos = (base_addr + phdr->p_vaddr);
uintptr_t end = (pos + phdr->p_memsz);

// iterate through segment until we reach the end
while (pos < end) {
if (pos + sizeof(ElfW(Nhdr)) > end) {
break; // invalid
}

ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos;
if (note->n_namesz != 0 && note->n_descsz != 0 &&
strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name,
sizeof(name)) == 0) {
*size = note->n_descsz;
// advance past note header and aligned name
// to get to description data
return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) +
roundup(note->n_namesz, 4));
}

pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) +
roundup(note->n_descsz, 4));
struct dl_phdr_info main_program_info;
dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info);

uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr;
size_t n = main_program_info.dlpi_phnum;
uintptr_t base_addr = main_program_info.dlpi_addr;

// iterate program header
for (; n > 0; n--, p += sizeof(ElfW(Phdr))) {
ElfW(Phdr)* phdr = (ElfW(Phdr)*)p;

// skip everything but notes
if (phdr->p_type != PT_NOTE) {
continue;
}

// note segment starts at base address + segment virtual address
uintptr_t pos = (base_addr + phdr->p_vaddr);
uintptr_t end = (pos + phdr->p_memsz);

// iterate through segment until we reach the end
while (pos < end) {
if (pos + sizeof(ElfW(Nhdr)) > end) {
break; // invalid
}

ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos;
if (note->n_namesz != 0 && note->n_descsz != 0 && strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name, sizeof(name)) == 0) {
*size = note->n_descsz;
// advance past note header and aligned name
// to get to description data
return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4));
}

pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + roundup(note->n_descsz, 4));
}
}
}
return NULL;
return NULL;

#elif defined(_WIN32)
void* ptr = NULL;
char* resource_name = NULL;

if (options != NULL && options->pe_resource_name != NULL) {
name = options->pe_resource_name;
} else {
// Automatically uppercase the resource name or it won't be found
resource_name = (char*)malloc(strlen(name) + 1);
if (resource_name == NULL) {
return NULL;
void* ptr = NULL;
char* resource_name = NULL;

if (options != NULL && options->pe_resource_name != NULL) {
name = options->pe_resource_name;
} else {
// Automatically uppercase the resource name or it won't be found
resource_name = (char*)malloc(strlen(name) + 1);
if (resource_name == NULL) {
return NULL;
}
strcpy_s(resource_name, strlen(name) + 1, name);
CharUpperA(resource_name); // Uppercases inplace
}
strcpy_s(resource_name, strlen(name) + 1, name);
CharUpperA(resource_name); // Uppercases inplace
}

HRSRC resource_handle =
FindResourceA(NULL, resource_name != NULL ? resource_name : name,
MAKEINTRESOURCEA(10) /* RT_RCDATA */);
HRSRC resource_handle = FindResourceA(NULL, resource_name != NULL ? resource_name : name,
MAKEINTRESOURCEA(10) /* RT_RCDATA */);

if (resource_handle) {
HGLOBAL global_resource_handle = LoadResource(NULL, resource_handle);
if (resource_handle) {
HGLOBAL global_resource_handle = LoadResource(NULL, resource_handle);

if (global_resource_handle) {
if (size != NULL) {
*size = SizeofResource(NULL, resource_handle);
}
if (global_resource_handle) {
if (size != NULL) {
*size = SizeofResource(NULL, resource_handle);
}

ptr = LockResource(global_resource_handle);
ptr = LockResource(global_resource_handle);
}
}
}

free(resource_name);
free(resource_name);

return ptr;
return ptr;
#else
return NULL;
return NULL;
#endif
}

#endif // POSTJECT_API_H_
#endif // POSTJECT_API_H_
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ const path = require('path');

module.exports = inject = require(`./addon/${path.basename(__dirname)}.node`);
module.exports.inject = function (filename, resourceName, resourceData, options) {
const machoSegmentName = options?.machoSegmentName || "__POSTJECT";
const machoSegmentName = options?.machoSegmentName || "__FIBINJECT";
const overwrite = options?.overwrite || false;
let sentinelFuse = options?.sentinelFuse || "POSTJECT_SENTINEL_fce680ab2cc467b6e072b8b5df1996b2";
let sentinelFuse = options?.sentinelFuse || "FIBINJECT_SENTINEL_d0695dd05effa072dcb0b1f8f807ac40";

if (!Buffer.isBuffer(resourceData)) {
throw new TypeError("resourceData must be a buffer");
Expand Down
Loading

0 comments on commit 589b4cc

Please sign in to comment.