|
Wrapper Redirection
Before using DDL we might need to make some changes in our source code
so that we can intercept calls to all the functions which we want to
wrap/redirect.
Changes Required In C Code
- The target functions (the functions which we want
to redirect) should be non-static.
- The target functions that are present in the main
executable and are not in the shared object should be “called” from a
shared object file, these calls may never execute, and by doing this
the linker links the calls to these functions dynamically and we are
able to intercept them.
- To make sure that there is no statically linked
call to any target function we can use objdump command:
objdump -d executable_file
| grep call | grep target_func_name
We don't need to make any change for the functions which are already
present in shared objects.
Writing
Wrapper
Functions
In normal redirection each target functions is wrapped by a different
wrapper function, unlike table based redirection in which all the
target functions are wrapped by a single function.
We have added two mechanisms that make writing wrappers and runtime
monitors much easier.
The first is a function void redirect_ignore_next(char *name, char*
libname). This
function, when called with a function name and the library name of the
wrapper library as parameters, tells the
redirection code to ignore the next link request for this function.
That is, it will not redirect the next link request for this function,
even if this function is on the list of functions to be redirected.
What this means is that a wrapper, e.g., named "func_wrap", can simply
call the actual function, e.g., "func", by name, by first doing a void
redirect_ignore_next("func","wraplib"), and then calling the function.
This mechanism
will only ignore the single next call to the function. It automatically
disables itself after one call.
Of course, the dynamic linking process only happens once, on the first
call to this function in this shared object, so after the call to the
function, the wrapper should do a void redirect_ignore_next("","") to
disable
the ignoring of the function.
The second mechanism is a global flag do_redirect (note this
should be changed to a set/clear API). This turns on redirection
globally. It
is very similar to the _redirect_isactive flag we added to the linker
itself, but this controls the user-level redirection library. This is
useful to
turning off redirection while you are in your analysis or monitoring
code,
or whatever code in your wrapper you want to avoid doing any
redirection
on.
You might be wondering why the first (specific) mechanism is needed if
we have a global flag. The reason that you cannot use the above flag to
disable redirection for the wrapped function call is that the wrapped
function
may call other functions in the application, and you may want to
intercept
those. So, general redirection needs to be on when we enter application
code, but to get there we have to disable the redirection for the
specific
next function call.
So, a wrapper might look like:
A Sample Wrapper Function
|
void myputchar (int c)
{
// turn off
redirection
for my wrapper code
do_redirect =
0;
//
// put my pre-call
monitoring/logging/whatever code in here
//
// now be sure not
to
redirect my own putchar call
redirect_ignore_next("putchar","libWrappers");
// turn redirection
back on
do_redirect = 1;
// call the real
putchar
function
putchar (c);
// turn off
redirection
again, for the rest of my wrapper
do_redirect = 0;
// turn off skipping
redirection of putchar
_dl_ignore_next("");
//
// put my post-call
monitoring/logging/whatever code here
//
// turn on
redirection
before we leave
do_redirect = 1;
return;
}
|
Compiling
Wrapper
functions
The wrapper functions can be compiled in two ways:
1. Write wrapper functions and compile them into a
shared object file. Add this file to LD_WRAP_LIB. Our loader will load
this
library before the main executable is loaded. The wrapper shared object
should be compiled in this way :
cc -fPIC -shared -Wall
2. Write wrapper functions in the file that contains
the main function. This becomes necessary when we want to access any
global variable, which is declared in the main file, from our wrapper
function. The reason behind this is we need to declare global
variables as extern in our wrapper functions and as the loader tries to
load the wrapper library before the main executable is loaded, it fails
to resolve the external references.
|