Highway to libc |
Sep. 13th, 2011|01:21 pm |
Почему эта хрень работает?
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <elf.h>
/* Type for the dtv. */
typedef union dtv
{
size_t counter;
struct
{
void *val;
bool is_static;
} pointer;
} dtv_t;
typedef struct
{
void *tcb; /* Pointer to the TCB. Not necessarily the
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
int multiple_threads;
uintptr_t sysinfo;
uintptr_t stack_guard;
uintptr_t pointer_guard;
} tcbhead_t;
int main(int argc, char **argv)
{
void *get_base(uint32_t addr) {
addr &= ~4095;
while (*(uint32_t*)addr != 0x464c457fUL)
addr -= 4096;
return (void*)addr;
}
tcbhead_t *tcb;
asm ("mov %%gs:0x0,%%eax":"=a"(tcb));
dtv_t *dtv = tcb->dtv;
if (dtv->counter > 0) {
uint32_t *tls = dtv[1].pointer.val;
Elf32_Ehdr *ehdr = get_base(tls[0]);
Elf32_Phdr *phdr = (Elf32_Phdr*)((char*)ehdr + ehdr->e_phoff);
int i;
Elf32_Dyn *dyn = NULL;
int delta;
uint32_t low;
for (i = 0; i < ehdr->e_phnum; i++)
if (phdr[i].p_type == PT_DYNAMIC)
dyn = (Elf32_Dyn*)phdr[i].p_vaddr;
else
if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == 0)
delta = phdr[i].p_vaddr;
delta = (uint32_t)ehdr - delta;
dyn = (Elf32_Dyn*)((char*)dyn + delta);
assert(dyn != NULL);
char *strtab = NULL;
int soname = 0;
while (dyn->d_tag != DT_NULL) {
if (dyn->d_tag == DT_STRTAB)
strtab = (char*)dyn->d_un.d_ptr;
else if (dyn->d_tag == DT_SONAME)
soname = dyn->d_un.d_val;
dyn++;
}
assert(strtab != NULL && soname != 0);
printf("%s\n", soname + strtab);
}
}
Собственно, хрень нужна для поиска libc из инжектированного кода (даже базовый адрес процесса не известен). Имеются и ограничения - если процесс использует треды, то индекс libc TLS в DTV поменяется. Пока не придумал, как определить наверняка. Ну, или если тредов нет вообще, то тогда сами складывайте буквы А,Ж,П,О в нужном порядке.
|
|