update code structure for custom_loader

This commit is contained in:
nganhkhoa 2023-06-02 15:24:09 +07:00
parent 7880e647f5
commit e3a1dcf76a
3 changed files with 177 additions and 56 deletions

View File

@ -42,6 +42,12 @@ struct libcache_item {
void *trie;
uint32_t trie_size;
uint32_t hash;
uint64_t slide;
// pointer to segment address
uint32_t nsegment;
uint64_t* segment;
};
struct libcache {
@ -226,6 +232,17 @@ void print_macho_summary(const void *header) {
printf(" Segment %s\n", name);
printf(" vmaddr=0x%llx fileoffset=0x%llx\n", vmaddr, fileoffset);
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) {
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;
}
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) {
FILE *outfile = fopen(filename, "wb");
fwrite((char*)trie, size, 1, outfile);
@ -465,21 +537,53 @@ struct ProgramVars {
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
bruh(int argc, const char *const argv[], const char *const envp[],
const char *const apple[], const struct ProgramVars *vars) {
set_cwd(envp);
// 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);
// Find our lib (mapped) file
const void *thislib = find_header((void *)bruh);
// Find dyld lib (mapped) file using a no-sus function
const void *libdyld = find_header((void *)dyld_get_sdk_version);
struct libcache cache = {0, 0, (void *)main, (void *)thislib,
(void *)libdyld};
cache.main = (void*)main;
cache.thislib = (void*)thislib;
cache.libdyld = (void*)libdyld;
uint32_t libsystem_hash =
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("libdyld header at %p\n", libdyld);
// print_macho_summary(main);
// print_macho_summary(thislib);
uint32_t trie_size;
void *thislib_export_trie = get_export_trie(thislib, 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 char *(*dyld_get_image_name_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++) {
void *header = dyld_get_image_header_func(i);
char *name = dyld_get_image_name_func(i);
cache.libs[i].header = header;
cache.libs[i].trie = get_export_trie(header, trie_size);
cache.libs[i].trie_size = trie_size;
bootstrap_libcache_item(&cache.libs[i], header, name);
cache.libs[i].hash = calculate_libname_hash(&cache, name);
printf("%p %s\n", header, name);
}
}
// dump_export_trie_of("/usr/lib/system/libsystem_c.dylib", &cache, "../scripts/libsystem_c_export_trie.bin");
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);
}
void fix(struct libcache& cache) {
// now we have function to find exported symbols
// it supports full name search or 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
// generic
uint32_t libsystem_hash =
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
// this is just for now,
// 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);
@ -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
#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++) {
struct imported_symbol symbol = imported_table[i];
uint64_t fix_at = symbol.offset + libfixing->segment[symbol.segment_i];
int need_rw_fix = true;
for (int j = 0; j < npage_rw_fixed; j++) {
if (page_rw_fixed[j] <= symbol.address &&
page_rw_fixed[j] + 0x4000 > symbol.address) {
if (page_rw_fixed[j] <= fix_at &&
page_rw_fixed[j] + 0x4000 > fix_at) {
need_rw_fix = false;
}
}
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_PROT_READ | VM_PROT_WRITE);
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
resolved = custom_dlsym(&cache, symbol.lib, symbol.name);
}
uint64_t fix_at = symbol.address + main_slide;
*(uint64_t *)fix_at = (uint64_t)resolved;
printf("imports need to fix: (0x%x)%s at 0x%llx\n", symbol.hash,
symbol.name, symbol.address);
printf(" resolved %p\n", resolved);
symbol.name, fix_at);
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++) {
uint64_t start_page = page_rw_fixed[j];
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);
}
}

View File

@ -6,7 +6,12 @@ LOGIC=2
mkdir -p $OUT
if [[ $LOGIC -eq 1 ]]
if [[ $LOGIC -eq 0 ]]
then
clang-format -i -style=llvm *.cc
elif [[ $LOGIC -eq 1 ]]
then
# full poc flow

View File

@ -1,4 +1,2 @@
#include <stdio.h>
void exported_from_c() {
printf("from c\n");
}
void exported_from_c() { printf("from c\n"); }