C++ 用libelf注入所需的dtu条目
我正在尝试向任意elf可执行文件中注入一个新的C++ 用libelf注入所需的dtu条目,c++,c,linux,64-bit,elf,C++,C,Linux,64 Bit,Elf,我正在尝试向任意elf可执行文件中注入一个新的DT_所需的条目 到目前为止,我只编辑了现有的DT_NEEDED条目,其中的字符串已经存在于.dynstr部分中。这是我的密码: #define _GNU_SOURCE #include <assert.h> #include <err.h> #include <fcntl.h> #include <gelf.h> #include <limits.h> #include <stdio
DT_所需的条目
到目前为止,我只编辑了现有的DT_NEEDED
条目,其中的字符串已经存在于.dynstr
部分中。这是我的密码:
#define _GNU_SOURCE
#include <assert.h>
#include <err.h>
#include <fcntl.h>
#include <gelf.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char g_target_path[] = "/tmp/new_elf";
void copy_elf(const char *arg_path) {
char source_path[PATH_MAX];
realpath(arg_path, source_path);
FILE *source, *target;
source = fopen(source_path, "rb");
assert(source != NULL);
target = fopen(g_target_path, "wb");
assert(target != NULL);
size_t n, m;
unsigned char buff[8192];
do {
n = fread(buff, 1, sizeof buff, source);
if (n != 0)
m = fwrite(buff, 1, n, target);
else
m = 0;
} while ((n > 0) && (n == m));
assert(m == 0);
assert(fclose(target) == 0);
assert(fclose(source) == 0);
}
void inject_dt_needed(const char *elf_path) {
assert(elf_version(EV_CURRENT) != EV_NONE);
int fd = open(elf_path, O_RDWR, 0);
assert(fd >= 0);
Elf *elf = elf_begin(fd, ELF_C_RDWR, NULL);
assert(elf != NULL);
assert(elf_kind(elf) == ELF_K_ELF);
elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT);
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
GElf_Shdr shdr = {0};
assert(gelf_getshdr(scn, &shdr) == &shdr);
if (shdr.sh_type == SHT_DYNAMIC) {
Elf_Data *data = NULL;
data = elf_getdata(scn, data);
assert(data != NULL);
size_t sh_entsize = gelf_fsize(elf, ELF_T_DYN, 1, EV_CURRENT);
for (size_t i = 0; i < shdr.sh_size / sh_entsize; i++) {
GElf_Dyn dyn = {0};
assert(gelf_getdyn(data, (int)i, &dyn) == &dyn);
if (dyn.d_tag == DT_NEEDED) {
printf("DT_NEEDED detected: %s string offset: %ld\n",
elf_strptr(elf, shdr.sh_link, dyn.d_un.d_val), dyn.d_un.d_val);
// Update a DT_NEEDED inplace.
dyn.d_un.d_val = 1;
assert(gelf_update_dyn(data, (int)i, &dyn) != 0);
}
}
}
}
assert(elf_update(elf, ELF_C_WRITE) >= 0);
assert(elf_end(elf) == 0);
assert(close(fd) == 0);
}
int main(int argc, char const *argv[]) {
if (argc != 2)
errx(EXIT_FAILURE, "Please give a path to an elf.");
copy_elf(argv[1]);
inject_dt_needed(g_target_path);
return 0;
}
如何添加所需的任意额外dtu
条目
我试图创建一个新的.dynamic
部分,如下所示:
void inject_dt_needed(const char *elf_path) {
assert(elf_version(EV_CURRENT) != EV_NONE);
int fd = open(elf_path, O_RDWR, 0);
assert(fd >= 0);
Elf *elf = elf_begin(fd, ELF_C_RDWR, NULL);
assert(elf != NULL);
assert(elf_kind(elf) == ELF_K_ELF);
elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT);
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
GElf_Shdr shdr = {};
assert(gelf_getshdr(scn, &shdr) == &shdr);
if (shdr.sh_type == SHT_DYNAMIC) {
Elf_Data *data = NULL;
data = elf_getdata(scn, data);
assert(data != NULL);
Elf_Scn *n_scn = elf_newscn(elf);
assert(n_scn != NULL);
Elf_Data *n_data = elf_newdata(n_scn);
assert(n_data != NULL);
*n_data = *data;
GElf_Shdr n_shdr = {};
assert(gelf_getshdr(n_scn, &n_shdr) == &n_shdr);
n_shdr = shdr;
assert(gelf_update_shdr(n_scn, &n_shdr) != 0);
shdr.sh_name = 0;
assert(gelf_update_shdr(scn, &shdr) != 0);
elf_flagscn(n_scn, ELF_C_SET, ELF_F_DIRTY);
elf_flagshdr(n_scn, ELF_C_SET, ELF_F_DIRTY);
elf_flagdata(n_data, ELF_C_SET, ELF_F_DIRTY);
assert(elf_update(elf, ELF_C_NULL) >= 0);
break;
}
}
assert(elf_update(elf, ELF_C_WRITE) >= 0);
assert(elf_end(elf) == 0);
assert(close(fd) == 0);
}
但由于某种原因,当我将原始elf与新生成的elf进行比较时,额外的部分没有标题信息,而我看到旧的。dynamic
部分已被删除:
$ diff <(readelf -a /tmp/new_elf) <(readelf -a ./elftarget)
readelf: Error: no .dynamic section in the dynamic segment
19c19
< Number of section headers: 36
---
> Number of section headers: 35
69c69
< [22] DYNAMIC 0000000000200d78 00000d78
---
> [22] .dynamic DYNAMIC 0000000000200d78 00000d78
95,96d94
< [35] NULL 0000001400000001 00000000
< 000000000160c260 0000000000000000 WSIx 2 1 544
133,134c131,132
< 03 .preinit_array .init_array .fini_array .got .data .bss
< 04
---
> 03 .preinit_array .init_array .fini_array .dynamic .got .data .bss
> 04 .dynamic
138c136
< 08 .preinit_array .init_array .fini_array .got
---
> 08 .preinit_array .init_array .fini_array .dynamic .got
$diff[22]。动态0000000000 200D78 00000d78
95,96d94
<[35]空000000 140000001 00000000
<000000000 160C260 0000000000000000 WSIx 2 1 544
133134C131132
<03.preinit_数组.init_数组.fini_数组.got.data.bss
< 04
---
>03.preinit_数组.init_数组.fini_数组.dynamic.got.data.bss
>04.动态
138c136
<08.preinit\u数组。init\u数组。fini\u数组。获取
---
>08.preinit_数组.init_数组.fini_数组.dynamic.get
关于<代码>GElf_Shdr Shdr={}代码>通过gcc
编译器运行会导致:untitled1.c:65:24:警告:ISO c禁止使用空的初始值设定项大括号[-Wpedantic]。还有很多其他的编译问题。编译时,始终启用警告,然后修复这些警告。(对于gcc
,至少使用:-Wall-Wextra-Wconversion-pedantic-std=gnu11
)注意:其他编译器使用不同的选项来产生相同的结果
$ diff <(readelf -a /tmp/new_elf) <(readelf -a ./elftarget)
readelf: Error: no .dynamic section in the dynamic segment
19c19
< Number of section headers: 36
---
> Number of section headers: 35
69c69
< [22] DYNAMIC 0000000000200d78 00000d78
---
> [22] .dynamic DYNAMIC 0000000000200d78 00000d78
95,96d94
< [35] NULL 0000001400000001 00000000
< 000000000160c260 0000000000000000 WSIx 2 1 544
133,134c131,132
< 03 .preinit_array .init_array .fini_array .got .data .bss
< 04
---
> 03 .preinit_array .init_array .fini_array .dynamic .got .data .bss
> 04 .dynamic
138c136
< 08 .preinit_array .init_array .fini_array .got
---
> 08 .preinit_array .init_array .fini_array .dynamic .got