kubo / plthook

Hook function calls by replacing PLT(Procedure Linkage Table) entries.
745 stars 152 forks source link

plthook issues on MacOS #48

Open tomrus88 opened 1 month ago

tomrus88 commented 1 month ago

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:

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;
    }
}
tomrus88 commented 1 month ago

I think I found why this offset of 0x30 error happens, but I don't know how to fix it...

There's some __got entries in the library i'm hooking that are followed by 8+8+8 (0x18) bytes more data that should be skipped, but your code doesn't skip it and that causes rest of the functions to have invalid addresses that is shifted by 8 bytes per each entry that should be skipped

void **addr = (void**)(d->got_addr + i * sizeof(void*));

image image

Here you can see __Unwind_Resume and ZSt9terminatev are 8 bytes structs followed by 8+8+8 more bytes which shifts all got entries after them by 0x18+0x18=0x30 bytes, which is exactly the error I encountered and it breaks everything...

tomrus88 commented 1 month ago

After more digging it seems like some __got entries must be skipped, specifically those that have dyld_chained_ptr_64_rebase::bind value equal to 0, that should make things work again... And from looks of it that data is only available in file on disk, but not in memory?

        dyld_chained_ptr_64_bind __Unwind_Resume
          ordinal  19
          addend   0
          reserved 0
          next     2
          bind     1
        dyld_chained_ptr_64_rebase must skip
          target   3912432
          high8    0
          reserved 0
          next     2
          bind     0
        dyld_chained_ptr_64_rebase must skip
          target   431472
          high8    0
          reserved 0
          next     2
          bind     0
        dyld_chained_ptr_64_rebase must skip
          target   383136
          high8    0
          reserved 0
          next     2
          bind     0
        dyld_chained_ptr_64_bind __ZSt9terminatev
          ordinal  29
          addend   0
          reserved 0
          next     2
          bind     1
        dyld_chained_ptr_64_rebase must skip
          target   5070584
          high8    0
          reserved 0
          next     2
          bind     0
        dyld_chained_ptr_64_rebase must skip
          target   5060176
          high8    0
          reserved 0
          next     2
          bind     0
        dyld_chained_ptr_64_rebase must skip
          target   5026720
          high8    0
          reserved 0
          next     2
          bind     0
kubo commented 1 month ago

Thanks for your report.

kubo commented 4 weeks ago

@tomrus88 I updated plthook.h and plthook_osx.c. Could you check whether it works for you?

tomrus88 commented 3 weeks ago

Sure, i'll check it out soon and report back.

tomrus88 commented 3 weeks ago

Tested your fixes and it seems to work fine now. No more crash and hooked functions being called correctly in my case.