GJDuck / e9patch

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

What is the best way to add extern variable into the instrumentation? #72

Closed jjang3 closed 11 months ago

jjang3 commented 11 months ago

Hello,

This is quite weird because somehow, what was working is not working for me, and I'm lost on why that is the case. I am using an old commit, but I am hoping to see by asking this question whether it might be possible to figure out how to use it on the latest commit or whether this is even feasible anymore (I am really sure it was working before).

So I have these fours files to add support for extern global variable (for special purpose): print.c (I'm using the one from example), sub.c, sub.h, and global.h

Files look like this:

// print.c
/*
 * PRINT instrumentation.
 */

#include "../include/stdlib.c"
#include "../include/sub.h"
#include "../include/global.h"

#define RED     "\33[31m"
#define GREEN   "\33[32m"
#define YELLOW  "\33[33m"
#define WHITE   "\33[0m"

/*
 * Entry point.
 *
 * call entry(addr,instr,size,asm)@print
 */
void entry(const void *addr, const uint8_t *instr, size_t size,
    const char *_asm)
{
    sub_fun();
    static mutex_t mutex = MUTEX_INITIALIZER;
    if (mutex_lock(&mutex) < 0)
        return;

    clearerr_unlocked(stderr);
    fprintf_unlocked(stderr, RED "%.16lx" WHITE ": " YELLOW, addr);
    int i;
    for (i = 0; i < size; i++)
    {
        fprintf_unlocked(stderr, "%.2x ", instr[i]);
        if (i == 7 && size > 8)
            fprintf_unlocked(stderr, GREEN "%s" WHITE "\n                  "
                YELLOW, _asm);
    }
    if (i <= 8)
    {
        for (; i < 8; i++)
            fputs_unlocked("   ", stderr);
        fprintf_unlocked(stderr, GREEN "%s", _asm);
    }
    fputs_unlocked(WHITE "\n", stderr);
    fflush_unlocked(stderr);

    mutex_unlock(&mutex);
}

void init(void)
{
    setvbuf(stderr, NULL, _IOFBF, 0);
}

// sub.c
#include "../include/global.h"
#include "../include/sub.h"

void sub_fun(void)
{
    global_var = 1;
}

// sub.h
void sub_fun(void);

// global.h
extern int global_var;

After creating these files, I minimally modify e9compile.sh to add new sub.c and sub.o. It looks like this:

gcc -fno-stack-protector -fpie -O2 -Wno-unused-function -mno-mmx -mno-sse -mno-avx -mno-avx2 -mno-avx512f -msoft-float -fno-tree-vectorize -fomit-frame-pointer -I examples/ -c -Wall /home/e9stuff/src/sub.c /home/e9stuff/src/print.c

This will create sub.o and print.o which I will now try to link:

gcc print.o sub.o -o print -pie -nostdlib -Wl,-z -Wl,max-page-size=4096 -Wl,-z -Wl,norelro -Wl,-z -Wl,stack-size=0 -Wl,--export-dynamic -Wl,--entry=0x0 -Wl,--strip-all

However, this causes a weird linking error I didn't face before, and now I'm wondering what went wrong.

/usr/bin/ld: sub.o: warning: relocation against `global_var' in read-only section `.text'
/usr/bin/ld: sub.o: in function `sub_fun':
sub.c:(.text+0x2): undefined reference to `global_var'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

error: linking (print) failed

Would you happen to have any suggestions on how to fix this problem? I looked through stack_overflow, but the answers suggest it is a linking order problem. But I changed the order and tried to do everything I could think of at the moment, but cannot find the fix for it.

I would appreciate any suggestions. Kind regards.

GJDuck commented 11 months ago

The e9compile script does not support seperate compilation. This is because the patch binary is very low-level with no support for any kind of linking.

The "correct" way to do it is to #include everything into one big .c file, e.g. in print.c:

    #include "sub.c"
    ...