|
Table Based
Redirection
Table-based redirection allows you to use a "jump table" type of redirection.
With Table-Based we can redirect all out target functions to a single
wrapper function.
Example:
This is a sample for table based redirection. This code his following
properties :
1. Tablesize = 4
The table can have maximum of 4 entries
2. Argument bytes = 16
The code argument bytes of all the target functions must be less
than or equal to 16.
3. Jump Index Variable = _jt_func_index
This variable is used to index the entries in jump table.
4. Jump Table Name = _jt_jumptable
All the target functions will be redirected to this location plus some
offset.
5. Jump Function Name = _jt_jumppoint
This is the wrapper function for all target functions.
6. First entry is at _jt_jumptable + 3, each entry is 15 bytes
7. Entry address equation is (_jt_jumptable + 3 + i*15), i is
index
of entry (starting at 0)
Sample Source Code:
int _jt_func_index;
void _jt_jumptable()
{
asm("\
movl $0,
_jt_func_index\n\
jmp
_jt_jumppoint\n\
movl $1,
_jt_func_index\n\
jmp
_jt_jumppoint\n\
movl $2,
_jt_func_index\n\
jmp
_jt_jumppoint\n\
movl $3,
_jt_func_index\n\
jmp
_jt_jumppoint\n\
movl $4,
_jt_func_index\n\
jmp
_jt_jumppoint\n\
");
}
struct jt_args {
int a0;
int a1;
int a2;
int a3;
};
// an array to store
the
symbol names
char* _jt_symboltable[4];
//array of function
pointers to
store original functions
int
(*_jt_ptrtable[4])(struct
jt_args args);
int _jt_nextstentry = 0;
int _jt_nextoffset = 0;
int _jt_get_tableoffset(char
*funcname)
{
if (_jt_nextstentry >= 4)
return -1;
_jt_symboltable[_jt_nextstentry] = strdup(funcname);
_jt_ptrtable[_jt_nextstentry] = 0;
_jt_nextoffset = 3 + 15 * _jt_nextstentry;
_jt_nextstentry++;
return _jt_nextoffset;
}
int _jt_jumppoint
(struct
jt_args
args)
{
int retval;
do_redirect = 0;
//
// put my pre-call
monitoring/logging/whatever code in here
//
if (!_jt_ptrtable[_jt_func_index])
{
_jt_ptrtable[_jt_func_index] = dlsym((void *)-1l,
_jt_symboltable[_jt_func_index]);
if
(!_jt_ptrtable[_jt_func_index])
{
fprintf(stderr,"Error: function
%s cannot be found\n",_jt_symboltable[_jt_func_index]);
exit(1);
}
}
retval = (_jt_ptrtable[_jt_func_index])(args);
//
// put my post-call
monitoring/logging/whatever code in here
//
do_redirect = 1;
return retval;
}
Explanation of Sample Code:
void _jt_jumptable();
The symbol "_jt_jumptable" is the beginning of the jump table, and then
you need to look at the object code to figure out the correct offsets.
Each "mov" instruction begins a new table entry. The idea in the above
code
is to identify each function by an ID number, and then redirect them
all
to a single wrapper function. The wrapper function can then use the ID
to
know which function it is currently handling. Obviously, there is more
programming to support all of this, but the foundational capability is
already there.
struct jt_args; The wrapper function can handle
functions
of different argument sizes but still we need to specify the maximum
size
of the arguments while writing the wrapper function. In this example we
can wrap functions with argument size of 16 maximum. For this we are
passing a
structure of size 16 (4 integers) to our wrapper function.
int
_jt_get_tableoffset(char *funcname)
This function is called by the redirection library to find
the
table
offset of the functions which is being resolved. In this function we
also store the
function name in an array, store its address in function pointer array
and calculate the offset for the next entry in jump table. The next
offset is calculated by this statement;
_jt_nextoffset = 3 + 15 *
_jt_nextstentry;
int _jt_jumppoint (struct jt_args args); This is the
actual
wrapper function. All the "wrapped" functions jump to this function
from the jump table. This is the place where we add "pre-call" and
"post-call" code for all the "wrapped" function.
|