刪除正在使用的檔案

lin_zyang發表於2007-10-08
#include <Windows.h>
#include 
<stdio.h>
BOOL ZapDelFile(
char *szFileToDel)
{
    
char cTempFileName[0x80];
    
char cTempPathName[0x100];
    
char cFileName[0x100];

    
if(szFileToDel[1== ':'){
        sprintf(cTempPathName, 
"%c:/", szFileToDel[0]);
    }

    
else{
        GetModuleFileName(NULL, cFileName, 
0x100);
        sprintf(cTempPathName, 
"%c:/", cFileName[0]);
    }


    
if(GetTempFileName(cTempPathName, "_@"0, cTempFileName) == 0){
        
return FALSE;
    }


    
if(MoveFileEx(szFileToDel, cTempFileName, 1== 0){
        
return FALSE;
    }


    
if(MoveFileEx(cTempFileName, NULL, 4== 0){
        
return FALSE;
    }


    
return TRUE;
}


void usage(char *n) {
    printf(
"usage: %s fileNeedToDeln", n);
    exit(
0);
}


int main(int argc, char* argv[])
{

    printf(
"Zap programed by bgate. :) *nn");

    
if (argc != 2)
        usage(argv[
0]);

    
if(ZapDelFile(argv[1]) == TRUE){
        printf(
"OK");
    }

    
else{
        printf(
"error %d", GetLastError());
    }

    
return 0;
}
 

 

現在你已經可以用它去刪除正在使用的系統檔案了, 不過刪除之後會彈出讓你插入Windows CD對話方塊.
注意: 刪系統檔案前做好備份, 在重啟前恢復, 另外刪系統檔案前還需要把dllcache中相應的備份刪除. 否則系統會自動恢復.

接下來就想辦法去掉這個對話方塊, 拿出我的法寶--google. 胡亂地搜了一氣. 搜到兩條有用資訊.
1.Windows 2000下執行系統檔案保護的程式碼在sfc.dll中, Xp系統下在sfc_os.dll中.
2.登錄檔中把一個叫SfcDisable的鍵設為FFFFFF9D能在下次啟動時讓檔案保護功能失效.

下面的分析是在Win2K sp4+上進行的. 其中分析的sfc.dll版本是5.0.2195.6673

    用ida開啟sfc.dll在string中找sfcdisable, 沒找到! 讓string顯示Unicode. 這下看到了. 找到對SfcDisable引用的一個地方.程式碼如下
.text:769269F9                 call     _SfcQueryRegDwordWithAlternate@16 ; SfcQueryRegDwordWithAlternate(x,x,x,x)
.text:769269FE                 push     ebx
.text:769269FF                 push     offset ??_C@_1BG@HOGG@?$AAS?$AAf?$AAc?$AAD?; "SfcDisable"
.text:76926A04                 push     edi
.text:76926A05                 push     esi
.text:76926A06                 mov     _SFCDebug, eax
.text:76926A0B                 call     _SfcQueryRegDwordWithAlternate@16 ; SfcQueryRegDwordWithAlternate(x,x,x,x)
.text:76926A10                 push     ebx
.text:76926A11                 push     offset ??_C@_1BA@HLJH@?$AAS?$AAf?$AAc?$AAS?$AAc?$AAa?$AAn?$AA?$AA@ ; "SfcScan"
.text:76926A16                 push     edi
.text:76926A17                 push     esi
.text:76926A18                 mov     _SFCDisable, eax
.text:76926A1D                 call     _SfcQueryRegDwordWithAlternate@16 ; SfcQueryRegDwordWithAlternate(x,x,x,x)
.text:76926A22                 push     ebx
.text:76926A23                 push     offset ??_C@_1BC@KFAJ@?$AAS?$AAf?$AAc?$AAQ?$AAu?$AAo?$AAt?$AAa?$AA?$AA@ ; "SfcQuota"
.text:76926A28                 push     edi
.text:76926A29                 push     esi
.text:76926A2A                 mov     _SFCScan, eax

    其中_SfcQueryRegDwordWithAlternate@16是讀登錄檔的函式. 很明顯, 它把登錄檔中SfcDisable的值讀到了_SFCDisable中. 好, 調出softice. 在_SFCDisable上設斷點. 我們又用剛寫的zap去刪系統檔案, softice彈出來了. 斷到了下面這個地方, eip為7692A326, _SFCDisable為2.
.text:7692A319                 push     ecx
.text:7692A31A                 and     [esp+4+var_4], 0
.text:7692A31F                 cmp     _SFCDisable, 3
.text:7692A326                 push     ebx
.text:7692A327                 push     ebp
.text:7692A328                 push     esi
.text:7692A329                 push     edi
.text:7692A32A                 jnz     short loc_7692A333
.text:7692A32C                 xor     eax, eax
.text:7692A32E                 jmp     loc_7692A459
    F5退出, 一會兒對話方塊彈了出來, 就對這兒引用了一次. 很好, 看看上面這段程式碼"cmp _SFCDisable, 3". 此時_SFCDisable為2彈出了對話方塊, 那麼我就把它改為3又用zap刪系統檔案試試. 哈, 運氣很好, 這次沒出現讓插CD的對話方塊了. 也就是說只要我們把_SFCDisable改為3就能偷偷地替換系統檔案了. 不過不同版本這個地址是不一樣的, 用switch來做這個活總是不好. 得寫個有通用性的程式碼.

    開始我想它的工作原理大概是Winlogon發現了有對系統檔案進行操作. 便呼叫sfc.dll中的輸出函式進行檢查. 我們就只需得到這個輸出函式入口然後把這個函式"註釋"掉就可以了.跟著上面這段程式碼逆流而上, 找到最後由76924544輸出, 又在76924544上加個斷點, 繼續去刪檔案. softice跳出來了, 不過不在函式的入口, 反倒在剛才設定的對_SFCDisable的讀取上, 沒執行函式的入口就執行了函式體中的程式碼, 看來遇到高人了. 非得逼我出必殺技, 開啟2000原始碼 : ). 找了半天沒找到相應程式碼又只得退回來看彙編, 最後發現了這個函式NtWaitForMultipleObjects. 呵, 難怪沒中斷在函式的入口上, 原來早執行了函式的入口然後在函式體裡一直沒退出. 註釋函式的方法不行了.

    這時我想它的工作原理大概是winlogon呼叫sfc.dll中的輸出函式在系統啟動時建立了一系列事件. 既然winlogon建立了, 那麼它也應該得撤銷. 用depends開啟winlogon. 果然從sfc.dll中輸入了兩個函式. 一個是剛才分析的那個, 建立了一系列事件. 看看另一個, 輸出地址是76926869, 不出所料, 關閉了一系列事件. 現在我們只要向winlogon中注入程式碼呼叫"另一個"函式就能取消檔案保護功能了. 不過winlogon不能隨便注入程式碼. 26A雜誌第六期上有篇文章提到了注入方法:"adjust debugger access rightz to our process". 那也是一篇SFCDisable的文章, 他用的方法是在記憶體中搜尋特徵碼, 然後修改. 通用性應該沒這麼好.

    下面的注入方法是從crazylord的程式碼中拷過來的, 不過方法不是. :), 寫完後就懶得檢查了, 加之水平有限, 寫的不過優雅的地方就將就著看.

-----------------cut antisfc.c-----------

#include <stdlib.h> 
#include 
"Windows.h" 
#include 
"Tlhelp32.h" 
#pragma comment( lib, "Advapi32.lib" ) 

typedef 
void (_stdcall * CLOSEEVENTS)(void); 
typedef unsigned 
long DWORD; 
typedef DWORD ANTISFC_ACCESS; 

/* 
* ANTISFC structures 
*/
 

typedef 
struct _ANTISFC_PROCESS 
    DWORD     Pid;                 
// process pid 
    HANDLE ProcessHandle;       // process handle 
    char   ImageName[MAX_PATH]; // image name (not full path) 
}
 ANTISFC_PROCESS, *PANTISFC_PROCESS; 

__inline 
void ErrorMessageBox(char *szAdditionInfo) 

    printf(
"error on %s, error code %d. n", szAdditionInfo, GetLastError()); 
}
 

void usage(char *n) 
    printf(
"usage: %s [/d]n", n); 
    printf(
"t/d: disable sfc file protecte fuction.n"); 
    exit(
0); 
}
 

DWORD Init() 

    DWORD   Ret 
= 0
    HANDLE hToken; 
    LUID sedebugnameValue; 
    TOKEN_PRIVILEGES tkp; 

    
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
        ErrorMessageBox(
"OpenProcessToken"); 
    }
 else 

        
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) 
            ErrorMessageBox(
"LookupPrivilegeValue"); 
        }
 else 

            tkp.PrivilegeCount 
= 1
            tkp.Privileges[
0].Luid = sedebugnameValue; 
            tkp.Privileges[
0].Attributes = SE_PRIVILEGE_ENABLED; 

            
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL)) 
                ErrorMessageBox(
"AdjustTokenPrivileges"); 
            }
 else 
                Ret 
= 1
            }
 
        }
 
        CloseHandle(hToken); 
    }
 

    
return(Ret); 
}
 

DWORD GetPidEx(
char *proc_name, char *full_path) 
    DWORD             dwPid
=0
    HANDLE             hSnapshot; 
    PROCESSENTRY32     pe; 
    BOOL               Ret; 
    
  
if (isdigit(proc_name[0])) 
      dwPid 
= strtoul(proc_name, NULL, 0); 
  
else 
      dwPid 
= -1
      
    hSnapshot 
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    
if (hSnapshot == (HANDLE) -1)
        ErrorMessageBox(
"CreateToolhelp32Snapshot"); 
        
return(0); 
    }
 

    pe.dwSize 
= sizeof(PROCESSENTRY32); 
    Ret 
= Process32First(hSnapshot, &pe); 

    
while (Ret) 
          
if((strncmp(strlwr(pe.szExeFile), strlwr(proc_name), strlen(proc_name)) == 0
            
(pe.th32ProcessID 
== dwPid)) 
                dwPid 
= pe.th32ProcessID; 
                strcpy(full_path, pe.szExeFile); 
                
break
        }
 
        pe.dwSize 
= sizeof(PROCESSENTRY32); 
        Ret 
= Process32Next(hSnapshot, &pe); 
    }
 

    CloseHandle(hSnapshot); 
    
if (dwPid == -1
      dwPid 
= 0
    
return(dwPid); 
}
 

DWORD InitProcess(PANTISFC_PROCESS Process, 
char *proc_name, ANTISFC_ACCESS access) 
    DWORD Ret
=0

    Process
->Pid = GetPidEx(proc_name, Process->ImageName); 
    
if (Process->Pid != 0 && Process->ImageName[0!= 0
        Process
->ProcessHandle = OpenProcess(access, FALSE, Process->Pid); 
        
if (Process->ProcessHandle == NULL) 
            ErrorMessageBox(
"OpenProcess"); 
        
else 
            Ret 
= 1
    }
 

    
return(Ret); 
}
 

DWORD InjectThread(PANTISFC_PROCESS Process, 
                PVOID function) 

    HANDLE     hThread; 
    DWORD     dwThreadPid 
= 0, dwState; 

    hThread 
= CreateRemoteThread(Process->ProcessHandle, 
                                NULL, 
                                
0
                                (DWORD (__stdcall 
*) (void *)) function, 
                                NULL, 
                                
0
                                
&dwThreadPid); 
    
if (hThread == NULL) 
        ErrorMessageBox(
"CreateRemoteThread"); 
        
goto cleanup; 
    }
 

    dwState 
= WaitForSingleObject(hThread, 4000); // attends 4 secondes 

    
switch (dwState) 
    
case WAIT_TIMEOUT: 
    
case WAIT_FAILED: 
        ErrorMessageBox(
"WaitForSingleObject"); 
        
goto cleanup; 

    
case WAIT_OBJECT_0: 
        
break

    
default
        ErrorMessageBox(
"WaitForSingleObject"); 
        
goto cleanup; 
    }
 

    CloseHandle(hThread); 
    
return dwThreadPid; 
    
cleanup: 
    CloseHandle(hThread); 

    
return 0
}
 

int main(int argc, char* argv[]) 

    ANTISFC_PROCESS     Process; 
    HMODULE hSfc; 
    DWORD     dwThread; 
    CLOSEEVENTS pfnCloseEvents; 
    DWORD dwVersion; 

    printf(
"AntiSfc programed by bgate. :) *nn"); 

    
if (argc != 2
        usage(argv[
0]); 

    
if (strcmp(argv[1], "/d"!= 0
        usage(argv[
0]); 
    }
 

    
if (Init()) 
        printf(
"debug privilege setn"); 
    }
 else 
        printf(
"error on get debug privilegen"); 
        
return(0); 
    }
 

    
if(InitProcess(&Process, "winlogon.exe", PROCESS_ALL_ACCESS) == 0
        printf(
"error on get process info. n"); 
        
return(0); 
    }
 

    dwVersion 
= GetVersion(); 
    
if ((DWORD)(LOBYTE(LOWORD(dwVersion))) == 5){                 // Windows 2000/XP 
        if((DWORD)(HIBYTE(LOWORD(dwVersion))) == 0){             //Windows 2000 
            hSfc = LoadLibrary("sfc.dll"); 
            printf(
"Win2000n"); 
        }
 
        
else {//if((DWORD)(HIBYTE(LOWORD(dwVersion))) = 1)             //Windows XP 
            hSfc = LoadLibrary("sfc_os.dll"); 
            printf(
"Windows XPn"); 
        }
 
    }
     
    
//else if ()   //2003? 
    else 
        printf(
"unsupported versionn"); 
    }
 

    pfnCloseEvents 
= (CLOSEEVENTS)GetProcAddress(hSfc, 
                                                MAKEINTRESOURCE(
2)); 
    
if(pfnCloseEvents == NULL)
        printf(
"Load the sfc fuction failedn"); 
        FreeLibrary(hSfc); 
        
return(0); 
    }
 

    FreeLibrary(hSfc); 

    dwThread 
= InjectThread(&Process, 
                            pfnCloseEvents); 
    
    
if(dwThread == 0)
        printf(
"failedn"); 
    }
 
    
else
        printf(
"OKn"); 
    }
 

    CloseHandle(Process.ProcessHandle); 
    
return(0); 

}
 




------------------end cut---------
    在執行zap替換系統檔案前執行一下antisfc就行了, 你也可以把它們寫到一起. 理論上他能在2000, xp, 2003?的任何版本上使用. 不過我只在Win2K sp4+, WinXP sp1+上測試過.
    本文的缺點是替換的系統檔案只能在重啟後生效, 寫完了.

 

相關文章