herm1t LIVE!ng room - RTLD [entries|archive|friends|userinfo]
herm1t

[ website | twilight corner in the herm1t's cave ]
[ userinfo | ljr userinfo ]
[ archive | journal archive ]

RTLD [Nov. 13th, 2007|02:27 pm]
Previous Entry Add to Memories Tell A Friend Next Entry
[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 ковырять, а то некрасиво выглядят все эти блошиные скачки по таблицам.
LinkLeave a comment

Comments:
From:[info]russianfrost@lj
Date:November 14th, 2007 - 03:36 am
(Link)
ты аццкий кодер