正在使用基本的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();
}
'int64_t'不能保證容納一個指針。而且,函數指針到整數的轉換與標準一樣是未定義的行爲,一旦將這些整數值轉換回(函數)指針,就算作整數值。至少你應該使用專用的類型來保存這樣一個指針(但沒有算法),'uintptr_t'(使用帶符號的指針整數也是一個壞主意;指針根據定義是無符號的)。說:你怎麼知道你的算法有效?你檢查了機器碼嗎?調試器說什麼? – Olaf
這種方法註定了設計;不僅操作系統保護已經取得了進展,編譯器也同樣如此。這個黑客你試圖解決哪個問題?你爲什麼不使用兼容的方法,並將潛在的優化留給編譯器? – Olaf