GJDuck / e9patch

A powerful static binary rewriting tool
GNU General Public License v3.0
986 stars 67 forks source link

Return value of call trampolines. #64

Closed Emegua closed 1 year ago

Emegua commented 1 year ago

If I have my own implementation of malloc called myMalloc, and if I want to instrument a binary to use myMalloc instead of malloc, what arguments should I pass for e9tool. I used the following command:

./e9tool --option --debug=true -s -M '(call and target==&malloc)' -P 'replace myMalloc@my_malloc' test

The call to malloc is replaced with a corresponding jump instruction, but how can I make sure the pointer to the allocated memory space is correctly returned from myMalloc?

Thanks.

GJDuck commented 1 year ago

Some knowledge of x86_64 calling conventions is necessary. Specifically, the first argument (the size) is stored in register %rdi, and the return value will be stored in register %rax. So myMalloc can take two arguments, e.g.:

    #include "stdlib.c"
    void myMalloc(intptr_t rdi, intptr_t *rax)
    {
        // Example: replace with stdlib.c malloc():
        *rax = (intptr_t)malloc(rdi);
    }

    e9tool -M  '((call or jmp) and target==&malloc)' -P 'replace myMalloc(%rdi,&%rax)@my_malloc' test

Note the (call or jump) since the program may use jmp for tail calls.

Note that replacing the program's malloc() using this method will have other problems. You'd also need to replace free(), realloc(), calloc() as well as other memory allocation variants. You'd also need to (at least) replace free()/realloc() in all shared library dependencies too, since it is somewhat common that the main program will allocate a pointer that is free'ed by a library. Generally, I find it easier to replace malloc/free using the LD_PRELOAD trick rather than E9Patch.

Emegua commented 1 year ago

Thanks. That resolved the issue.

Emegua commented 1 year ago

I know using LD_PRELOAD is easier, but why do we need to replace free() if we replace malloc?

GJDuck commented 1 year ago

I know using LD_PRELOAD is easier, but why do we need to replace free() if we replace malloc?

It depends if you are changing the allocator. If you are, then the pointer created by your malloc may be passed to the glibc free() which will cause problems.