[ | Current Mood |
| | calm | ] | Надо будет потом покопать в сторону извлечения пользы из RTLD. Полезная ведь вещь - функции можно импортировать, в нем самом дофига всяких вкусных штук - есть сисколы, указатели всякие полезные, к примеру на _dl_make_stack_executable. Очень удобно: масса полезностей, которые не являются частью зверька. Адрес можно получить из aux-вектора или взять указатель на _dl_runtime_resolve из GOT. Попробовал пока только подсунуть fixup() левые параметры, но что-то у меня не заладилось. Потом, потом, потом...
Не удержался всё-таки Ж-)))
# ./a.out
Hello, world!
# nm -gu a.out
w __gmon_start__
w _Jv_RegisterClasses
U __libc_start_main@@GLIBC_2.0
U strcmp@@GLIBC_2.0
Вот такой вот исходничек:
#include <stdio.h>
#include <elf.h>
extern _DYNAMIC;
static unsigned long elf_hash(const unsigned char *name)
...
void *lookup_x(char *name, uint32_t *hash, Elf32_Sym *sym, char *str)
...
return (void*)sym[idx].st_value;
...
int main(int argc, char **argv, char **envp)
{
int i;
uint32_t *got;
uint32_t *get_from_dyn(Elf32_Dyn *dynamic, uint32_t tag) {
Elf32_Dyn *dyn;
for (dyn = dynamic; dyn->d_tag != DT_NULL; ++dyn)
if (dyn->d_tag == tag)
return (uint32_t*)dyn->d_un.d_ptr;
return NULL;
}
uint8_t *get_base(uint8_t *addr) {
addr = (uint8_t*)((uint32_t)addr & ~4095);
while (*(uint64_t*)addr != 0x10101464c457fULL)
addr -= 4096;
return addr;
}
Elf32_Dyn *get_dyn(uint8_t *base) {
Elf32_Dyn *__DYN;
uint32_t file_base = -1;
Elf32_Phdr *phdr;
phdr = (Elf32_Phdr*)(base + ((Elf32_Ehdr*)base)->e_phoff);
for (i = 0; i < ((Elf32_Ehdr*)base)->e_phnum; i++) {
if (phdr[i].p_type == PT_LOAD && file_base == -1)
file_base = phdr[i].p_vaddr;
if (phdr[i].p_type == PT_DYNAMIC)
__DYN = (Elf32_Dyn*)(base + phdr[i].p_vaddr - file_base);
}
return __DYN;
}
got = get_from_dyn((Elf32_Dyn*)&_DYNAMIC, DT_PLTGOT);
got = get_from_dyn((Elf32_Dyn*)get_dyn(get_base((uint8_t*)got[2])), DT_PLTGOT);
Elf32_Dyn *glibc_dyn = get_dyn(get_base((uint8_t*)got[3]));
Elf32_Sym *dynsym = (Elf32_Sym*)get_from_dyn(glibc_dyn, DT_SYMTAB);
char *dynstr = (char*)get_from_dyn(glibc_dyn, DT_STRTAB);
uint32_t *hash = get_from_dyn(glibc_dyn, DT_HASH);
void (*printf_ptr)(char*,...) = lookup_x("printf", hash, dynsym, dynstr);
printf_ptr("Hello, world!\n");
}
Чё делаем?
- Получаем указатель на DYNAMIC текущего процесса
- Получаем .got.plt текущего процесса, got[2] - это резолвер
- Получаем базу интерпретатора, DYNAMIC, и опять _GOT_, но уже в интерпретаторе
- Он уже пользовался libc, и в GOT[3] есть адрес libc'шной ф-ии
- Получим базу и DYNAMIC, но теперь уже в libc
- Имея DYNAMIC libc, получим указатели на .hash, .dynsym, .dynstr
- Все. Ищем нужную функцию.
Нихера не проверяется и lookup_x не знает про prelink, так что пример будет работать только с прелинкед glibc, но это несложно исправить...
Вообщем-то примерчик довольно тупой, нужно ld-linux.so ковырять, а то некрасиво выглядят все эти блошиные скачки по таблицам.
|