I know that I can change the file a program writes to by interrupting the process in gdb, closing using the file descriptor and then re-opening with the file name I want. Is there a way to do the same thing at run time?
For example I know that the file I want to change uses file descriptor 5 so I tried
./myexe 5>/dev/null
But all that does is change things so the file of interest is on fd=6.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
When a program opens a file, that file ends up on a file descriptor that’s free at the time. By opening a file before the program starts, you’re only making one more file descriptor busy, so the file you’re interested in might end up on a different descriptor. If you want the program to open a different file, you’ll need to modify the open operation when it takes place, or intervene afterwards.
One way to modify the operation is to wedge some code between the program and the system library, by preloading a small piece of code. This assumes that the program is a dynamically linked binary, or a script executed by a dynamically linked binary (i.e. it isn’t statically linked). Write the following code to a file override_fopen.c:
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef FROM
#error "Define FROM to the path to override in double quotes, e.g. -DFROM='"/bad"'"
#endif
#ifndef TO
#error "Define TO to the path to use instead in double quotes, e.g. -DFROM='"/good"'"
#endif
FILE *fopen(const char *path, const char *mode) {
void *(*original_fopen)(const char *, const char *) = dlsym(RTLD_NEXT, "fopen");
if (!strcmp(path, FROM)) {
path = TO;
}
return original_fopen(path, mode);
}
int open(const char *path, int oflag, ...) {
int (*original_open)(const char *, int, ...) = dlsym(RTLD_NEXT, "open");
int ret;
va_list args;
if (!strcmp(path, FROM)) {
path = TO;
}
va_start(args, oflag);
if (oflag & O_CREAT) {
ret = original_open(path, oflag, (mode_t)va_arg(args, mode_t));
} else {
ret = original_open(path, oflag);
}
va_end(args);
return ret;
}
Compile with the following command (that’s for Linux, other Unix variants may require different options). Note the quotes around the path you want to override.
gcc -DFROM='"/some/path"' -DTO='"/dev/null"' -D_GNU_SOURCE -O -Wall -fPIC -shared -o override_fopen.so override_fopen.c -ldl
Run the program as follows (on OSX, use DYLD_PRELOAD instead of LD_PRELOAD):
LD_PRELOAD=./override_fopen.so ./myexe
This only works if the program is calling the fopen or open library function. If it calls some other function, you’ll need to override that one. You can use ltrace to see what library calls the program makes.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0