1.下载代码
git clone https://github.com/gaffe23/linux-inject.git
cd linux-inject
make
2.开启2个终端,其中一个终端执行
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用户注入代码
3.向目标进程注入自己实现的代码
#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!”。
4.延伸问题
如果你尝试循环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);
}
它应该可以正常工作。但如果你注入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);
}