標籤:

linux hook機制研究

linux hook機制研究

1 人贊了文章

在研究C++中協程機制時,發現有些實現通過hack掉glibc的read、write等IO操作函數,以達到遷移協程框架時,最小化代碼改動,遂小小研究一下linux下的hook機制。

引子

在linux下調用C庫中的函數,主要是調用得 libc.so.6 這個動態鏈接庫中的函數。 那麼我們有沒有辦法讓應用程序改調其它函數,而應用程序無感知,也就是hack掉應用程序中調用的某些函數。

由於是調用得動態鏈接庫中函數,我們可以通過劫持該函數的方式引入額外處理。 例如通過劫持 mallocfree 來追蹤內存使用情況等等。

實際操作

so文件

我們先創建一個 my_hook.c 文件,並編寫需要hook的函數實現。

#define _GNU_SOURCE#include <stdio.h>#include <stdint.h>#include <dlfcn.h>#define unlikely(x) __builtin_expect(!!(x), 0)#define TRY_LOAD_HOOK_FUNC(name) if (unlikely(!g_sys_##name)) {g_sys_##name = (sys_##name##_t)dlsym(RTLD_NEXT,#name);}typedef void* (*sys_malloc_t)(size_t size);static sys_malloc_t g_sys_malloc = NULL;void* malloc(size_t size){ TRY_LOAD_HOOK_FUNC(malloc); void *p = g_sys_malloc(size); printf("in malloc hook function ...
"); return p;}typedef void (*sys_free_t)(void *ptr);static sys_free_t g_sys_free = NULL;void free(void *ptr){ TRY_LOAD_HOOK_FUNC(free); g_sys_free(ptr); printf("in free hook function ...
");}

其中使用 RTLD_NEXT 來獲取系統glibc的 malloc 函數地址,由於待會使用 LD_PRELOAD 來優先載入我們創建的 so 文件,因而系統的 libc.so.6 排在第二位,也就是 next

編譯該文件生成一個 so 庫: gcc -fPIC -shared -o libmyhook.so my_hook.c -ldl

測試程序

接下來創建測試程序:

#include <stdio.h>#include <malloc.h>#include <stdlib.h>#include <string.h>int main(){ printf("enter main...
"); int *p = (int *)malloc(10); if (!p) { printf("allocation error...
"); exit(1); } printf("returning to main...
"); free(p); if (strcmp("aa", "bb") == 0) { printf("hook strcmp
"); } else { printf("not match
"); } return 0;}

hack測試

對上面的測試程序,直接編譯並運行 gcc -o main main.c ./main

結果如下:

enter main...returning to main...not match

可以清楚的看到,我們創建的 so 中函數並沒有被調用到,也就是說hack失敗

等等!目前為止我們生成的 so 文件,並沒有與測試程序產生關聯,所以 mallocfree 函數沒有被hack掉,理所應當。

那麼,如何才能讓兩者產生關聯呢?

LD_PRELOAD這個環境變數,能夠影響程序運行時候動態鏈接庫的載入,可以通過設置其來優先載入某些庫,進而覆蓋掉某些函數。

這裡只需要稍加更改運行方式LD_PRELOAD=./libmyhook.so ./main

結果如下:

enter main...in malloc hook function ...returning to main...in free hook function ...not match

大功告成,我們自定義的 mallocfree 被調用到,hack成功

問題

在嘗試對strcmp 函數進行hack時,按照如上方式並不能hack成功,通過查閱資料,原來編譯器對很多函數進行了內聯優化,並不會調用到 so 庫中的函數,因而通過優先載入自定義動態庫的方式不可行。 不過,可以在編譯測試程序時,添加 -fno-builtin-strcmp,關閉 strcmp 函數的優化 gcc -o main main.c -fno-builtin-strcmp

以相同的方式運行測試程序: LD_PRELOAD=./libmyhook.so ./main

運行結果:

enter main...in malloc hook function ...returning to main...in free hook function ...in strcmp hook function ...hook strcmp

參考資料

  • 警惕UNIX下的LD_PRELOAD環境變數
  • 如何hack strcmp

推薦閱讀:

每個 Linux 新手都應該知道的 10 個命令
給小白的Ubuntu系統不完全安裝指北
運用虛擬機搭建本地Hadoop環境
翻譯 known.met 程序
centos 7 Minimal設置網路及配置ssh

TAG:CC | Linux |