Can a program make itself immune to an interposer? - Unix

This is a discussion on Can a program make itself immune to an interposer? - Unix ; Note: The question is posed in that way, suggesting that I am looking for a way to make my program immune. However, in fact, I'm looking at it the other way - I have written an interposer, but somehow it ...

+ Reply to Thread
Results 1 to 14 of 14

Thread: Can a program make itself immune to an interposer?

  1. Can a program make itself immune to an interposer?

    Note: The question is posed in that way, suggesting that I am looking
    for a way to make my program immune. However, in fact, I'm looking at
    it the other way - I have written an interposer, but somehow it is not
    working (in one case).

    Longer version: I have written an interposer for the POSIX open()
    function. This is not at all the first interposer I've written, and it
    works fine with a little test program that I have written. However, it
    does not work (that is, I can tell that my interposer is not called),
    when used with GAWK.

    I am invoking gawk as:

    LD_PRELOAD=./libopen_fix.so gawk '{print FILENAME,$0}' "$@"

    and yet the interposer never gets called. GAWK *is* dynamically linked:

    (output of "ldd gawk")
    linux-gate.so.1 => (0xb7ee8000)
    libdl.so.2 => /lib/libdl.so.2 (0xb7ed2000)
    libm.so.6 => /lib/libm.so.6 (0xb7ead000)
    libc.so.6 => /lib/libc.so.6 (0xb7d74000)
    /lib/ld-linux.so.2 (0xb7ee9000)

    Any ideas?


  2. Re: Can a program make itself immune to an interposer?

    >Note: The question is posed in that way, suggesting that I am looking
    >for a way to make my program immune. However, in fact, I'm looking at
    >it the other way - I have written an interposer, but somehow it is not
    >working (in one case).
    >
    >Longer version: I have written an interposer for the POSIX open()
    >function. This is not at all the first interposer I've written, and it
    >works fine with a little test program that I have written. However, it
    >does not work (that is, I can tell that my interposer is not called),
    >when used with GAWK.


    Theory 1: What happens with your interposer if the program never
    calls open() directly but only calls fopen(), which then calls
    open() *from libc.a*? Can you interpose calls from a library to
    that same library? You could interpose fopen(), probably.

    Theory 2: What happens with your interposer if the program never
    calls open() directly, but only calls fopen(), which then calls
    some internal synonym for open like _open()? This one I'm fairly
    sure will result in the interposer never getting called.


    This is one of the problems with interposers: the whole thing seems
    pretty fragile when applied to system libraries.


  3. Re: Can a program make itself immune to an interposer?

    In article ,
    Gordon Burditt wrote:
    >>Note: The question is posed in that way, suggesting that I am looking
    >>for a way to make my program immune. However, in fact, I'm looking at
    >>it the other way - I have written an interposer, but somehow it is not
    >>working (in one case).
    >>
    >>Longer version: I have written an interposer for the POSIX open()
    >>function. This is not at all the first interposer I've written, and it
    >>works fine with a little test program that I have written. However, it
    >>does not work (that is, I can tell that my interposer is not called),
    >>when used with GAWK.

    >
    >Theory 1: What happens with your interposer if the program never
    >calls open() directly but only calls fopen(), which then calls
    >open() *from libc.a*? Can you interpose calls from a library to
    >that same library? You could interpose fopen(), probably.
    >
    >Theory 2: What happens with your interposer if the program never
    >calls open() directly, but only calls fopen(), which then calls
    >some internal synonym for open like _open()? This one I'm fairly
    >sure will result in the interposer never getting called.


    Well, I am pretty sure it is something like that. However, a key piece
    of information that I had meant to include in my OP, but forgot to
    include is that I ran "strace" on GAWK and strace does show GAWK calling
    open() - with the parameters that I expect. So, it seems clear that it
    is calling some version of open() - but not mine. Note further that I
    first tried interposing "fopen()" and convinced myself that GAWK does
    *not* call fopen().

    Incidentally, is that how it works - that if the app calls libc.foo()
    and libc.foo() calls bar() and bar is also in libc, then any bar()
    interposer will be left out of the loop?

    >This is one of the problems with interposers: the whole thing seems
    >pretty fragile when applied to system libraries.


    It is a hack. A useful and fun hack...
    When it works, great; when it doesn't - well, you tried.


  4. Re: Can a program make itself immune to an interposer?

    >>>Note: The question is posed in that way, suggesting that I am looking
    >>>for a way to make my program immune. However, in fact, I'm looking at
    >>>it the other way - I have written an interposer, but somehow it is not
    >>>working (in one case).
    >>>
    >>>Longer version: I have written an interposer for the POSIX open()
    >>>function. This is not at all the first interposer I've written, and it
    >>>works fine with a little test program that I have written. However, it
    >>>does not work (that is, I can tell that my interposer is not called),
    >>>when used with GAWK.

    >>
    >>Theory 1: What happens with your interposer if the program never
    >>calls open() directly but only calls fopen(), which then calls
    >>open() *from libc.a*? Can you interpose calls from a library to
    >>that same library? You could interpose fopen(), probably.
    >>
    >>Theory 2: What happens with your interposer if the program never
    >>calls open() directly, but only calls fopen(), which then calls
    >>some internal synonym for open like _open()? This one I'm fairly
    >>sure will result in the interposer never getting called.

    >
    >Well, I am pretty sure it is something like that. However, a key piece
    >of information that I had meant to include in my OP, but forgot to
    >include is that I ran "strace" on GAWK and strace does show GAWK calling
    >open() - with the parameters that I expect.


    Doesn't strace operate on actual kernel calls? It wouldn't matter
    what the name of the libc routine is. If the %qzx_dammit register
    [1] is set to SYS_open and the kernel gets a syscall trap, that's
    an open even if the code being executed is buffer overflow trash,
    and that's what strace will call it. And it definitely won't
    distinguish between a call to _open() and a call to open() which
    calls _open(). There's also the possibility that it's using
    syscall(), which seems pretty wierd for a program trying to be
    portable.

    [1] Your platform probably doesn't have a %qzx_dammit register, but
    the kernel trap indicates *somehow* which call it is, and the details
    aren't that important here.

    Another question: if gdb (or whatever debugger) is tracing
    instructions, and a particular function has an address associated
    with *5* names: open, _open, _QZX_gerbil_teeth, _QZX_rat_burger,
    and _QZX_eat_madagascar_hissing_****roach, which name will it display
    in a traceback? Interposing works on the *name*, not the address,
    as I understand it, so interposing open() won't interpose _open(),
    even if they have the same address (and, obviously, the same code).

    Interposing works on global symbols. If _open() is a *non-global*
    symbol in libc, and open() calls it from libc, and you try interposing
    _open(), I'd expect interposing to fail ("symbol not found"). Does
    your interposing code check for this happening, and report it?


    >So, it seems clear that it
    >is calling some version of open() - but not mine. Note further that I
    >first tried interposing "fopen()" and convinced myself that GAWK does
    >*not* call fopen().
    >
    >Incidentally, is that how it works - that if the app calls libc.foo()
    >and libc.foo() calls bar() and bar is also in libc, then any bar()
    >interposer will be left out of the loop?


    That's definitely the case if bar() is not a global symbol. It may
    be implementation-dependent if bar() is a global symbol resolved
    by the runtime linker. What does the linker do: resolve
    call-to-own-library global-symbol calls at *link* time or *run*
    time? That could be up to the implementation, and it affects
    interposing.

    >>This is one of the problems with interposers: the whole thing seems
    >>pretty fragile when applied to system libraries.

    >
    >It is a hack. A useful and fun hack...
    >When it works, great; when it doesn't - well, you tried.


    Some descriptions of what people do/did with Windows/DOS suggest that
    the whole OS is based on a couple dozen layers of interposing between
    the user-level Windows/DOS program and the base viruses that comprise
    the core OS. Naturally, the issue of what registers need to be
    saved/restored when interposing is not documented.


  5. Re: Can a program make itself immune to an interposer?

    On Aug 19, 7:56 pm, gordonb.eo...@burditt.org (Gordon Burditt) wrote:
    ....
    > Theory 2: What happens with your interposer if the program never
    > calls open() directly, but only calls fopen(), which then calls
    > some internal synonym for open like _open()? This one I'm fairly
    > sure will result in the interposer never getting called.


    This is the normal situation. Indeed, it's practically required by
    the C standard! In particular, 'open' is not reserved by the C
    standard, so the fopen() implementation can't be affected by an
    application defining a function (or data member!) with that name.
    Making that true for the application but not an interposer seems like
    a waste of effort: I don't know of any implementations that bother.
    So everyone has a symbol in the reserved namespace, like '_open', as
    the real name, and then fopen() uses that and 'open' is provided as a
    weak symbol for POSIX applications, but overrideable/ignorable for
    pure C applications.

    (rule: no function defined by the C standard can depend on a symbol
    that isn't defined or reserved by the C standard.)

    Philip Guenther

  6. Re: Can a program make itself immune to an interposer?

    gazelle@shell.xmission.com (Kenny McCormack) writes:

    > Note: The question is posed in that way, suggesting that I am looking
    > for a way to make my program immune. However, in fact, I'm looking at
    > it the other way - I have written an interposer, but somehow it is not
    > working (in one case).


    Short answer: sure, just link it statically.
    Or don't call any libc functions directly; instead do this:

    void *h = dlopen("/lib/libc.so.6", RTLD_LAZY);
    int (*p_open)() = dlsym(h, "open");
    int fd = p_open("/etc/passwd", O_RDONLY); // foil interposers!

    > Longer version: I have written an interposer for the POSIX open()
    > function. This is not at all the first interposer I've written, and it
    > works fine with a little test program that I have written. However, it
    > does not work (that is, I can tell that my interposer is not called),
    > when used with GAWK.


    That's because Linux gawk doesn't call open. It was compiled with
    large file support, and calls open64:

    $ readelf -s /usr/bin/gawk | grep ' open'
    296: 00000000 189 FUNC GLOBAL DEFAULT UND open64@GLIBC_2.1 (3)

    Cheers,
    --
    In order to understand recursion you must first understand recursion.
    Remove /-nsp/ for email.

  7. Re: Can a program make itself immune to an interposer?

    gazelle@shell.xmission.com (Kenny McCormack) writes:

    > Well, I am pretty sure it is something like that. However, a key piece
    > of information that I had meant to include in my OP, but forgot to
    > include is that I ran "strace" on GAWK and strace does show GAWK calling
    > open() - with the parameters that I expect. So, it seems clear that it
    > is calling some version of open() - but not mine.


    The 'strace' only proves that the open system call was executed,
    not that some version of libc open() was called. Also, if you look
    *really* close, you'll likely discover that strace shows open with
    slightly different parameters than what you expect.

    > Note further that I
    > first tried interposing "fopen()" and convinced myself that GAWK does
    > *not* call fopen().
    >
    > Incidentally, is that how it works - that if the app calls libc.foo()
    > and libc.foo() calls bar() and bar is also in libc, then any bar()
    > interposer will be left out of the loop?


    Not necessarily. Many glibc symbols have several aliases, some of
    which are marked "internal". A call to "internal" alias (such as
    a call to open from fopen) will not be interposable, but a call
    to non-internal one (such as a call to malloc from strdup) will be
    fully interposable.

    Cheers,
    --
    In order to understand recursion you must first understand recursion.
    Remove /-nsp/ for email.

  8. Re: Can a program make itself immune to an interposer?

    In article ,
    Paul Pluzhnikov wrote:
    ....
    >That's because Linux gawk doesn't call open. It was compiled with
    >large file support, and calls open64:
    >
    > $ readelf -s /usr/bin/gawk | grep ' open'
    > 296: 00000000 189 FUNC GLOBAL DEFAULT UND open64@GLIBC_2.1 (3)


    Short summary: That's it! I changed it to interpose open64() and it works.

    Side note: I had thought (before posting) that that was it - I knew that
    gawk was using the large file stuff and thus open64(). I just hadn't
    gotten around to testing it before I posted.

    Thanks for the tip on readelf - that's useful, too.

    P.S. To all those who posted in this thread about "The C standard,
    blah, blah, blah" - stuff it! And go back to clc, where they like that
    sort of thing.


  9. Re: Can a program make itself immune to an interposer?

    In article ,
    Gordon Burditt wrote:
    ....
    >Some descriptions of what people do/did with Windows/DOS suggest that
    >the whole OS is based on a couple dozen layers of interposing between
    >the user-level Windows/DOS program and the base viruses that comprise
    >the core OS. Naturally, the issue of what registers need to be
    >saved/restored when interposing is not documented.


    Heh - good quote. Belongs on my cork board.

    Anyway, I got it sorted. Thanks for the commentary.


  10. Re: Can a program make itself immune to an interposer?

    gazelle@shell.xmission.com (Kenny McCormack) writes:
    >In article ,
    >Gordon Burditt wrote:
    >>>Note: The question is posed in that way, suggesting that I am looking
    >>>for a way to make my program immune. However, in fact, I'm looking at
    >>>it the other way - I have written an interposer, but somehow it is not
    >>>working (in one case).
    >>>
    >>>Longer version: I have written an interposer for the POSIX open()
    >>>function. This is not at all the first interposer I've written, and it
    >>>works fine with a little test program that I have written. However, it
    >>>does not work (that is, I can tell that my interposer is not called),
    >>>when used with GAWK.

    >>
    >>Theory 1: What happens with your interposer if the program never
    >>calls open() directly but only calls fopen(), which then calls
    >>open() *from libc.a*? Can you interpose calls from a library to
    >>that same library? You could interpose fopen(), probably.
    >>
    >>Theory 2: What happens with your interposer if the program never
    >>calls open() directly, but only calls fopen(), which then calls
    >>some internal synonym for open like _open()? This one I'm fairly
    >>sure will result in the interposer never getting called.

    >
    >Well, I am pretty sure it is something like that. However, a key piece
    >of information that I had meant to include in my OP, but forgot to
    >include is that I ran "strace" on GAWK and strace does show GAWK calling
    >open() - with the parameters that I expect. So, it seems clear that it
    >is calling some version of open() - but not mine. Note further that I
    >first tried interposing "fopen()" and convinced myself that GAWK does
    >*not* call fopen().


    ltrace may be more useful in this case then strace. All strace shows
    is that the system call has been invoked (via int $80 or syscall insn),
    not that any entry point named 'open' was called.

    scott

  11. Re: Can a program make itself immune to an interposer?

    Paul Pluzhnikov writes:

    > gazelle@shell.xmission.com (Kenny McCormack) writes:
    >
    >> Note: The question is posed in that way, suggesting that I am looking
    >> for a way to make my program immune. However, in fact, I'm looking at
    >> it the other way - I have written an interposer, but somehow it is not
    >> working (in one case).

    >
    > Short answer: sure, just link it statically.
    > Or don't call any libc functions directly; instead do this:
    >
    > void *h = dlopen("/lib/libc.so.6", RTLD_LAZY);
    > int (*p_open)() = dlsym(h, "open");
    > int fd = p_open("/etc/passwd", O_RDONLY); // foil interposers!


    It's easy enough to interpose dlopen() and dlsym(), and fake anything
    you want. If an executable needs something from another file, there
    is always a way to get in between.

    --
    Måns Rullgård
    mans@mansr.com

  12. Re: Can a program make itself immune to an interposer?

    On Aug 20, 6:26 am, gaze...@shell.xmission.com (Kenny McCormack)
    wrote:
    > P.S. To all those who posted in this thread about "The C standard,
    > blah, blah, blah" - stuff it! And go back to clc, where they like that
    > sort of thing.


    Heh. Don't worry, that information wasn't for you. It was for the
    other people in this newsgroup who in the past have wondered why
    fopen() doesn't call (their) open(). Someone people actually prefer
    explanations to bare claims.


    Philip Guenther

  13. Re: Can a program make itself immune to an interposer?

    In article <6vYqk.37176$ZE5.16164@nlpi061.nbdc.sbc.com>,
    Scott Lurndal wrote:
    ....
    >
    >ltrace may be more useful in this case then strace. All strace shows
    >is that the system call has been invoked (via int $80 or syscall insn),
    >not that any entry point named 'open' was called.


    Thanks. I knew there was a way to do it at the lib level, not (just)
    the system level - but I couldn't find it. I thought it was an option
    to strace, not a separate (different) program.


  14. Re: Can a program make itself immune to an interposer?

    Paul Pluzhnikov writes:

    > Måns Rullgård writes:
    >
    >> It's easy enough to interpose dlopen() and dlsym(), and fake anything
    >> you want.

    >
    > Actually, interposing dlsym() is non-trivial: how are you going to
    > find the original to call?


    I can include my own libdl with renamed functions. I can even make
    them inaccessible outside the library if I choose.

    >> If an executable needs something from another file, there
    >> is always a way to get in between.

    >
    > In this particular case, everything is already in memory, so with
    > sufficient understanding of ELF, all interposers could be avoided.


    How did it get into memory? ld.so put it there. If I ptrace the
    loading, I can replace anything it tries to access with other data.

    I didn't say it would be easy, only that it can be done.

    If all else fails, modifying the original executable is always an
    option. That is, however, a somewhat different game.

    --
    Måns Rullgård
    mans@mansr.com

+ Reply to Thread