介绍
Windows于Liunx
问:什么是dl_iterate_phdr?
int dl_iterate_phdr(int (*callback)(struct dl_phdr_info *info,
size_t size, void *data),
void *data);
struct dl_phdr_info {
ElfW(Addr) dlpi_addr; /* Base address of object */
const char *dlpi_name; /* (Null-terminated) name of object */
const ElfW(Phdr) *dlpi_phdr; /* Pointer to array of ELF program headers for this object */
ElfW(Half) dlpi_phnum; /* Number of items in dlpi_phdr */
/* The following fields were added in glibc 2.4, after the first
version of this structure was available. Check the size
argument passed to the dl_iterate_phdr callback to determine
whether or not each later member is available. */
unsigned long long dlpi_adds; /* Incremented when a new object may have been added */
unsigned long long dlpi_subs; /* Incremented when an object may have been removed */
size_t dlpi_tls_modid; /* If there is a PT_TLS segment, its module ID as used in TLS relocations, else zero */
void *dlpi_tls_data; /* The address of the calling thread's instance of this module's PT_TLS segment, if it has one and it has been allocated in the calling thread, otherwise a null pointer */
};
使用dl_iterate_phdr
// callback function to be called for each shared object
int callback(struct dl_phdr_info *info, size_t size, void *data) {
if (info->dlpi_name && info->dlpi_name[0]) {
printf("Shared object: %s @ %pn", info->dlpi_name, (void *)info->dlpi_addr);
}
else {
printf("Shared object: (null)n");
}
return 0;
}
int main() {
// iterate over the shared objects in the current process
dl_iterate_phdr(callback, NULL);
exit(EXIT_SUCCESS);
}
$ ./main
Shared object: (null)
Shared object: linux-vdso.so.1 @ 0x7ffe6d5cc000
Shared object: /usr/lib/libc.so.6 @ 0x7f4c3cfe8000
Shared object: /lib64/ld-linux-x86-64.so.2 @ 0x7f4c3d1f8000
解析节头来定位符号表
void locate_symtable(const char *obj_path);
// callback function to be called for each shared object
int callback(struct dl_phdr_info *info, size_t size, void *data) {
if (info->dlpi_name && info->dlpi_name[0]) {
printf("Shared object: %s @ %pn", info->dlpi_name, (void *)info->dlpi_addr);
if (strstr(info->dlpi_name, "libc.so")) {
locate_symtable(info->dlpi_name);
}
}
else {
printf("Shared object: (null)n");
}
return 0;
}
// function to locate the symbol table in the shared object
void locate_symtable(const char *obj_path) {
int fd = open(obj_path, O_RDONLY);
if (fd < 0) {
perror("open");
return;
}
// map the ELF file into memory
off_t file_size = lseek(fd, 0, SEEK_END);
void *elf_base = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (elf_base == MAP_FAILED) {
perror("mmap");
close(fd);
return;
}
// read ELF header
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)elf_base;
// read section headers
ElfW(Shdr) *shdrs = (ElfW(Shdr) *)((char *)elf_base + ehdr->e_shoff);
const char *shstrtab = (char *)elf_base + shdrs[ehdr->e_shstrndx].sh_offset;
// iterate over section headers to find the dynamic symbol table
for (int i = 0; i < ehdr->e_shnum; i++) {
if (shdrs[i].sh_type == SHT_DYNSYM) {
const char *section_name = shstrtab + shdrs[i].sh_name;
printf(" Found symbol table: %sn", section_name);
}
}
munmap(elf_base, file_size);
close(fd);
}
$ ./main Shared object: (null) Shared object: linux-vdso.so.1 @ 0x7ffe6d5cc000 Shared object: /usr/lib/libc.so.6 @ 0x7f4c3cfe8000 Found symbol table: .dynsym <--- found dynamic symbol table Shared object: /lib64/ld-linux-x86-64.so.2 @ 0x7f4c3d1f8000
解析并打印符号表中的所有符号
void locate_symtable(const char *obj_path) {
int fd = open(obj_path, O_RDONLY);
if (fd < 0) {
perror("open");
return;
}
// map the ELF file into memory
off_t file_size = lseek(fd, 0, SEEK_END);
void *elf_base = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (elf_base == MAP_FAILED) {
perror("mmap");
close(fd);
return;
}
// read ELF header
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)elf_base;
// read section headers
ElfW(Shdr) *shdrs = (ElfW(Shdr) *)((char *)elf_base + ehdr->e_shoff);
const char *shstrtab = (char *)elf_base + shdrs[ehdr->e_shstrndx].sh_offset;
// iterate over section headers to find the dynamic symbol table
for (int i = 0; i < ehdr->e_shnum; i++) {
if (shdrs[i].sh_type == SHT_DYNSYM) {
const char *section_name = shstrtab + shdrs[i].sh_name;
printf(" Found symbol table: %sn", section_name);
// read the symbol table
ElfW(Sym) *symtab = (ElfW(Sym) *)((char *)elf_base + shdrs[i].sh_offset);
const char *strtab = (const char *)elf_base + shdrs[shdrs[i].sh_link].sh_offset;
int num_symbols = shdrs[i].sh_size / shdrs[i].sh_entsize;
for (int j = 0; j < num_symbols; j++) {
printf(" Symbol: %sn", strtab + symtab[j].st_name);
}
}
}
munmap(elf_base, file_size);
close(fd);
}
./main
Shared object: (null)
Shared object: linux-vdso.so.1 @ 0x7ffe6d5cc000
Shared object: /usr/lib/libc.so.6 @ 0x7f4c3cfe8000
Found symbol table: .dynsym
Symbol:
Symbol: _dl_argv
Symbol: _dl_find_dso_for_object
Symbol: __libc_enable_secure
Symbol: _dl_deallocate_tls
Symbol: __tls_get_addr
Symbol: __libc_stack_end
Symbol: _rtld_global_ro
Symbol: _dl_signal_error
Symbol: _dl_signal_exception
Symbol: _dl_audit_symbind_alt
Symbol: __tunable_is_initialized
Symbol: _dl_rtld_di_serinfo
Symbol: _dl_allocate_tls
Symbol: __tunable_get_val
Symbol: _dl_catch_exception
Symbol: _dl_allocate_tls_init
Symbol: _rtld_global
Symbol: __nptl_change_stack_perm
Symbol: _dl_audit_preinit
Symbol: fgetc
Symbol: pthread_attr_setscope
Symbol: pthread_attr_getstacksize
Symbol: envz_strip
Symbol: pthread_attr_getstacksize
为系统函数生成哈希值
unsigned long HASH(unsigned char *str) {
unsigned long hash = 6543;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}
int main() {
unsigned char *function_name = (unsigned char *)"system";
unsigned long hash = HASH(function_name);
printf("hash of %s: %un", function_name, hash);
return 0;
}
system`这将为我们提供与之对应的字符串的哈希值:`2227611796
实现哈希函数
// djb2 hash function
uint32_t HASH(const char *str) {
uint32_t hash = 6543;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}
// function to locate the symbol table in the shared object and resolve function addresses
void locate_symtable(const char *obj_path, void *base_addr) {
int fd = open(obj_path, O_RDONLY);
if (fd < 0) {
perror("open");
return;
}
// map the ELF file into memory
off_t file_size = lseek(fd, 0, SEEK_END);
void *elf_base = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (elf_base == MAP_FAILED) {
perror("mmap");
close(fd);
return;
}
// read ELF header
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)elf_base;
// read section headers
ElfW(Shdr) *shdrs = (ElfW(Shdr) *)((char *)elf_base + ehdr->e_shoff);
const char *shstrtab = (char *)elf_base + shdrs[ehdr->e_shstrndx].sh_offset;
// system hash calculated from other snippet
uint32_t target_hash = 2227611796;
// iterate over section headers to find the dynamic symbol table
for (int i = 0; i < ehdr->e_shnum; i++) {
if (shdrs[i].sh_type == SHT_DYNSYM) {
const char *section_name = shstrtab + shdrs[i].sh_name;
printf(" Found symbol table: %sn", section_name);
// read symbol table
ElfW(Sym) *symtab = (ElfW(Sym) *)((char *)elf_base + shdrs[i].sh_offset);
const char *strtab = (const char *)elf_base + shdrs[shdrs[i].sh_link].sh_offset;
int num_symbols = shdrs[i].sh_size / shdrs[i].sh_entsize;
// iterate each symbol to check for a matching hash with system
for (int j = 0; j < num_symbols; j++) {
const char *sym_name = strtab + symtab[j].st_name;
uint32_t sym_hash = HASH(sym_name);
if (sym_hash == target_hash) {
printf(" Found target symbol: %sn", sym_name);
// calculate the functions address (need to calculate this by also adding the base addr)
void *func_addr = (void *)((char *)base_addr + symtab[j].st_value);
printf(" Address of system: %pn", func_addr);
}
}
}
}
munmap(elf_base, file_size);
close(fd);
}
// callback function to be called for each shared object
int callback(struct dl_phdr_info *info, size_t size, void *data) {
if (info->dlpi_name && info->dlpi_name[0]) {
printf("Shared object: %s @ %pn", info->dlpi_name, (void *)info->dlpi_addr);
if (strstr(info->dlpi_name, "libc.so")) {
locate_symtable(info->dlpi_name, (void *)info->dlpi_addr);
}
} else {
printf("Shared object: (null)n");
}
return 0;
}
int main() {
// iterate over the shared objects in the current process
dl_iterate_phdr(callback, NULL);
return 0;
}
执行已解析的函数
b *main+30
Breakpoint 1 at 0x15ef: file main.c, line 98.
r
Shared object: (null)
Shared object: linux-vdso.so.1 @ 0x7ffdf0fe9000
Shared object: /usr/lib/libc.so.6 @ 0x75d6d33a3000
Found symbol table: .dynsym
Found target symbol: system
Address of system: 0x75d6d33f3f10 <--- system addr
Shared object: /lib64/ld-linux-x86-64.so.2 @ 0x75d6d35b3000
Breakpoint 1, 0x00005555555555ef in main () at main.c:98
x/x 0x75d6d33f3f10
0x75d6d33f3f10: 0xfa1e0ff3
typedef int (*system_func)(const char *);
system_func _system = (system_func)func_addr;
_system("uname");
if (sym_hash == target_hash) {
printf(" Found target symbol: %sn", sym_name);
// calculate the functions address (need to calculate this by also adding the base addr)
void *func_addr = (void *)((char *)base_addr + symtab[j].st_value);
printf(" Address of system: %pn", func_addr);
// define a function pointer type for system
typedef int (*system_func)(const char *);
system_func _system = (system_func)func_addr;
// execute uname using the resolved system function
_system("uname");
}
./main
Shared object: (null)
Shared object: linux-vdso.so.1 @ 0x7ffe1f9d3000
Shared object: /usr/lib/libc.so.6 @ 0x7028ce28e000
Found symbol table: .dynsym
Found target symbol: system
Address of system: 0x7028ce2def10
Linux <--- uname executed
Shared object: /lib64/ld-linux-x86-64.so.2 @ 0x7028ce49e000
$ readelf -Ws ./main
Symbol table '.dynsym' contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dl_iterate_phdr@GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.34 (3)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND mmap@GLIBC_2.2.5 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND lseek@GLIBC_2.2.5 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND close@GLIBC_2.2.5 (2)
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND munmap@GLIBC_2.2.5 (2)
11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND open@GLIBC_2.2.5 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.2.5 (2)
13: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
14: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strstr@GLIBC_2.2.5 (2)
Symbol table '.symtab' contains 36 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c
2: 0000000000000000 0 FILE LOCAL DEFAULT ABS
3: 0000000000003de0 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
4: 00000000000020ac 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
5: 0000000000003fe8 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dl_iterate_phdr@GLIBC_2.2.5
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.34
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
9: 0000000000004050 0 NOTYPE WEAK DEFAULT 24 data_start
10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5
11: 0000000000004060 0 NOTYPE GLOBAL DEFAULT 24 _edata
12: 0000000000001608 0 FUNC GLOBAL HIDDEN 15 _fini
13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND mmap@GLIBC_2.2.5
14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5
15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND lseek@GLIBC_2.2.5
16: 0000000000000000 0 FUNC GLOBAL DEFAULT UND close@GLIBC_2.2.5
17: 0000000000004050 0 NOTYPE GLOBAL DEFAULT 24 __data_start
18: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
19: 0000000000004058 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
20: 0000000000002000 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
21: 0000000000004068 0 NOTYPE GLOBAL DEFAULT 25 _end
22: 00000000000010d0 38 FUNC GLOBAL DEFAULT 14 _start
23: 000000000000120f 793 FUNC GLOBAL DEFAULT 14 locate_symtable
24: 0000000000004060 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
25: 0000000000000000 0 FUNC GLOBAL DEFAULT UND munmap@GLIBC_2.2.5
26: 00000000000015e9 31 FUNC GLOBAL DEFAULT 14 main
27: 0000000000000000 0 FUNC GLOBAL DEFAULT UND open@GLIBC_2.2.5
28: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.2.5
29: 0000000000004060 0 OBJECT GLOBAL HIDDEN 24 __TMC_END__
30: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
31: 0000000000001528 193 FUNC GLOBAL DEFAULT 14 callback
32: 00000000000011c9 70 FUNC GLOBAL DEFAULT 14 HASH
33: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5
34: 0000000000001000 0 FUNC GLOBAL HIDDEN 12 _init
35: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strstr@GLIBC_2.2.5
$ strings ./main | grep -i sys
Address of system: %p
注意事项
结论
参考链接
https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html
https://linux.die.net/man/5/elf
https://blogs.oracle.com/solaris/post/inside-elf-symbol-tables
https://stackoverflow.com/a/15779309
打个广子
原文始发于微信公众号(影域实验室):重生之我在干免杀-逃避 Linux 恶意软件静态分析的新方法
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论