日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Linux下HOOK动态链接库中API的方法

發布時間:2023/11/27 生活经验 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下HOOK动态链接库中API的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 2012年,我寫了一篇介紹Windows系統下Ring3層API的hook方案——《一種注冊表沙箱的思路、實現——Hook Nt函數》,其在底層使用了微軟的Detours庫。5年后,我又遇到這么一個問題,但是系統變成了Linux。我最開始的想法是找一個Linux下的Detours庫,于是找到了subhook。其原理是:修改被Hook函數起始地址處的匯編代碼,讓執行流程跳到我們定義的函數中。但是在實際使用中,我發現通過該庫調用原始函數有錯誤——地址違例,導致進程崩潰,所以最終放棄了subhook的方案。(轉載請指明出于breaksoftware的csdn博客)

? ? ? ? 后來發現,Linux用戶層Hook非常簡單。我們只要定義一個和被Hook的API相同名稱、參數、返回值的函數即可。比如我們需要Hook獲取用戶UID的函數getuid(原來是在libc.so中實現的),則需要定義如下函數:

uid_t getuid(void) {return 800;
}

? ? ? ? 我們在main函數中調用之

int main() {printf("get_uid:%d\n", getuid());
}

? ? ? ? 函數返回


? ? ? ? 我使用work賬戶登錄的,其真實uid是502。而我們重寫了程序中的getuid,則返回的是我們“指定”的800。

? ? ? ? 如果我們希望在被hook中的函數中調用原始函數,怎么做呢?這兒有個比較尷尬的問題,那就是我們定義的getuid地址將對應于符號getuid,那么原始的getuid(以后稱libc中的getuid)地址將對應什么符號?我們怎么找到它?

? ? ? ? 可以想象libc中的getuid對應的符號不會因為我們的程序而被改變,那么就意味著程序運行中,將有兩個getuid。事實也的確如此。

? ? ? ? 第一個getuid就是我們重定義的hook的函數體,第二個是動態鏈接庫libc.so中的。于是我們在重定義的函數體中,使用

dlsym(RTLD_NEXT, "getuid")

? ? ? ? 就可以獲得原始的函數地址。

? ? ? ? 所以這種方案的精髓就是RTLD_NEXT參數。我們看下dlsym函數參數的說明:

? ? ? ??There are two special pseudo-handles, RTLD_DEFAULT and RTLD_NEXT. The former will find the first occurrence of the desired symbol using the default library search order. The latter will find the next occurrence of a function in the search order after the current library. This allows one to provide a wrapper around a function in another shared library.
? ? ? ? 這段文字意思是:在默認的庫查找順序下,RTLD_DEFAULT是用于查找第一個符號匹配的函數地址,RTLD_NEXT是用于查找第二個符號匹配的函數地址。這種方式就提供了一種針對動態鏈接庫中函數替換的功能。

? ? ? ? 以我們例子,RTLD_DEFAULT將找到我們自己定義的getuid,而RTLD_NEXT將找到libc.so中的。
? ? ? ? 為了方便使用這種方式,我封裝了相關調用

#ifndef HOOK_BASE
#define HOOK_BASE#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <dlfcn.h>#define HOOK_FUNC_TEMPLATE(function_name) function_name##_func_t#define HOOK_FUNC_ORI_NAME(function_name) function_name##_ori#define HOOK_FUNC_INIT(function_name) static HOOK_FUNC_TEMPLATE(function_name) HOOK_FUNC_ORI_NAME(function_name);#define HOOK_FUNC(function_name) \if (!HOOK_FUNC_ORI_NAME(function_name)) {\HOOK_FUNC_ORI_NAME(function_name) = (HOOK_FUNC_TEMPLATE(function_name)) dlsym(RTLD_NEXT, #function_name);\}\#define ORIGINAL_FUNC(function_name) ((HOOK_FUNC_TEMPLATE(function_name)) HOOK_FUNC_ORI_NAME(function_name))#endif

? ? ? ? 我們只要關注HOOK_FUNC_INIT、HOOK_FUNC和ORIGINAL_FUNC三個宏。HOOK_FUNC_INIT方法聲明了一個全局函數指針變量,其在HOOK_FUNC宏中被指定為被HOOK函數的原始地址。ORIGINAL_FUNC則是將這個指針進行類型轉換,從而方便調用。

? ? ? ? 下一步我們要定義被HOOK的函數的類型

#ifndef HOOK_DEF
#define HOOK_DEF#include "hook_base.h"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>typedef uid_t (*HOOK_FUNC_TEMPLATE(getuid))(void);
#endif

? ? ? ? 然后重定義我們要HOOK的函數

#include "hook_def.h"
#include <stdio.h>
#include <sys/types.h>HOOK_FUNC_INIT(getuid);uid_t getuid(void) {HOOK_FUNC(getuid);int uid = ORIGINAL_FUNC(getuid)();printf("getuid original:%d\n", uid);return 800;
}

? ? ? ? 這段代碼,我們先調用原始的getuid函數,并打印出它的值。最后才返回一個我們定義的值——800。

? ? ? ? 在main函數中,我們只調用getuid。并使用?gcc src/*.c -ldl -o main 編譯

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include "hook_def.h"int main() {printf("get_uid:%d\n", getuid());return 0;
}

? ? ? ? 其返回結果如下

總結

以上是生活随笔為你收集整理的Linux下HOOK动态链接库中API的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。