11

How do I, at run-time (no LD_PRELOAD), intercept/hook a C function like fopen() on Linux, a la Detours for Windows? I'd like to do this from Python (hence, I'm assuming that the program is already running a CPython VM) and also reroute to Python code. I'm fine with just hooking shared library functions. I'd also like to do this without having to change the way the program is run.

One idea is to roll my own tool based on ptrace(), or on rewriting code found with dlsym() or in the PLT, and targeting ctypes-generated C-callable functions, but I thought I'd ask here first. Thanks.

Yang
  • 16,037
  • 15
  • 100
  • 142
  • How would you do it *with* LD_PRELOAD? – Matt Joiner Feb 04 '11 at 00:10
  • You'll need to write a native module to do the low-level work for you. Even if you manage to access and modify the PLT from Python (which is probably possible), you'll need code to launch the Python VM. – Glenn Maynard Feb 04 '11 at 00:43
  • 1
    @Matt Joiner: By the way you're asking your question, I take it you don't like something I said, in which case it would be productive/constructive if you could be more specific. But in case you were really just asking, this is how you do function interposition non-dynamically: http://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick (and, yes, I've applied this many a time before) – Yang Feb 04 '11 at 00:51
  • @Glenn Maynard: Sorry if my question wasn't clear - I mentioned I'd like to do this from Python, so the assumption is that the VM is already running. But anyway I tweaked the question to clarify this. Manipulating the PLT from Python is precisely what I was getting at with my strawman. – Yang Feb 04 '11 at 00:59
  • It's not about creating the VM instance, it's about calling into it; you can't point the PLT at a Python function, after all, you need to point it at native code that calls the Python runtime and runs the function you want. – Glenn Maynard Feb 04 '11 at 01:29
  • @Yang: I am genuinely interested. I'm familiar with the LD_PRELOAD method and don't see how it's reasonably possible using Python. If you have links to this effect I'm very interested. – Matt Joiner Feb 04 '11 at 09:04
  • @Matt Joiner: Ah, OK - I also didn't mean to imply that I'd jumped into Python before using LD_PRELOAD. You would do it with C code that calls into the Python you want. Another reason why LD_PRELOAD is unsuitable. – Yang Feb 09 '11 at 02:06
  • @Glenn Maynard: ctypes allows you to create C callable function pointers from Python callables, so I'm hoping I can call into such a function from the PLT. – Yang Feb 09 '11 at 02:07
  • Yang did you ever find a solution to this? Was it possible to modify the PLT? – Matt Joiner Jan 17 '12 at 10:42
  • @MattJoiner Sadly, I haven't found a solution yet (though I still believe it's possible!) – Yang Jan 17 '12 at 18:57
  • Maybe you could write a kernel module to catch fopen? Just brainstorming. – gogators Jan 23 '12 at 01:39
  • I'd suggest that if modifying the execution environment is out of the question, loading arbitrary kernel modules is probably right out. – richo Jan 23 '12 at 01:45
  • `fopen` isn't a kernel function – Matt Joiner Jan 23 '12 at 08:03

2 Answers2

2

google-perftools has their own implementation of Detour under src/windows/preamble_patcher* . This is windows-only at the moment, but I don't see any reason it wouldn't work on any x86 machine except for the fact that it uses win32 functions to look up symbol addresses.

A quick scan of the code and I see these win32 functions used, all of which have linux versions:

  • GetModuleHandle/GetProcAddress : get the function address. dlsym can do this.
  • VirtualProtect : to allow modification of the assembly. mprotect.
  • GetCurrentProcess: getpid
  • FlushInstructionCache (apparently a nop according to the comments)

It doesn't seem too hard to get this compiled and linked into python, but I'd send a message to the perftools devs and see what they think.

user314104
  • 1,528
  • 14
  • 31
aaron
  • 1,746
  • 1
  • 13
  • 24
  • Care to explain what assembly is modified? – Matt Joiner Feb 12 '11 at 15:01
  • Please link to the mentioned source file. – Matt Joiner Jan 24 '12 at 16:01
  • http://code.google.com/codesearch#BGeH2W13jNw/trunk/src/windows/preamble_patcher.cc&q=preamble_patcher%20package:http://gperftools%5C.googlecode%5C.com, win32 function calls leave a few instructions at the start of every function call that can be changed into a jump to whatever function you want. – aaron Feb 02 '12 at 18:24
2

You'll find from one of ltrace developer a way to do this. See this post, which includes a full patch in order to catch dynamically loaded library. In order to call it from python, you'll probably need to make a C module.

Coren
  • 5,517
  • 1
  • 21
  • 34