2017-02-10 141 views
0

正在使用基本的x86方法插入跳轉值5字節的函數來編寫鉤子。我的代碼很生疏,但我認爲我有邏輯。當我針對LD_PRELOAD env var運行時出現分段錯誤錯誤。基本上使用替換函數,鉤子函數,蹦牀函數來修改並返回原始地址。以下是代碼鏈接。Linux使用mprotect寫跳轉來保護內存

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'(使用帶符號的指針整數也是一個壞主意;指針根據定義是無符號的)。說:你怎麼知道你的算法有效?你檢查了機器碼嗎?調試器說什麼? – Olaf

+1

這種方法註定了設計;不僅操作系統保護已經取得了進展,編譯器也同樣如此。這個黑客你試圖解決哪個問題?你爲什麼不使用兼容的方法,並將潛在的優化留給編譯器? – Olaf

回答

1

頁面訪問標誌PROT_READ | PROT_WRITE | PROT_EXEC的結合違反w^^ X的保護,因此,可能是手頭上的第一個問題。在第一步中,首先設置PROT_READ | PROT_WRITE用於替換函數前導碼,然後將其恢復到PROT_READ | PROT_EXEC可能會解決該問題。

1

你放養你是在一個4個字節型5個字節的指令,你需要的東西是這樣的:

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