GithubHelp home page GithubHelp logo

Comments (8)

lazybind avatar lazybind commented on April 25, 2024 4

I've found solution. I take original pointer from dlsym instead of result from rebind_symbols, and that solves my issue.

    void *handle = dlopen("..framework...", RTLD_NOW);
    original_SomeFunction = dlsym(handle, "SomeFunction");

    if ((rebind_symbols((struct rebinding[1]){{(char *)"SomeFunction", (void *)replaced_SomeFunction}}, 1) < 0))
    {
        Log(@"Hooking failed.");
    }

Call of dlsym provides direct address of function, and that's all.

Conclusion
I based my code on the sample, but looks like it's wrong for some cases. Call of original function could rewrite hook. To avoid that, the simpler solution would be obtained pointer to original function from dlsym, instead of using it from rebind_symbols.

from fishhook.

grp avatar grp commented on April 25, 2024 2

Did you make your GitHub account just to report this bug? Either way, great username.

I can see why this would happen with lazy binding. Also not sure if it's a bug, but it's definitely confusing. Here's two potential workarounds:

  1. Load the library with dlopen(..., RTLD_NOW) before using fishhook for force immediate symbol binding.
  2. Call the function yourself to force it to be bound first.

Do either of those help for you?

from fishhook.

lazybind avatar lazybind commented on April 25, 2024

Did you make your GitHub account just to report this bug? Either way, great username.

ok Thanks, will know.

Do either of those help for you?

Doesn't work.

Option A Simple call dlopen/dlsym/original function

  1. Force loading framework
    dlopen("/Applications/Xcode8.0.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/Library/PrivateFrameworks/WebCore.framework/WebCore", RTLD_NOW);
  2. Obtain pointer to function (dlsym)
  3. Force call problematic function.
    Doesn't work, because dlsym provide real address of function, not a bind stub.

Code is below:

        void *handle = dlopen("/Applications/Xcode8.0.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/Library/PrivateFrameworks/WebCore.framework/WebCore", RTLD_NOW);
        
        typedef void * (*SQLiteStatement_bindBlob_func)(void *StorageMapThis, int index, void* WTFStrText);
        SQLiteStatement_bindBlob_func func= (SQLiteStatement_bindBlob_func)dlsym(handle, "_ZN7WebCore15SQLiteStatement8bindBlobEiRKN3WTF6StringE");
        char *stubData[100] = {0};
        func(stubData, 0, stubData);

Call of func looks like this:

    0x10000987a <+170>: movq   -0x3b0(%rbp), %rax
    0x100009881 <+177>: movq   -0x3d8(%rbp), %rdi
    0x100009888 <+184>: movl   -0x3cc(%rbp), %esi
    0x10000988e <+190>: movq   -0x3d8(%rbp), %rdx
->  0x100009895 <+197>: callq  *%rax

And $rax is original address of function:

(lldb) image lookup -a $rax
      Address: WebCore[0x0000000000e12e60] (WebCore.__TEXT.__text + 14749488)
      Summary: WebCore`WebCore::SQLiteStatement::bindBlob(int, WTF::String const&)
(lldb) 

Code from framework still contains stubs for lazy binding, those operations don't trigger the binding.

Option B More complex way: dlopen/dlsym but call upper function from framework which will call required function. Those must trigger binding mechanism. Unfortunately upper function is not exported, so can't force trigger binding mechanism for required function.

from fishhook.

grp avatar grp commented on April 25, 2024

Sorry, I meant dlopen(..., RTLD_NOW) on WebCoreLegacy, which is the one that has the lazy binding.

from fishhook.

lazybind avatar lazybind commented on April 25, 2024

Do not really understand.
Lazy binding function will be 'resolved' only after first real call of it. Loading framework which contains it does not resolve issue, because it needs to call original function at least once. Only after that hook can be installed and call of original function from hook will be safety (this will not lead to restoring original function).

In other words, if I postpone installing hook for 10 seconds, than all work as expected. Unfortunately, this is bad case for me, because I lose some important information in that 10 seconds.

I guess, you mean that I should load framework, and this would lead to call original function... but loaded framework doesn't call this function. This functionality linked with browsing webpage inside UIWebview component, and requires interaction from user side. Only in that way is posible to trigger this function.

from fishhook.

grp avatar grp commented on April 25, 2024

My understanding is that RLTD_NOW immediately binds the lazy symbols, without needing them to be called. From the manpage:

RTLD_NOW    All external function references are bound immediately during the call to dlopen().

You can then hook the functions after dlopen() returns since the symbols should all be bound.

from fishhook.

lazybind avatar lazybind commented on April 25, 2024

Usual case of using hook functionality

We have target library which functions have to be hooked.
Also, we have some other code (that could be our App or 3-rd party library) which uses target library functions. And we use fishhook for hooking target library functions.
So, when our App or 3-rd party library is calling target function then our hook is executed. Our hook is calling original function, and at that moment system binds original symbol.
Here is very tricky moment: system code patches/binds lazy symbol inside target library.

#0	0x00000001085ecb8d in ImageLoaderMachO::bindLocation(ImageLoader::LinkContext const&, unsigned long, unsigned long, unsigned char, char const*, long, char const*, char const*, char const*) ()
#1	0x00000001085f197b in ImageLoaderMachOCompressed::doBindFastLazySymbol(unsigned int, ImageLoader::LinkContext const&, void (*)(), void (*)()) ()
#2	0x00000001085dfbb9 in dyld::fastBindLazySymbol(ImageLoader**, unsigned long) ()
#3	0x000000010c358516 in dyld_stub_binder ()

This is fine for us, because lazy symbols inside our App (or 3-rd party library) still contain correct link on our hooked function.

Not obvious case

Now, another case, and it's more interesting (not obvious).
If we hook exported (external) function inside our module. When we are calling from hook function an original function then system does the same work - binds lazy symbol. But this also means that system re-writes our hook pointer. As the result, our hook called only once.
Of course this case looks very strange. Why do we need to hook own function in own module? But bellow is next case which explains my situation.

Now imagine that one function could be present in many frameworks. How it's posible? Well, some frameworks could be based on the same component, as in my case. For example WebCore component (with some functions set) is built with WebKit and also with WebKitLegacy frameworks.
So, in two frameworks is present the same function. When my hook is calling from WebKit and calls original function from WebKitLegacy then this works fine. Becuase system will bind original function inside WebKitLegacy. So, symbol inside WebKit will still has our hook.
But if we are calling hook from WebKitLegacy then our hook also calls original function from this framework, and system rewrites our hook.
In simple words: if we 'install' hook inside module/framework which calls own external function then we will see this bug - our hook will be called only once.

My case

Now imagine that one function could be present in many frameworks. How it's posible? Well, some frameworks could be based on the same component, as in my case. For example WebCore component (with some functions set) is built with WebKit and also with WebKitLegacy frameworks.
So, in two frameworks is present the same function. When my hook is calling from WebKit and calls original function from WebKitLegacy then this works fine. Because system will bind original function inside WebKitLegacy (rewrite our pointer on hook). So, symbol inside WebKit will still have our hook.
But if we are calling hook from WebKitLegacy then our hook also calls original function from this framework, and system rewrites our hook.
In simple words: if we 'install' hook inside module / framework which calls own external function then we will see this bug - our hook will be called only once.

@grp
I do not know why dlopen (RTLD_NOW) does not resolve lazy binding symbols.

Summary

I know the root cause of bug, but still don't know how to fix it in appropriate way. I can again install hook after first call of original function but this requires additional logic in code. Looks like the best way it's reading Apple documentation to understand how to force bind lazy symbols and only after that install hook.

from fishhook.

saagarjha avatar saagarjha commented on April 25, 2024

I wonder if fishhook could improve the situation here checking the GOT entry it's replacing to see if it's dyld_stub_binder, and if so, replacing it with a thunk that "does the right thing" when called.

from fishhook.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.