Skip to content

plthook issues on MacOS #48

@tomrus88

Description

@tomrus88

I've come across multiple issues with hooking imported functions on MacOS, resulting hook either not working at all or hooking wrong function (after "fixing" issue with hook not working at all).

So here is what I found out after many many hours of debugging:

  • in read_chained_fixups function value of
    const uint8_t *ptr
    is calculated incorrectly, making that pointer off by
    linkedit->vmaddr - linkedit->fileoff
    bytes, which results in rest of the things to be read incorrectly and ends up with "unknown imports format 0" error message in my case. I've changed code a bit and it fixed that error for me:
    //const uint8_t *ptr = (const uint8_t *)mh + d->chained_fixups->dataoff;
    struct segment_command_64* linkedit = d->segments[d->linkedit_segment_idx];
    const uint8_t* ptr = (uint8_t*)(linkedit->vmaddr - linkedit->fileoff + d->slide + d->chained_fixups->dataoff);
  • after "fixing" above error another one surfaced which results in plthook hooking incorrect functions, which results in app crashing when that hooked function is called, more specifically it is hooking functions that are located at address that is 0x30 bytes lower than intended (in my case), for example if target function's __got entry is located at 0x4BF2C8, plthook hooks function with __got entry at 0x4BF298 instead... At this point calculated addr already has incorrect value:
        void **addr = (void**)(d->got_addr + i * sizeof(void*));
        DEBUG_FIXUPS("  lib_ordinal %u, weak_import %u, name_offset %u (%s), addr %p, addend %llu\n",
                     imp.lib_ordinal, imp.weak_import, imp.name_offset, name, addr, imp.addend);
        d->plthook->entries[i].name = name;
        d->plthook->entries[i].addr = addr;
lib_base 0x10d9a7000

lib_ordinal 1, weak_import 0, name_offset 1387 (_dlopen), addr 0x10de66298, addend 0

dlopen=0x10de66298-0x10d9a7000=0x4BF298 while real dlopen is at 0x4BF2C8 if you look at IDA

image_2024-08-14_204020586

Rough code I'm using:

void* dlopen_hook(const char* filename, int flags)
{
    // stuff
}

void* dlsym_hook(void* handle, const char* symbol)
{
    // stuff
}

bool hook_stuff()
{
    plthook_t* plthook;

    if (plthook_open(&plthook, "libname.dylib") != 0) {
        return false;
    }

    if (plthook_replace(plthook, "dlopen", (void*)dlopen_hook, nullptr) != 0) {
        plthook_close(plthook);
        return false;
    }
    if (plthook_replace(plthook, "dlsym", (void*)dlsym_hook, nullptr) != 0) {
        plthook_close(plthook);
        return false;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions