0%

dlfcn

Makefileview raw
1
2
3
4
5
6
7
8
9
10
all: fake_dlfcn testlib main

fake_dlfcn:
g++ -std=c++17 -shared -fPIC fake_dlfcn.cpp -o libfake_dlfcn.so

testlib:
g++ -std=c++17 -fPIC -shared -o libtestlib.so testlib.cpp

main:
g++ -std=c++17 -o main main.cpp
fake_dlfcn.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <elf.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>

#define TAG_NAME "test2:fake_dlfcn"

#ifdef __arm__
#include <android/log.h>
#define log_info(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG_NAME, fmt, ##args)
#define log_err(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG_NAME, fmt, ##args)
#else
#define log_info(fmt, ...) std::cout << "[INFO] " << fmt << "\n", ##__VA_ARGS__
#define log_err(fmt, ...) std::cerr << "[ERROR] " << fmt << "\n", ##__VA_ARGS__
#endif

#ifdef LOG_DBG
#define log_dbg log_info
#else
#define log_dbg(...)
#endif

#ifdef __arm__
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#elif defined(__aarch64__) || defined(__x86_64__)
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#else
#error "Arch unknown, please port me"
#endif

struct Context {
void *load_addr = nullptr;
std::unique_ptr<char[]> dynstr;
std::unique_ptr<Elf_Sym[]> dynsym;
int nsyms = 0;
off_t bias = 0;

~Context() {
log_dbg("Context destroyed");
}
};

int fake_dlclose(void *handle) {
if (handle) {
delete static_cast<Context *>(handle);
}
return 0;
}

void *fake_dlopen(const char *libpath, int flags) {
std::ifstream maps("/proc/self/maps");
if (!maps.is_open()) {
log_err("Failed to open /proc/self/maps");
return nullptr;
}

std::string line;
std::string found_line;
while (std::getline(maps, line)) {
if (line.find("r-xp") != std::string::npos && line.find(libpath) != std::string::npos) {
found_line = line;
break;
}
}

if (found_line.empty()) {
log_err("%s not found in my userspace", libpath);
return nullptr;
}

off_t load_addr = 0;
std::istringstream iss(found_line);
iss >> std::hex >> load_addr;

log_info("%s loaded in Android at 0x%08lx", libpath, load_addr);

int fd = open(libpath, O_RDONLY);
if (fd < 0) {
log_err("Failed to open %s", libpath);
return nullptr;
}

off_t size = lseek(fd, 0, SEEK_END);
if (size <= 0) {
log_err("lseek() failed for %s", libpath);
close(fd);
return nullptr;
}

auto elf = static_cast<Elf_Ehdr *>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
close(fd);

if (elf == MAP_FAILED) {
log_err("mmap() failed for %s", libpath);
return nullptr;
}

auto ctx = std::make_unique<Context>();
ctx->load_addr = reinterpret_cast<void *>(load_addr);

auto shoff = reinterpret_cast<char *>(elf) + elf->e_shoff;
for (int k = 0; k < elf->e_shnum; ++k, shoff += elf->e_shentsize) {
auto sh = reinterpret_cast<Elf_Shdr *>(shoff);
log_dbg("%s: k=%d shdr=%p type=%x", __func__, k, sh, sh->sh_type);

switch (sh->sh_type) {
case SHT_DYNSYM:
if (ctx->dynsym) {
log_err("%s: duplicate DYNSYM sections", libpath);
munmap(elf, size);
return nullptr;
}
ctx->dynsym = std::make_unique<Elf_Sym[]>(sh->sh_size / sizeof(Elf_Sym));
std::memcpy(ctx->dynsym.get(), reinterpret_cast<char *>(elf) + sh->sh_offset, sh->sh_size);
ctx->nsyms = sh->sh_size / sizeof(Elf_Sym);
break;

case SHT_STRTAB:
if (ctx->dynstr) break;
ctx->dynstr = std::make_unique<char[]>(sh->sh_size);
std::memcpy(ctx->dynstr.get(), reinterpret_cast<char *>(elf) + sh->sh_offset, sh->sh_size);
break;

case SHT_PROGBITS:
if (!ctx->dynstr || !ctx->dynsym) break;
ctx->bias = static_cast<off_t>(sh->sh_addr) - static_cast<off_t>(sh->sh_offset);
k = elf->e_shnum; // exit loop
break;
}
}

munmap(elf, size);

if (!ctx->dynstr || !ctx->dynsym) {
log_err("Dynamic sections not found in %s", libpath);
return nullptr;
}

log_dbg("%s: ok, dynsym = %p, dynstr = %p", libpath, ctx->dynsym.get(), ctx->dynstr.get());
return ctx.release();
}

void *fake_dlsym(void *handle, const char *name) {
auto ctx = static_cast<Context *>(handle);
auto sym = ctx->dynsym.get();
auto strings = ctx->dynstr.get();

for (int k = 0; k < ctx->nsyms; ++k, ++sym) {
if (std::strcmp(strings + sym->st_name, name) == 0) {
void *ret = static_cast<char *>(ctx->load_addr) + sym->st_value - ctx->bias;
log_info("%s found at %p", name, ret);
return ret;
}
}
return nullptr;
}
main.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>

#include "fake_dlfcn.cpp" // 确保路径正确,或者将其改为头文件引用

// #include <dlfcn.h>
// #include <iostream>

// void preloadLibrary(const char *libraryPath) {
// void *handle = dlopen(libraryPath, RTLD_LAZY);
// if (!handle) {
// std::cerr << "Failed to preload library: " << libraryPath << std::endl;
// std::cerr << "Error: " << dlerror() << std::endl;
// return;
// }
// std::cout << "Library preloaded successfully: " << libraryPath << std::endl;

// // 注意:不要调用 dlclose(handle),否则会卸载库并从 /proc/self/maps 中移除
// }

#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#include <iostream>

void *mapLibrary(const char *libraryPath) {
int fd = open(libraryPath, O_RDONLY);
if (fd < 0) {
std::cerr << "Failed to open library: " << libraryPath << std::endl;
return nullptr;
}

off_t size = lseek(fd, 0, SEEK_END);
if (size <= 0) {
std::cerr << "Failed to get library size: " << libraryPath << std::endl;
close(fd);
return nullptr;
}

void *mapped = mmap(nullptr, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
close(fd);

if (mapped == MAP_FAILED) {
std::cerr << "Failed to map library: " << libraryPath << std::endl;
return nullptr;
}

std::cout << "Library mapped successfully: " << libraryPath << std::endl;
return mapped;
}

int main() {
const char *libraryPath = "./libtestlib.so"; // 替换为实际的共享库路径
const char *symbolName = "your_function_name"; // 替换为实际的符号名称

// 提前导入so到/proc中
void *mappedLibrary = mapLibrary(libraryPath);
if (!mappedLibrary) {
return 1; // 映射失败
}

// 加载共享库
void *handle = fake_dlopen(libraryPath, 0);
if (!handle) {
std::cerr << "Failed to load library: " << libraryPath << std::endl;
return 1;
}
std::cout << "Library loaded successfully: " << libraryPath << std::endl;

// 查找符号
void *symbol = fake_dlsym(handle, symbolName);
if (!symbol) {
std::cerr << "Failed to find symbol: " << symbolName << std::endl;
fake_dlclose(handle);
return 1;
}
std::cout << "Symbol found: " << symbolName << " at address " << symbol << std::endl;

// 调用符号(假设符号是一个函数)
using FunctionType = void (*)(); // 根据符号的实际类型修改
auto function = reinterpret_cast<FunctionType>(symbol);
function();

// 关闭共享库
if (fake_dlclose(handle) == 0) {
std::cout << "Library closed successfully." << std::endl;
} else {
std::cerr << "Failed to close library." << std::endl;
}

return 0;
}
testlib.cppview raw
1
2
3
4
5
6
7
8
9
10
#include <iostream>

extern "C" {

// 一个简单的函数,供 main.cpp 测试
void your_function_name() {
std::cout << "Hello from your_function_name in the shared library!" << std::endl;
}

}