2017-02-10 2 views
0

5バイトのジャンプを挿入する基本的なx86メソッドを使用して関数にフックを書き込んでいます。私のコードは錆びているが、私はロジックがあると思う。私は、LD_PRELOAD env varに対して実行すると、セグメンテーションフォールトエラーが発生します。基本的には、置換機能、フック関数、トランポリン関数を使用して元のアドレスを修正して返します。以下はコードリンクです。mprotectを使用してメモリを保護するためのLinux書き込みジャンプ

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(); 
} 
+0

'int64_t'がポインタを保持することは保証されません。また、関数ポインタの整数への変換は、標準のように未定義の動作であり、一旦それらが(ファンクション)ポインタにキャストされると、そのような整数値に対する算術演算である。少なくとも、あなたはそのようなポインタを保持するために専用の型を使うべきです。(算術演算なしで) 'uintptr_t'(ポインタの符号付き整数の使用も悪い考えです;ポインタは定義によっては符号なしです)。それは言った:どのようにあなたのarithmetics作品を知っていますか?マシンコードをチェックしましたか?デバッガは何を言いますか? – Olaf

+1

この方法は設計上の問題です。 OSの保護だけでなく、コンパイラもあります。あなたはこのハックでどの問題を解決しようとしていますか?なぜコンプライアンス・アプローチを使用せず、コンパイラに潜在的な最適化を任せますか? – Olaf

答えて

1

それが手元に最初の問題がある可能性がありますので、W^Xの保護に違反するPROT_READ | PROT_WRITE | PROT_EXECページアクセスフラグの組み合わせ。最初のステップでは、ファンクションプリアンブルを置き換えてPROT_READ | PROT_EXECに復元するために最初にPROT_READ | PROT_WRITEを設定すると、おそらくその問題が解決されます。

1

あなたは4バイトのタイプで5バイトの命令だストッキング、あなたはこのようなものが必要:

unsigned char instr[5]; 
instr[0] = 0xe9; 
*(int32_t*)(&instr[1]) = offset; 
memcpy(hkd->origFunc, instr, 5); 
関連する問題