linux-inject:注入代碼到運行的Linux進程中

jopen 8年前發布 | 21K 次閱讀 Linux 進程

 linux-inject:注入代碼到運行的Linux進程中

最近,我遇到了 linux-inject ,它是一個注入程序,可以注入一個.so文件到一個運行中的應用程序進程中。類似于LD_PRELOAD環境變量所實現的功能,但它可以在程序運行過程中進行動態注入,而LD_PRELOAD是定義在程序運行前優先加載的動態鏈接庫。事實上,linux-inject并不取代任何功能。換句話說,可以看成是忽略了LP_PRELOAD.

它的文檔很匱乏,理由可能是開發人員認為大多數使用這個程序的用戶不會是這個領域的新手,他們應當知道該怎么做。然而可能部分人并不是目標受眾,我當時花了很久才弄清楚需要做什么,因此我希望這篇文章能夠幫助別人。

我們首先需要克隆并且構建它:

git clone https://github.com/gaffe23/linux-inject.git
cd linux-inject
make

完成后,我們就可以開始這個例子了。打開另一個終端(這樣你有兩個可以自由使用),cd到你克隆linux-inject的目錄,然后

cd ~/workspace/linux-inject,運行./sample-target。

回到第一個終端,運行

sudo ./inject -n sample-target sample-library.so。

這些都是什么意思呢,注入sample-library.so到一個進程中,進程是通過-n name指定的sample-target。如果你需要注入到指定PID的進程,你可以使用-p PID的方式。

但這有可能無法工作,因為Linux3.4中有一個名為 Yama 的安全模塊可以禁用 ptrace-based代碼注入(或者是在代碼注入期間有其他的攔截方式)。要想讓它在這種情況下正常工作,你需要運行這些命令之一(出于安全考慮,我更喜歡第二個): 再次嘗試注入,你會在sample-target輸出的“sleeping...”中看到“I just got loaded”。

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # 允許任何進程注入代碼到相同用戶啟動的進程中,root用戶可以注入所有進程echo 2 | sudo tee /proc/sys/kernel/yama/ptrace_scope # 只允許root用戶注入代碼

如果你想注入自己寫的代碼,我必須要警告你:一些應用程序(例如VLC播放器)可能會發生段錯誤,因此你在編寫代碼的時候需要考慮到可能發生崩潰的情況。

做個簡單演示,我們可以嘗試注入這段代碼:

#include <stdio.h>__attribute__((constructor))void hello() {    puts("Hello world!");}

這段C語言代碼應該很容易理解,__attribute__((constructor))可能會使人迷惑。它的意思是說在函數庫加載之后盡快運行這個函數。換句話說,這個函數就是要注入到進程中的代碼。

編譯是很簡單的,沒有什么特別的要求:

gcc -shared -fPIC -o libhello.so hello.c

首先需要運行sample-target,然后我們嘗試注入:

sudo ./inject -n sample-target libhello.so

在長串的“sleeping...”中你應該會看到“Hello world!”。

不過還有一個問題,注入會中斷程序流程。如果你嘗試循環puts("Hello world!");,它會不斷打印"Hello world!",主程序在注入的library結束之前不會恢復運行。也就是說,你不會再看到“sleeping...”。

要解決這個問題,你可以將注入的代碼運行在單獨的線程中,例如下面這段修改的代碼:

#include <stdio.h>

include <unistd.h>

include <pthread.h>

void thread(void a) { while (1) { puts("Hello world!"); usleep(1000000); } return NULL; } attribute((constructor)) void hello() { pthread_t t; pthread_create(&t, NULL, thread, NULL); }</pre>

它應該可以正常工作。但如果你注入sample-target,因為sample-target并沒有鏈接libpthread這個庫,因此,任何使用pthread的函數都不能正常工作。當然,如果你通過添加參數-lpthread鏈接了libpthread,它會正常工作。

如果我們不想重新編譯目標程序,我們也可以使用一個linux-inject所依賴的函數:__libc_dlopen_mode()。為什么不是dlopen(),因為dlopen()需要鏈接libdl,而__libc_dlopen_mode()包含在標準C庫中(這里是glibc).

這里是代碼樣例:

#include <stdio.h>

include <unistd.h>

include <pthread.h>

include <dlfcn.h>

/ Forward declare these functions / void __libc_dlopen_mode(const char, int); void __libc_dlsym(void, const char); int __libc_dlclose(void); void thread(void a) { while (1) { puts("Hello world!"); usleep(1000000); } } attribute((constructor)) void hello() { / Note libpthread.so.0. For some reason, using the symbolic link (libpthread.so) will not work / void pthread_lib = __libc_dlopen_mode("libpthread.so.0", RTLD_LAZY); int(pthread_lib_create)(void,void,void()(void),void); pthread_t t; (void**)(&pthread_lib_create) = libc_dlsym(pthread_lib, "pthread_create"); pthread_lib_create(&t, NULL, thread, NULL); libc_dlclose(pthread_lib); }</pre>

如果你沒用過 dl函數,這段代碼看起來會非常吃力。但你可以查閱 相關文檔 ,自己去尋求解釋當然會理解的更深。 </p>

基于以上,你將可以注入自己的代碼到運行中的Linux進程中。Have fun!

本文由 360安全播報 翻譯,轉載請注明“轉自360安全播報”,并附上鏈接。

原文鏈接:

</div> </div>

來自: http://bobao.#/learning/detail/2601.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!