diff options
author | norly <ny-git@enpas.org> | 2013-06-20 01:56:24 +0100 |
---|---|---|
committer | norly <ny-git@enpas.org> | 2013-06-20 22:10:25 +0100 |
commit | b70b3ff9b1679bb1e0a215b7acd9b6d55497a46b (patch) | |
tree | d6e95ad143c7e2ec9ca39c1dd32c046fb9006eb9 /src/libelfu/modelops/detour.c | |
parent | 7f1a29e9e33059dfebdc24bb3ffaa3dac46b58f1 (diff) |
Separate library code, build .a/.so
Diffstat (limited to 'src/libelfu/modelops/detour.c')
-rw-r--r-- | src/libelfu/modelops/detour.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/libelfu/modelops/detour.c b/src/libelfu/modelops/detour.c new file mode 100644 index 0000000..075d945 --- /dev/null +++ b/src/libelfu/modelops/detour.c @@ -0,0 +1,51 @@ +#include <libelfu/libelfu.h> +#include <string.h> + +static void* subFindByAddr(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + GElf_Addr a = *(GElf_Addr*)aux1; + + if (OVERLAPPING(ms->shdr.sh_addr, ms->shdr.sh_size, a, 1)) { + return ms; + } + + /* Continue */ + return NULL; +} + + +void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to) +{ + ElfuScn *ms; + GElf_Word scnoffset; + unsigned char detourcode[] = {0xe9, 0xfc, 0xff, 0xff, 0xff}; + + ms = elfu_mScnForall(me, subFindByAddr, &from, NULL); + + if (!ms) { + ELFU_WARN("mDetour: Cannot find address %x in any section.\n", + (unsigned)from); + return; + } + + if (ms->shdr.sh_type != SHT_PROGBITS) { + ELFU_WARN("mDetour: Cannot detour in non-PROGBITS section %s.\n", + elfu_mScnName(me, ms)); + return; + } + + scnoffset = from - ms->shdr.sh_addr; + + if (ms->shdr.sh_size - scnoffset < 5) { + ELFU_WARN("mDetour: Not enough space to insert a detour.\n"); + return; + } + + ELFU_DEBUG("mDetour: Detouring at address %x in section %s to %x.\n", + (unsigned)from, + elfu_mScnName(me, ms), + (unsigned)to); + + *(Elf32_Word*)(detourcode + 1) = to - from - 5; + memcpy((char*)ms->data.d_buf + scnoffset, detourcode, 5); +} |