0

am writing a hook to a function using the basic x86 method of inserting a jump worth 5 bytes. My code is rusty but I think i have the logic. I get a segmentation fault error when I run against LD_PRELOAD env var. Am basically using a replacement function, hook func, trampoline function to modify and return the original address. Below is the code link.

foo.h

#ifndef foo_h__
#define foo_h__

extern void foo(const char*);

#endif  // foo_h_

foo.c

#include <stdio.h>


void foo(const char*str)
{
    puts(str);
}

main.c

#include <stdio.h>
#include "foo.h"

int main(void)
{const char*str="I am a shared lib!\n";
        int count=1;
    puts("This is a shared library test...");
    while(count!=200){
        printf("%d time!\n",count);    
    foo(str);
    count++;
}
    return 0;
}

hook.c

# include <stdio.h>
# include <unistd.h>
# define __USE_GNU
# include <dlfcn.h>
# include <stdint.h>
# include <sys/mman.h>

const char*str = "Hooked! ma fucker!\n";
struct hookdata
{
    int64_t*origFunc;
    int64_t*newFunc;
    const char*s;
    void (*foo_trampoline)(const char*str);
}*hkd;

void fooHooked(const char*str)
{
    puts(str);
    hkd->foo_trampoline(hkd->s);

}

void hook(void)
{
//Get pointers to the original and new functions and calculate the jump offset
    hkd->origFunc = dlsym(RTLD_NOW, "foo");
    hkd->newFunc = (int64_t*) &fooHooked;
    int64_t offset = hkd->newFunc - (hkd->origFunc + 5);
//Make the memory containing the original funcion writable
//Code from http://stackoverflow.com/questions/20381812/mprotect-always-returns-invalid-arguments
    size_t pageSize = sysconf(_SC_PAGESIZE);
    uintptr_t start = (uintptr_t) hkd->origFunc;
    uintptr_t end = start + 1;
    uintptr_t pageStart = start & -pageSize;
    mprotect((void *) pageStart, end - pageStart,
            PROT_READ | PROT_WRITE | PROT_EXEC);
//Insert the jump instruction at the beginning of the original function
    int32_t instruction = 0xe9 | offset << 8;
    *hkd->origFunc = instruction;
}
void foo(const char*str)
{
    if (*hkd->origFunc == 0xe9)
    {
        printf("hook detected!");
    }
    else
        hook();
}
LPs
  • 16,045
  • 8
  • 30
  • 61
  • `int64_t` is not guaranteed to hold a pointer. And the conversion of function pointers to integers is undefined behaviour as of the standard, as is arithmetics on such integer values once they are cast back to a (function) pointer. At least you should use the type dedicated to hold such a pointer (but without arithmetics), `uintptr_t` (using signed integers for pointers is also a bad idea; pointers are unsigned by definition). Said that: how do you know your arithmetics works? Did you check the machine code? What does the debugger say? – too honest for this site Feb 10 '17 at 10:16
  • 1
    This approach is doomed by design; not only OS protection has advanced, but so have compilers. Which problem do you try to solve with this hack? Why don't you use a compliant approach and leave potential optimisations to the compiler? – too honest for this site Feb 10 '17 at 10:20

2 Answers2

1

The combination of page access flags PROT_READ | PROT_WRITE | PROT_EXEC violates W^X protection, so that may be the first problem at hand. In a first step first setting PROT_READ | PROT_WRITE for replacing the function preamble and then restoring it to PROT_READ | PROT_EXEC will probably solve that problem.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
1

You stocking you're 5 bytes instruction in a 4 bytes type, you need something like this:

unsigned char instr[5];
instr[0] = 0xe9;
*(int32_t*)(&instr[1]) = offset;
memcpy(hkd->origFunc, instr, 5);
izissise
  • 898
  • 1
  • 7
  • 23