update code structure for custom_loader
This commit is contained in:
parent
7880e647f5
commit
e3a1dcf76a
@ -42,6 +42,12 @@ struct libcache_item {
|
|||||||
void *trie;
|
void *trie;
|
||||||
uint32_t trie_size;
|
uint32_t trie_size;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
|
||||||
|
uint64_t slide;
|
||||||
|
|
||||||
|
// pointer to segment address
|
||||||
|
uint32_t nsegment;
|
||||||
|
uint64_t* segment;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct libcache {
|
struct libcache {
|
||||||
@ -226,6 +232,17 @@ void print_macho_summary(const void *header) {
|
|||||||
printf(" Segment %s\n", name);
|
printf(" Segment %s\n", name);
|
||||||
printf(" vmaddr=0x%llx fileoffset=0x%llx\n", vmaddr, fileoffset);
|
printf(" vmaddr=0x%llx fileoffset=0x%llx\n", vmaddr, fileoffset);
|
||||||
printf(" vmsize=0x%llx filesize=0x%llx\n", vmsize, filesize);
|
printf(" vmsize=0x%llx filesize=0x%llx\n", vmsize, filesize);
|
||||||
|
|
||||||
|
uint64_t nsect = *((uint32_t *)ptr + 8*2);
|
||||||
|
char* sections_ptr = (char*)((uint32_t*)ptr + 18);
|
||||||
|
for (int sec = 0; sec < nsect; sec++) {
|
||||||
|
char* secname = sections_ptr;
|
||||||
|
uint64_t addr = *((uint64_t*)sections_ptr + 4);
|
||||||
|
uint64_t size = *((uint64_t*)sections_ptr + 5);
|
||||||
|
uint32_t fileoffset = *((uint32_t*)sections_ptr + 6*2);
|
||||||
|
printf(" Section %s\n", sections_ptr);
|
||||||
|
printf(" addr=0x%llx size=0x%llx fileoffset=0x%x\n", addr, size, fileoffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (cmd == LC_REEXPORT_DYLIB) {
|
if (cmd == LC_REEXPORT_DYLIB) {
|
||||||
uint32_t name_offset = *((uint32_t *)ptr + 2);
|
uint32_t name_offset = *((uint32_t *)ptr + 2);
|
||||||
@ -429,6 +446,61 @@ void *custom_dlsym(struct libcache *cache, uint32_t hash, const char *symbol) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bootstrap_libcache_item(struct libcache_item* item, const void* header, const char* name) {
|
||||||
|
item->header = (void*)header;
|
||||||
|
item->trie = get_export_trie(header, item->trie_size);
|
||||||
|
|
||||||
|
const uint32_t magic = *(uint32_t *)header;
|
||||||
|
char *ptr = (char *)header;
|
||||||
|
if (magic == magic64) {
|
||||||
|
ptr += 0x20;
|
||||||
|
} else {
|
||||||
|
ptr += 0x20 - 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||||
|
char* command_ptr = ptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < ncmds; i++) {
|
||||||
|
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||||
|
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||||
|
if (cmd == LC_SEGMENT_64) {
|
||||||
|
char *name = (char *)((uint64_t *)ptr + 1);
|
||||||
|
if (custom_strcmp(name, "__TEXT") == 0) {
|
||||||
|
uint64_t vmaddr = *((uint64_t *)ptr + 3);
|
||||||
|
item->slide = (uint64_t)header - vmaddr;
|
||||||
|
}
|
||||||
|
item->nsegment++;
|
||||||
|
}
|
||||||
|
ptr += cmdsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = command_ptr;
|
||||||
|
item->segment = (uint64_t*)malloc(sizeof(uint64_t) * item->nsegment);
|
||||||
|
for (int i = 0, segment_i = 0; i < ncmds; i++) {
|
||||||
|
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||||
|
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||||
|
if (cmd == LC_SEGMENT_64) {
|
||||||
|
uint64_t vmaddr = *((uint64_t *)ptr + 3);
|
||||||
|
item->segment[segment_i++] = (vmaddr + item->slide);
|
||||||
|
}
|
||||||
|
ptr += cmdsize;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct libcache_item* get_libcache_with_name(struct libcache* cache, const char* name) {
|
||||||
|
uint32_t hash = calculate_libname_hash(cache, name);
|
||||||
|
for (int i = 0; i < cache->size; i++) {
|
||||||
|
struct libcache_item* cache_lib = &cache->libs[i];
|
||||||
|
if (cache_lib->hash == hash) {
|
||||||
|
return cache_lib;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void dump_export_trie(const void* trie, uint32_t size, const char* filename) {
|
void dump_export_trie(const void* trie, uint32_t size, const char* filename) {
|
||||||
FILE *outfile = fopen(filename, "wb");
|
FILE *outfile = fopen(filename, "wb");
|
||||||
fwrite((char*)trie, size, 1, outfile);
|
fwrite((char*)trie, size, 1, outfile);
|
||||||
@ -465,21 +537,53 @@ struct ProgramVars {
|
|||||||
const char **__prognamePtr;
|
const char **__prognamePtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void build_cache(struct libcache& cache, void* main);
|
||||||
|
void fix(struct libcache& cache);
|
||||||
|
|
||||||
|
void test(struct libcache& cache);
|
||||||
|
|
||||||
__attribute__((constructor)) static void
|
__attribute__((constructor)) static void
|
||||||
bruh(int argc, const char *const argv[], const char *const envp[],
|
bruh(int argc, const char *const argv[], const char *const envp[],
|
||||||
const char *const apple[], const struct ProgramVars *vars) {
|
const char *const apple[], const struct ProgramVars *vars) {
|
||||||
set_cwd(envp);
|
set_cwd(envp);
|
||||||
|
|
||||||
// ProgramVars contains pointer to main executable (mapped) file
|
// ProgramVars contains pointer to main executable (mapped) file
|
||||||
const void *main = (int *)(vars->mh);
|
|
||||||
|
struct libcache cache;
|
||||||
|
build_cache(cache, (void *)(vars->mh));
|
||||||
|
|
||||||
|
// dump_export_trie_of(
|
||||||
|
// "/usr/lib/system/libsystem_c.dylib", &cache,
|
||||||
|
// "../scripts/libsystem_c_export_trie.bin");
|
||||||
|
|
||||||
|
// test(cache);
|
||||||
|
|
||||||
|
// ATTENTION:
|
||||||
|
// If we choose to resolve **this** lib
|
||||||
|
// Before resolve is complete, **DO NOT** call any library function
|
||||||
|
//
|
||||||
|
// The following functions can be used:
|
||||||
|
// (we do not remove them for **our lib**)
|
||||||
|
// - malloc
|
||||||
|
// - free
|
||||||
|
fix(cache);
|
||||||
|
|
||||||
|
for (int i = 0; i < cache.size; i++) {
|
||||||
|
free(cache.libs[i].segment);
|
||||||
|
}
|
||||||
|
free(cache.libs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_cache(struct libcache& cache, void* main) {
|
||||||
const uint64_t main_slide = get_slide(main);
|
const uint64_t main_slide = get_slide(main);
|
||||||
// Find our lib (mapped) file
|
// Find our lib (mapped) file
|
||||||
const void *thislib = find_header((void *)bruh);
|
const void *thislib = find_header((void *)bruh);
|
||||||
// Find dyld lib (mapped) file using a no-sus function
|
// Find dyld lib (mapped) file using a no-sus function
|
||||||
const void *libdyld = find_header((void *)dyld_get_sdk_version);
|
const void *libdyld = find_header((void *)dyld_get_sdk_version);
|
||||||
|
|
||||||
struct libcache cache = {0, 0, (void *)main, (void *)thislib,
|
cache.main = (void*)main;
|
||||||
(void *)libdyld};
|
cache.thislib = (void*)thislib;
|
||||||
|
cache.libdyld = (void*)libdyld;
|
||||||
uint32_t libsystem_hash =
|
uint32_t libsystem_hash =
|
||||||
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
|
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
|
||||||
|
|
||||||
@ -508,10 +612,16 @@ bruh(int argc, const char *const argv[], const char *const envp[],
|
|||||||
printf("lib header at %p\n", thislib);
|
printf("lib header at %p\n", thislib);
|
||||||
printf("libdyld header at %p\n", libdyld);
|
printf("libdyld header at %p\n", libdyld);
|
||||||
|
|
||||||
|
// print_macho_summary(main);
|
||||||
|
// print_macho_summary(thislib);
|
||||||
|
|
||||||
uint32_t trie_size;
|
uint32_t trie_size;
|
||||||
void *thislib_export_trie = get_export_trie(thislib, trie_size);
|
|
||||||
void *libdyld_export_trie = get_export_trie(libdyld, trie_size);
|
void *libdyld_export_trie = get_export_trie(libdyld, trie_size);
|
||||||
|
|
||||||
|
// we have to traverse the trie to find these symbols
|
||||||
|
// because if we self-rebuild import table for **this** lib,
|
||||||
|
// these symbols aren't resolved
|
||||||
|
// so we have to resolve ourselves and then rebuild the symbols for others
|
||||||
typedef int (*dyld_image_count_t)(void);
|
typedef int (*dyld_image_count_t)(void);
|
||||||
typedef char *(*dyld_get_image_name_t)(int);
|
typedef char *(*dyld_get_image_name_t)(int);
|
||||||
typedef void *(*dyld_get_image_header_t)(int);
|
typedef void *(*dyld_get_image_header_t)(int);
|
||||||
@ -530,50 +640,13 @@ bruh(int argc, const char *const argv[], const char *const envp[],
|
|||||||
for (int i = 0; i < cache.size; i++) {
|
for (int i = 0; i < cache.size; i++) {
|
||||||
void *header = dyld_get_image_header_func(i);
|
void *header = dyld_get_image_header_func(i);
|
||||||
char *name = dyld_get_image_name_func(i);
|
char *name = dyld_get_image_name_func(i);
|
||||||
cache.libs[i].header = header;
|
bootstrap_libcache_item(&cache.libs[i], header, name);
|
||||||
cache.libs[i].trie = get_export_trie(header, trie_size);
|
|
||||||
cache.libs[i].trie_size = trie_size;
|
|
||||||
cache.libs[i].hash = calculate_libname_hash(&cache, name);
|
cache.libs[i].hash = calculate_libname_hash(&cache, name);
|
||||||
printf("%p %s\n", header, name);
|
printf("%p %s\n", header, name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dump_export_trie_of("/usr/lib/system/libsystem_c.dylib", &cache, "../scripts/libsystem_c_export_trie.bin");
|
void fix(struct libcache& cache) {
|
||||||
|
|
||||||
if (false) { // test search using name
|
|
||||||
void *printf_func =
|
|
||||||
custom_dlsym(&cache, "/usr/lib/libSystem.B.dylib", "_printf");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", printf_func, printf);
|
|
||||||
|
|
||||||
void *vm_protect_func =
|
|
||||||
custom_dlsym(&cache, "/usr/lib/libSystem.B.dylib", "_vm_protect");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", vm_protect_func,
|
|
||||||
vm_protect);
|
|
||||||
|
|
||||||
// using relative path
|
|
||||||
void *func_c_1 =
|
|
||||||
custom_dlsym(&cache, "./out/libb.dylib", "__Z15exported_from_cv");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", func_c_1,
|
|
||||||
exported_from_c);
|
|
||||||
|
|
||||||
// using rpath
|
|
||||||
void *func_c_2 =
|
|
||||||
custom_dlsym(&cache, "@rpath/libb.dylib", "__Z15exported_from_cv");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", func_c_2,
|
|
||||||
exported_from_c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false) { // test search using hash of name
|
|
||||||
void *printf_func = custom_dlsym(&cache, libsystem_hash, "_printf");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", printf_func, printf);
|
|
||||||
|
|
||||||
void *vm_protect_func = custom_dlsym(&cache, libsystem_hash, "_vm_protect");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", vm_protect_func,
|
|
||||||
vm_protect);
|
|
||||||
|
|
||||||
void *realpath_func = custom_dlsym(&cache, libsystem_hash, "_realpath$DARWIN_EXTSN");
|
|
||||||
printf("Indirect search: Found=%p Expected=%p\n", realpath_func, realpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we have function to find exported symbols
|
// now we have function to find exported symbols
|
||||||
// it supports full name search or hash search
|
// it supports full name search or hash search
|
||||||
// to reserve space, we use the hash search
|
// to reserve space, we use the hash search
|
||||||
@ -617,6 +690,9 @@ bruh(int argc, const char *const argv[], const char *const envp[],
|
|||||||
// may need to look into why this happens so we can deal with this more
|
// may need to look into why this happens so we can deal with this more
|
||||||
// generic
|
// generic
|
||||||
|
|
||||||
|
uint32_t libsystem_hash =
|
||||||
|
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
|
||||||
|
|
||||||
// this is just for now,
|
// this is just for now,
|
||||||
// in the future we will self fix our lib so our lib also has no import
|
// in the future we will self fix our lib so our lib also has no import
|
||||||
typedef void *(*vm_protect_t)(void *, uint64_t, uint64_t, int, int);
|
typedef void *(*vm_protect_t)(void *, uint64_t, uint64_t, int, int);
|
||||||
@ -630,18 +706,22 @@ bruh(int argc, const char *const argv[], const char *const envp[],
|
|||||||
uint64_t page_rw_fixed[10]; // should be dynamic, but works for now
|
uint64_t page_rw_fixed[10]; // should be dynamic, but works for now
|
||||||
|
|
||||||
#include "out/b.h"
|
#include "out/b.h"
|
||||||
|
// think of a way to get what binary to fix
|
||||||
|
// so we can iterate through them
|
||||||
|
struct libcache_item* libfixing = get_libcache_with_name(&cache, "./out/a");
|
||||||
for (int i = 0; i < nimports; i++) {
|
for (int i = 0; i < nimports; i++) {
|
||||||
struct imported_symbol symbol = imported_table[i];
|
struct imported_symbol symbol = imported_table[i];
|
||||||
|
uint64_t fix_at = symbol.offset + libfixing->segment[symbol.segment_i];
|
||||||
|
|
||||||
int need_rw_fix = true;
|
int need_rw_fix = true;
|
||||||
for (int j = 0; j < npage_rw_fixed; j++) {
|
for (int j = 0; j < npage_rw_fixed; j++) {
|
||||||
if (page_rw_fixed[j] <= symbol.address &&
|
if (page_rw_fixed[j] <= fix_at &&
|
||||||
page_rw_fixed[j] + 0x4000 > symbol.address) {
|
page_rw_fixed[j] + 0x4000 > fix_at) {
|
||||||
need_rw_fix = false;
|
need_rw_fix = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (need_rw_fix) {
|
if (need_rw_fix) {
|
||||||
uint64_t start_page = symbol.address - (symbol.address % 0x4000);
|
uint64_t start_page = fix_at - (fix_at % 0x4000);
|
||||||
vm_protect_func(mach_task_self_func(), start_page, 0x4000, 0,
|
vm_protect_func(mach_task_self_func(), start_page, 0x4000, 0,
|
||||||
VM_PROT_READ | VM_PROT_WRITE);
|
VM_PROT_READ | VM_PROT_WRITE);
|
||||||
page_rw_fixed[npage_rw_fixed++] = start_page;
|
page_rw_fixed[npage_rw_fixed++] = start_page;
|
||||||
@ -655,18 +735,56 @@ bruh(int argc, const char *const argv[], const char *const envp[],
|
|||||||
// but fuck apple they have relative path and rpath
|
// but fuck apple they have relative path and rpath
|
||||||
resolved = custom_dlsym(&cache, symbol.lib, symbol.name);
|
resolved = custom_dlsym(&cache, symbol.lib, symbol.name);
|
||||||
}
|
}
|
||||||
uint64_t fix_at = symbol.address + main_slide;
|
|
||||||
*(uint64_t *)fix_at = (uint64_t)resolved;
|
*(uint64_t *)fix_at = (uint64_t)resolved;
|
||||||
|
|
||||||
printf("imports need to fix: (0x%x)%s at 0x%llx\n", symbol.hash,
|
printf("imports need to fix: (0x%x)%s at 0x%llx\n", symbol.hash,
|
||||||
symbol.name, symbol.address);
|
symbol.name, fix_at);
|
||||||
printf(" resolved %p\n", resolved);
|
printf(" from=%s\n", symbol.lib);
|
||||||
|
printf(" segment id=%d; offset=0x%llx;", symbol.segment_i, symbol.offset);
|
||||||
|
printf(" resolved=%p\n", resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < npage_rw_fixed; j++) {
|
for (int j = 0; j < npage_rw_fixed; j++) {
|
||||||
uint64_t start_page = page_rw_fixed[j];
|
uint64_t start_page = page_rw_fixed[j];
|
||||||
vm_protect_func(mach_task_self_func(), start_page, 0x4000, 0, VM_PROT_READ);
|
vm_protect_func(mach_task_self_func(), start_page, 0x4000, 0, VM_PROT_READ);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
free(cache.libs);
|
|
||||||
|
void test(struct libcache& cache) {
|
||||||
|
uint32_t libsystem_hash =
|
||||||
|
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
|
||||||
|
if (false) { // test search using name
|
||||||
|
void *printf_func =
|
||||||
|
custom_dlsym(&cache, "/usr/lib/libSystem.B.dylib", "_printf");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", printf_func, printf);
|
||||||
|
|
||||||
|
void *vm_protect_func =
|
||||||
|
custom_dlsym(&cache, "/usr/lib/libSystem.B.dylib", "_vm_protect");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", vm_protect_func,
|
||||||
|
vm_protect);
|
||||||
|
|
||||||
|
// using relative path
|
||||||
|
void *func_c_1 =
|
||||||
|
custom_dlsym(&cache, "./out/libb.dylib", "__Z15exported_from_cv");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", func_c_1,
|
||||||
|
exported_from_c);
|
||||||
|
|
||||||
|
// using rpath
|
||||||
|
void *func_c_2 =
|
||||||
|
custom_dlsym(&cache, "@rpath/libb.dylib", "__Z15exported_from_cv");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", func_c_2,
|
||||||
|
exported_from_c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false) { // test search using hash of name
|
||||||
|
void *printf_func = custom_dlsym(&cache, libsystem_hash, "_printf");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", printf_func, printf);
|
||||||
|
|
||||||
|
void *vm_protect_func = custom_dlsym(&cache, libsystem_hash, "_vm_protect");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", vm_protect_func,
|
||||||
|
vm_protect);
|
||||||
|
|
||||||
|
void *realpath_func = custom_dlsym(&cache, libsystem_hash, "_realpath$DARWIN_EXTSN");
|
||||||
|
printf("Indirect search: Found=%p Expected=%p\n", realpath_func, realpath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,12 @@ LOGIC=2
|
|||||||
|
|
||||||
mkdir -p $OUT
|
mkdir -p $OUT
|
||||||
|
|
||||||
if [[ $LOGIC -eq 1 ]]
|
if [[ $LOGIC -eq 0 ]]
|
||||||
|
then
|
||||||
|
|
||||||
|
clang-format -i -style=llvm *.cc
|
||||||
|
|
||||||
|
elif [[ $LOGIC -eq 1 ]]
|
||||||
then
|
then
|
||||||
# full poc flow
|
# full poc flow
|
||||||
|
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
void exported_from_c() {
|
void exported_from_c() { printf("from c\n"); }
|
||||||
printf("from c\n");
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user