4

I'm writing some C code to hook some function of .so ELF (shared-library) loaded into memory.

My C code should be able to re-direct an export function of another .so library that was loaded into the app/program's memory.

Here's a bit of elaboration:

enter image description here

Android app will have multiple .so files loaded. My C code has to look through export function that belongs to another shared .so library (called target.so in this case)

This is not a regular dlsym approach because I don't just want address of a function but I want to replace it with my own fuction; in that: when another library makes the call to its own function then instead my hook_func gets called, and then from my hook_func I should call the original_func.

For import functions this can work. But for export functions I'm not sure how to do it. Import functions have the entries in the symbol table that have corresponding entry in relocation table that eventually gives the address of entry in global offset table (GOT). But for the export functions, the symbol's st_value element itself has address of the procedure and not GOT address (correct me if I'm wrong).

How do I perform the hooking for the export function?

Theoretically speaking, I should get the memory location of the st_value element of dynamic symbol table entry ( Elf32_Sym ) of export function. If I get that location then I should be able to replace the value in that location with my hook_func's address. However, I'm not able to write into this location so far. I have to assume the dynamic symbol table's memory is read-only. If that is true then what is the workaround in that case?

Thanks a lot for reading and helping me out.

Update: LD_PRELOAD can only replace the original functions with my own, but then I'm not sure if there any way to call the originals. In my case for example:

App initializes the audio engine by calling Audio_System_Create and passes a reference of AUDIO_SYSTEM object to Audio_System_Create(AUDIO_SYSTEM **); AUDIO API allocates this struct/object and function returns. Now if only I could access that AUDIO_SYSTEM object, I would easily attach a callback to this object and start receiving audio data. Hence, my ultimate goal is to get the reference to AUIOD_SYSTEM object; and in my understanding, I can only get that if I intercept the call where that object is first getting allocated through Audio_System_Create(AUIOD_SYSTEM **). Currently there is no straight way to grab the output audio at android. (all examples talk about recording audio that comes from microphone only)

Update2: As advised by Basile in his answer, I made use of dladdr() but strangely enough it gives me the same address as I pass to it.

void *pFunc=procedure_addr;  //procedure address calculated from the st_value of symbol from symbol table in ELF file (not from loaded file)

        int  nRet;

            // Lookup the name of the function given the function pointer
            if ((nRet = dladdr(pFunc, &DlInfo)) != 0)
            {
                LOGE("Symbol Name is: %s", DlInfo.dli_sname);
                if(DlInfo.dli_saddr==NULL)
                    LOGE("Symbol Address is: NULL");
                else
                    LOGE("Symbol Address is: 0x%x", DlInfo.dli_saddr);
            }
            else
                LOGE("dladdr failed");

Here's the result I get:

entry_addr =0x75a28cfc

entry_addr_through_dlysm =0x75a28cfc

Symbol Name is: AUDIO_System_Create

Symbol Address is: 0x75a28cfc

Here address obtained through dlysm or calculated through ELF file is the address of procedure; while I need the location where this address itself is; so that I can replace this address with my hook_func address. dladdr() didn't do what I thought it will do.

Usman.3D
  • 1,791
  • 3
  • 16
  • 27
  • 1
    Why the hacks? Why not code that explicitly? For example global variable with the pointer to the function, and all libraries should call the function. Otherwise, check *weak symbols*, `LD_PRELOAD` and `elf plt/got`. – Dummy00001 Apr 15 '15 at 12:16
  • There was a very solid reason to go for the hack. I'm coding this module that has to redirect Unity's game's calls for the FMOD audio engine. So I have to intercept the very first call of FMOD_System_Create so that I can get the FMOD_SYSTEM handle. Why need that handle? So that I can attach my callback to get the audio. – Usman.3D Apr 15 '15 at 13:29
  • By the way, couple of companies already have NDK (C) solution to grab audio from unity games. – Usman.3D Apr 15 '15 at 13:30
  • What about `LD_PRELOAD`? – hek2mgl Apr 15 '15 at 13:30
  • Sorry, could you elaborate a bit? I'm not an ELF expert. Edit: I guess you are referring to the early loading of library? Well, that's not an issue here. I can verify through dlsym that the required function does exist and I did make call to it. But the problem is that, I want to intercept the Unity's call to that function. – Usman.3D Apr 15 '15 at 13:31
  • 1
    Check [this answer](http://stackoverflow.com/questions/14690010/bash-trick-program-into-thinking-stdout-is-an-interactive-terminal/14694983#14694983) which I gave a sometime ago. Is this what you basically want to do? – hek2mgl Apr 15 '15 at 13:33
  • My goal is to provide my own .so file that can be added into unity. When unity game's android project is generated, the game developer just runs it then my .so method is called to do the hook. The hook is working for import functions. The only problem is with export functions. FMOD audio engine's functions are export functions that are listed along with the import functions. – Usman.3D Apr 15 '15 at 13:38
  • @hek2mgl The answer you referred has the import function example. An export function is that which was not part of Unity but it included them from FMOD. +1 for your reference though. :) – Usman.3D Apr 15 '15 at 13:42
  • @Usman.3D, so have you tried the `LD_PRELOAD`? From inside your version of the `FMOD_System_Create` you need to call the original function. The original can be found using the `dlsym( RTLD_NEXT )`. Otherwise, I would advise you to create a minimalistic example and post new question. You question is too broad, since you lack the basic knowledge how the dynamic libraries work. – Dummy00001 Apr 17 '15 at 21:11
  • @Dummy00001, I know about dlsym and I know about Linked Libraries to some extent. dlsym gives me the address of function ONLY so that I can call the original function. I don't want that only. I want that function to be replaced by my hook_func (and save the orginal_func). So when the app invokes the original_func it actually comes to hook_func instead of original_func. From my hook_func I do stuff and then call the original_func that I had saved at the time of hooking. Why do I need that? Because when Unity invokes FMOD_System_Create then I want obtain the object FMOD System created. – Usman.3D Apr 18 '15 at 23:31
  • @Usman.3D, Orignal question stands: have you tried the `LD_PRELOAD`? And the "I don't want that only." - nobody said that it is the *only* thing you can do. Otherwise, the `LD_PRELOAD` would have been completely useless. You need to actually try it, experiment with it, and, if it doesn't work, come back asking why it doesn't work/how to make it work/alternatives. – Dummy00001 Apr 19 '15 at 11:53
  • @Dummy00001 My understanding about LD_PRELOAD is that my library will get loaded first. How will that help achieve my goal? Also, please enlighten me how to find out the address of a symbol in dynamic symbol table in the loaded porgram. Is the dynamic symbol table of loaded app will be editable memory? Or is it possible to make it editable somehow? – Usman.3D Apr 20 '15 at 03:35
  • 1
    @Usman.3D: please edit your question, instead of commenting it, to improve it. – Basile Starynkevitch Apr 20 '15 at 05:36

1 Answers1

7

You should read in details Drepper's paper: how to write shared libraries - notably to understand why using LD_PRELOADis not enough. You may want to study the source code of the dynamic linker (ld-linux.so) inside your libc. You might try to change with mprotect(2) and/or mmap(2) and/or mremap(2) the relevant pages. You can query the memory mapping thru proc(5) using /proc/self/maps & /proc/self/smaps. Then you could, in an architecture-specific way, replace the starting bytes (perhaps using asmjit or GNU lightning) of the code of original_func by a jump to your hook_func function (which you might need to change its epilogue, to put the overwritten instructions -originally at original_func- there...)

Things might be slightly easier if original_func is well known and always the same. You could then study its source and assembler code, and write the patching function and your hook_func only for it.

Perhaps using dladdr(3) might be helpful too (but probably not).

Alternatively, hack your dynamic linker to change it for your needs. You might study the source code of musl-libc

Notice that you probably need to overwrite the machine code at the address of original_func (as given by dlsym on "original_func"). Alternatively, you'll need to relocate every occurrence of calls to that function in all the already loaded shared objects (I believe it is harder; if you insist see dl_iterate_phdr(3)).

If you want a generic solution (for an arbitrary original_func) you'll need to implement some binary code analyzer (or disassembler) to patch that function. If you just want to hack a particular original_func you should disassemble it, and patch its machine code, and have your hook_func do the part of original_func that you have overwritten.

Such horrible and time consuming hacks (you'll need weeks to make it work) make me prefer using free software (since then, it is much simpler to patch the source of the shared library and recompile it).

Of course, all this isn't easy. You need to understand in details what ELF shared objects are, see also elf(5) and read Levine's book: Linkers and Loaders


NB: Beware, if you are hacking against a proprietary library (e.g. unity3d), what you are trying to achieve might be illegal. Ask a lawyer. Technically, you are violating most abstractions provided by shared libraries. If possible, ask the author of the shared library to give help and perhaps implement some plugin machinery in it.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Now that was valuable response. +1 for that. I know about mprotect, but I didnt' know dladdr existed. So far I had only found exported function's starting address by reading the st_value for the exported function (that's what dlsym also does, i.e. it gives address of the procedure). I will try dladdr along with mprotect. – Usman.3D Apr 20 '15 at 05:25
  • About hacking the dynamic linker: I think it will be too complicated and I'm not sure even if I have any control over that at android(?) I'm building my hooking module itself as a .so file that will be used by the game's app. I want to note here that I had successfully hooked for the OpenGL import functions only because their symbol entry has GOT entry address and not procedure's address itself. – Usman.3D Apr 20 '15 at 05:33
  • What is Unity? If it is a proprietary game, are you so "addict" to it to spend a week or two of your time for such hacks? I'm surprised! BTW, check that what you want to do is legal in your juridiction! – Basile Starynkevitch Apr 20 '15 at 05:37
  • Unity3D is a game engine where you setup your game assets and scripts and it generates the game app or project for virtually any gaming platform. I'm not addicted to do any illegal hack but I want to build a solution that can work for any Unity game WITH the consent of the game developer. Actually there are two such solutions in the market who are doing some hacks to capture screen+audio; namely: Everyplay and Kamcord. I just want to build a similar solution. – Usman.3D Apr 20 '15 at 06:16
  • Update2 added to my question – Usman.3D Apr 21 '15 at 09:02