1

I am trying to hook some glibc functions that has works with file names. Basically I need to modify the filename a bit, then pass it along with other arguments to the original glibc functions.

The code looks like this:

FILE *fopen(const char *filename, const char *modes) {
  filename = modify(filename); // assuming we don't need to free the new filename pointer for now
  using FuncT = FILE*(*) (const char *, const char *);
  static FuncT originalFunc = (FuncT)dlsym(RTLD_NEXT, "fopen");
  return originalFunc(filename, modes);
}

This works fine for most cases, but when it comes to variadic arguments for function like int execl(const char *path, const char *arg, ...), How can I do it properly?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Terry Shen
  • 11
  • 1
  • 4
    Common variadic functions in the standard library have versions that take a `va_list` argument, like `vsnprintf()`. – Lee Daniel Crocker Jan 03 '20 at 20:54
  • Where can I find these functions that takes va_list, for example for `execl`? – Terry Shen Jan 03 '20 at 20:58
  • 3
    Finding the va_list version is all case-by-case. In the specific case of `execl`, the [documentation for execl](https://linux.die.net/man/3/execl) also mentions the `execv` function, which looks like what you want. – Raymond Chen Jan 03 '20 at 21:01
  • 1
    Isn't the dialect of C that supports notation such as `using FuncT = FILE*(*) (const char *, const char *);` usually called C++? Or is it a feature of `glibc` somehow? – Jonathan Leffler Jan 03 '20 at 21:48
  • regarding `FILE *fopen(const char *filename, const char *modes) {` and `filename = modify(filename);` since the parameter `filename` is 'pointer to a char constant, cannot modify the data where the filename points. *which is a constant* however, can modify that pointer – user3629249 Jan 05 '20 at 04:35
  • `vsprintf` takes a `va_list` argument, while `execv` takes `char *const []`. Is `va_list` just `char *const []`, or is there a way to convert? – Terry Shen Jan 06 '20 at 21:45
  • @Terry Shen neither is true; actually va_list is very much platform-dependent. – Lorinczy Zsigmond Jan 23 '20 at 19:47

2 Answers2

1

Basically, you can't -- there's no way to copy the (unparsed) argument list you get and pass it to another varargs function. That's why all varags functions come in two forms -- one that takes ... and one that takes the arguments more concretely (an explicit va_list or an array pointer).

In the case of execl, the corresponding function is execv -- if you want to intercept and "wrap" execl, your replacement function will need to extract the arguments from the va_list and then call execv with the resulting array.

Note that all the execX functions in the library are usually just written as wrappers that call execve, so you probably only need to intercept execve and you'll effectively be intercepting all of them.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

To pass variable number parameters you need to know how many you expect or have a parameter with the special value (like in the example below - NULL ends the parameters list). printf for example knows what to expect from the format string.

This function concatenates strings.

#include <stdio.h>
#include <stdarg.h>

char *concat(char *s1, ...)
{
    char *saved = s1;
    char *s2;
    va_list ap;
    va_start(ap, s1);
    if(s1)
    {
        while(*s1) s1++;
        while((s2 = va_arg(ap, char *))) while(*s2) *s1++ = *s2++;
    }
    va_end(ap);
    return saved;
}

int main()
{
    char s1[64] = "Hello";
    printf("%s\n", concat(s1," World", " !12345!", " QWWERTY ", "@@", NULL));

    return 0;
}

You cam play and experiment with this example yourself here: https://onlinegdb.com/HkY5a7pJL

0___________
  • 60,014
  • 4
  • 34
  • 74
  • So you suggest to reimplement parsing of function that OP wants to wrap... :/ And even with that, how to call original function? – Jarod42 Jan 03 '20 at 21:24