fishhook icon indicating copy to clipboard operation
fishhook copied to clipboard

The returned original pointer does not point to the correct symbol.

Open tirodkar opened this issue 8 years ago • 7 comments

Hello,

We are using rebind_symbols with GSEventPopRunLoopMode, for which we require the original symbol pointer. With commit 8dbd09b , we passed in a pointer to the rebinding struct to get the original symbol as suggested. However, the symbol-value returned for GSEventPopRunLoopMode is different from that provided by dlsym using the method suggested in the README before the change - _dlsym(RTLD_DEFAULT, “SYMBOL”)_ and also leads to the original implementation never being called.

As of now, this was the only symbol we saw this issue with. It would be great if we could find out why the original pointer value is different, since this means that we have to revert to using dlsym.

tirodkar avatar Nov 24 '15 02:11 tirodkar

Interesting. I wonder if you could find out what the original symbol is — is it the binding stub for that symbol? You might be able to disassemble at the address in the debugger and see if it's clear. If nothing else, you should be able to tell there what library the symbol fishhook is returning comes from.

For now, you can probably work around this by just still using dlsym(), but good to track this.

grp avatar Nov 24 '15 07:11 grp

I'll also cc in @uroboro in case they have any ideas :)

grp avatar Nov 24 '15 07:11 grp

We initially thought it was the binding stub as well. Can you see any particular reason why other symbols are not affected by this?

tirodkar avatar Nov 24 '15 20:11 tirodkar

Inserting printf("fishhook;%s: %p\n", &symbol_name[1], indirect_symbol_bindings[i]); in fishhook.c at line 100 (that's just after the name check), I see only two symbols that correspond to GSEventPopRunLoopMode (open and close have a couple more). Both addresses are the same as opposed to open and close which in my tests have the first address different from the others.

Testing for this symbol rebinding, I've written the following code (that is compiled into two dylibs to test if multiple hooks are possible):

#import <dlfcn.h>
#import <stdio.h>

#import "fishhook.h"

#include <CoreFoundation/CFString.h>
void GSEventPopRunLoopMode(CFStringRef mode);
static void (*orig_GSEventPopRunLoopMode)(CFStringRef mode);
static void my_GSEventPopRunLoopMode(CFStringRef mode) {
        orig_GSEventPopRunLoopMode(mode);
}

__attribute__((constructor)) static void ctor(int argc, char **argv, char **envp) {
        printf("dlsym(\"GSEventPopRunLoopMode\"):%p\n", dlsym(RTLD_DEFAULT, "GSEventPopRunLoopMode"));
        printf("GSEventPopRunLoopMode:%p | my_GSEventPopRunLoopMode:%p\n", GSEventPopRunLoopMode, my_GSEventPopRunLoopMode);

        struct rebinding rebinds[1] = (struct rebinding[1]){{"GSEventPopRunLoopMode", my_GSEventPopRunLoopMode, (void **)&orig_GSEventPopRunLoopMode}};
        rebind_symbols(rebinds, sizeof(rebinds)/sizeof(struct rebinding));

        printf("GSEventPopRunLoopMode:%p | orig_GSEventPopRunLoopMode:%p\n", GSEventPopRunLoopMode, orig_GSEventPopRunLoopMode);
        printf("dlsym(\"GSEventPopRunLoopMode\"):%p\n", dlsym(RTLD_DEFAULT, "GSEventPopRunLoopMode"));
}

I get the following output

dlsym("GSEventPopRunLoopMode"):0x353f2425
GSEventPopRunLoopMode:0x353f2425 | my_GSEventPopRunLoopMode:0xae701
fishhook;GSEventPopRunLoopMode: 0x353f2425
GSEventPopRunLoopMode:0xae701 | orig_GSEventPopRunLoopMode:0x353f2425
dlsym("GSEventPopRunLoopMode"):0x353f2425
fishhook;GSEventPopRunLoopMode: 0x353f2425
dlsym("GSEventPopRunLoopMode"):0x353f2425
GSEventPopRunLoopMode:0xae701 | my_GSEventPopRunLoopMode:0xb1701
fishhook;GSEventPopRunLoopMode: 0xae701
fishhook;GSEventPopRunLoopMode: 0xae701
GSEventPopRunLoopMode:0xb1701 | orig_GSEventPopRunLoopMode:0xae701
dlsym("GSEventPopRunLoopMode"):0x353f2425

While dlsym finds the original symbol address, both orig_GSEventPopRunLoopMode contain the previous address so I'm unable to reproduce.

uroboro avatar Nov 25 '15 14:11 uroboro

I tried the code above, without the constructor, however we still seem to get the issue. The way I tried was by using rebind_symbols directly in a viewDidLoad or in the +load :

#import "ViewController.h"
#import <dlfcn.h>
#import "fishhook.h"

void GSEventPopRunLoopMode(CFStringRef mode);
static void (*orig_GSEventPopRunLoopMode)(CFStringRef mode);
static void (*orig_dlsym_GSEventPopRunLoopMode)(CFStringRef mode);
static void rebound_GSEventPopRunLoopMode(CFStringRef mode) {
  orig_GSEventPopRunLoopMode(mode);
}

@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];

  orig_dlsym_GSEventPopRunLoopMode = dlsym(RTLD_DEFAULT, "GSEventPopRunLoopMode");
  struct rebinding rebinds[1] = (struct rebinding[1]){{"GSEventPopRunLoopMode",
    rebound_GSEventPopRunLoopMode,
    (void **)&orig_GSEventPopRunLoopMode}};
  rebind_symbols(rebinds, sizeof(rebinds)/sizeof(struct rebinding));

  printf("dlsym %p orig %p rebound %p\n", orig_dlsym_GSEventPopRunLoopMode, orig_GSEventPopRunLoopMode, rebound_GSEventPopRunLoopMode);
}
@end

and got :

dlsym 0x112ea2b88 orig 0x11003f748 rebound 0x10ec42010

Is there something that I'm doing wrong in the way I'm using fishhook here?

tirodkar avatar Dec 14 '15 04:12 tirodkar

Also, we are using the latest Xcode with a freshly created app with no changes whatsoever except the above ones.

tirodkar avatar Dec 14 '15 22:12 tirodkar

See codes in dyld: const ImageLoader::Symbol* ImageLoaderMachOClassic::findShallowExportedSymbol(const char* name, const ImageLoader** foundIn) const { const struct macho_nlist* sym = NULL; if ( fDynamicInfo->tocoff == 0 ) sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym); else sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], fDynamicInfo->ntoc, fDynamicInfo->nextdefsym); if ( sym != NULL ) { if ( foundIn != NULL ) foundIn = (ImageLoader)this; return (const Symbol*)sym; } return NULL; }

Look at this ---> binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym); That's the point , the symbol to be replaced is dynamic !

So the address read directly from the symbol is a indirect address , a address value in the stub . This happens every time you replacing a third party libs symbol .

duduWang20 avatar Jun 14 '18 10:06 duduWang20