1

Basically, I'm trying to figure out how PIN tracks "Image" loads using IMG_AddInstrumentFunction. The documentation says "Use this to register a call back to catch the loading of an image". (There is an imageload pintool in source/tools/ManualExamples that uses this).

From what I understand an ELF binary that is executed(execve'd) is mmaped into memory by the kernel. If the executable has a PT_INTERP segment(pointing to something like ld-linux.so.2), it mmaps that file's segments into memory and passes control to it.

What I'm trying to figure out is : What behaviour causes PIN to recognise an "image load"?

Initially I thought it would be a set of open-fstat-mmap2-close system calls that would indicate an image load. PIN also shows that the initial executable image in the load, but as it cannot intercept mmap calls made from execve to kernel space, so I imagined that PIN would be monitoring execve's also.

However, when I tried using PIN with a UPX compressed binary on Linux(which ends up becoming stripped and statically linked), I could find no image loads at all(not even of the main executable image).

Why does this happen?

1 Answers1

2

What behaviour causes PIN to recognise an "image load"

There is a "standard" interface between the ld-linux.so and debuggers (such as GDB): every time an ELF image is loaded or unloaded, ld-linux sets a global variable _r_debug.r_state == RT_CONSISTENT and calls a function _dl_debug_state() (within itself). That function is usually just a single RET.

[This description is simplified from how it really works, but details of what actually happens are irrelevant here.]

The debugger is expected to set a breakpoint on _dl_debug_state, and then examine _r_debug.r_state and _r_debug.r_map to see what happened.

I imagine that PIN uses this same technique to watch for "normal" image loading and unloading.

when I tried using PIN with a UPX compressed binary ... I could find no image loads at all

That is what I would have expected: PIN looked at the UPX'd binary, discovered that it is fully-static, and didn't set any breakpoints (after all, ld-linux.so is not loaded in memory when control reaches UPX'd binary, so it couldn't set a breakpoint on _dl_debug_state even if it wanted to).

Running GDB on UPX'd binary, and setting stop-on-solib-events 1 also doesn't stop. IOW, UPX "fools" both GDB and PIN into thinking that shared libraries are not possible in this binary.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362