替換運行中的檔案

來源:互聯網
上載者:User

by dancefire: dancefire at 263 dot net

2004/06/17

這是今天瞎琢磨的一點收穫。

一、引入

凡事總喜歡刨根問底,一直問自己為什麼,問到實在沒什麼可問了為止,當然也有問到自己是在懶得再問了為止的時候。因為一個軟體的自動更新老出問題,有時候出現無法自動更新,分析後發現原來是在替換正在啟動並執行程式時出了問題。無知的我就開始對替換正在運行中的程式的方法進行分析。

雖大言不慚自稱深入淺出,其實只不過對一個問題想深入進去,分析到自己因技術不佳無法繼續分析的時候,淺淺的出來而已。但是仍舊希望這篇文章能夠對和我一樣思考這個問題的人有一點點協助。

言歸正傳,首先從xfocus的bgate的文章《在Win2000/XP上安靜地替換正在使用的系統檔案》中獲得啟發。

他對替換正在使用的系統檔案進行了研究,分析了微軟的一個工具zap,這個工具可以替換系統檔案。經過分析後,這個工具其實是先把正在使用的檔案移動到一個臨時目錄中去,然後再把這個檔案刪除,但是標記為下次啟動的時候刪除。此時系統檔案目錄已經騰出了空間,這樣再把新的檔案移動過來就可以了。

實現部分代碼示意如下:

    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, MOVEFILE_REPLACE_EXISTING) == 0) return FALSE;
    if(MoveFileEx(cTempFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) == 0) return FALSE;
if(MoveFileEx(szSrcFile, cTempPathName) == 0) return FALSE;

其中
winbase.h:

#define MOVEFILE_REPLACE_EXISTING   0x00000001
#define MOVEFILE_COPY_ALLOWED       0x00000002
#define MOVEFILE_DELAY_UNTIL_REBOOT 0x00000004
#define MOVEFILE_WRITE_THROUGH      0x00000008

二、MoveFileEx分析

為了瞭解MoveFileEx()到底是如何在下次重新啟動的時候進行的檔案移動操作的,我查閱了作業系統原始碼。
1、MoveFileEx()實際上是調用的MoveFileWithProgressW(),只不過NULL了兩個回調參數。
2、MoveFileWithProgressW()中針對dwFlag=MOVEFILE_DELAY_UNTIL_REBOOT的,調用了BasepMoveFileDelayed()函數
3、BasepMoveFileDelayed()是通過修改註冊表的方法,讓作業系統重新啟動時進行檔案操作的。
它修改的索引值是
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/PendingFileRenameOperations
這是一個REG_MULTI_SZ的索引值。
格式是:

szDstFile/0/0
szSrcFile/0szDstFile/0/0
szSrcFile/0!szDstFile/0/0

有些文章中所說的源檔案和目標檔案中間是換行,這並不是最合理的,雖然也可以,中間是Unicode的/0,也就是 00 00

而且需要注意的是,如果指定了MOVEFILE_REPLACE_EXISTING屬性的話,目標檔案前會加註一個歎號。

這個索引值我是在分析完原始碼後,才發現原來MSDN中已經給出這個索引值了。

後來我開啟我的這個索引值,發現裡面有一堆,還沒有來得及刪除的檔案,在等著我下一次重新啟動的時候刪除呢。

根據關於MOVEFILE_DELAY_UNTIL_REBOOT的解釋,作業系統會在系統重新啟動的時候,在Autochk檢查完成後,並且在建立任何PageFile檔案之前,立即進行指定的檔案移動。而且要確保所要操作的檔案能夠被LocalSystem或者Administrator 群組所操作。

我同時也注意到了另外一個我不熟悉的問題,就是為什麼檔案被移動了,但是應用程式還可以繼續執行,而刪除則不行。我沒有細考慮這個問題,但是我感覺一定是有什麼東西沒有變化,比如某種連結。雖然位置變了,但是連結依舊能夠跟蹤到映像的位置,所以所有指向該連結的操作都是生效的。但是刪除檔案的時候,該連結就會被刪除,從而會導致操作失敗,為了避免這種失敗,所以禁止刪除正在被佔用的檔案。

三、作業系統啟動過程中相關操作

關注了一下NT的啟動過程,想瞭解系統在啟動的時候是如何執行上面提到的移動或者刪除行為的。

在初始化核心階段,ntoskrnl.exe從NTLDR手中接管了控制權,在最後一步,Session Manager啟動了Windows XP的進階子系統以及服務,Session Manager啟動控制所有輸入、輸出裝置以及訪問顯示器螢幕的Win32子系統以及Winlogon進程,初始化核心完畢。

Session Manager實際上就是smss.exe,我們經常可以在記憶體進程中看到他的身影。反組譯碼的時候,在sub_48584D01中看到XP有考慮識別的CPU有:

0 x86
1 MIPS
2 ALPHA
3 PPC
4 IA64
5 ALPHA64
other UNKNOWN

我在smss.exe裡面找到了PendingFileRenameOperations,可見應該是此檔案負責了在引導的時候執行其中的檔案移動操作。只可惜,我沒有找到何處調用了PendingFileRenameOperations,反組譯碼功底不佳啊。

從sysinternals.com中看到一段關於Session Manager調用PendingFileRenameOperations的話

[http://www.sysinternals.com/ntw2k/info/regboot.shtml]

After you pass the point in the log where boot and system driver initialization is complete you'll begin to see records created by the smss.exe process, which is called the Session Manager. Session Manager is the first user-mode process launched during a boot. You'll see it immediately check to see if there are any rename operations it should perform before the system is up and running by looking at the value HKLM/System/CurrentControlSet/Control/Session Manager/PendingFileRenameOperations. Next you'll see it determine what DOS device mappings it should create (e.g. COM1, LPT1), what environment variables are defined, what DLL's it "knows about" (standard DLLs in the system32 directory), and which protected subsystems it should start (e.g. OS/2, POSIX).

Session Manager typically launches Chkdsk (autocheck.exe), which is specified in the Session Manager's BootExecute value along with direction to run other boot-time native applications. After Autocheck finishes Session Manager starts Winlogon and the Win32 subsystem (CSRSS.EXE). Both of these generate interleaved Registry accesses as they start up concurrently. Winlogon can be seen querying the .Default key's display settings, including colors and mouse settings under HKU/.Default/Control Panel. The .Default key's contents are user preferences that are active when no one is logged in, and Winlogon uses them for the screen on which it displays the logon dialog box.

不過這個和微軟所說的先Autochk,然後再PendingFileRenameOperations,不同。

從另一份文檔中(http://freehost02.websamba.com/brittanyfoo/BootProcess.html),提到了初始化進程問題:

Smss 的主線程進行以下的初始化步驟:

1、建立 LPC 連接埠對象( /SmApiPort )和兩個等待客戶請求的線程。客戶請求包括裝載一個新的子系統或者建立一個會話等。

2、為 MS-DOS 裝置名稱,如 COM1 和 LPT1 定義符號連結。

3、如果安裝了終端服務(Terminal Services),在對象管理器的名字空間建立 /Sessions 目錄。

4、運行 HKLM/SYSTEM/CurrentControlSet/ Control/Session Manager/BootExecute 定義的程式,典型的是運行 Autochk (Chkdsk在引導其間的版本)。

5、按照 HKLM/SYSTEM/CurrentControlSet/Control/Session Manager/PendingFileRenameOperations 的指令,進行延遲檔案改名操作。掛起檔案刪除在 PendingFileRenameOperations2 。

6、開啟已知的 DLL 。

7、建立另外的分頁檔案。

8、初始化註冊表。組態管理員重新整理註冊表, 為HKLM/SAM, HKLM/SECURITY, 和 HKLM/SOFTWARE 關鍵字裝載註冊檔案。HKLM/SYSTEM/ CurrentControlSet/Control/hivelist 在硬碟上搜尋註冊表檔案,組態管理員在 /Winnt/System32/Config 尋找。

9、建立系統內容變數。

10、裝載Win32子系統核心模式部分(Win32k.sys)。Smss 在 HKLM/SYSTEM/CurrentControlSet/Control/Session Manager 下尋找 Win32k.sys 和其它要裝載組件的路徑,確定它們的位置。Win32k.sys 中的初始化代碼使用視頻驅動程式,螢幕的解析度轉換到預設概貌檔案定義的值。因此,螢幕從引導視頻驅動程式使用的VGA模式轉到系統選擇的預設的解析度。

11、啟動子系統進程,包括 Csrss 。

12、啟動登陸進程 (Winlogon) 。

13、為調試事件資訊建立LPC口(DbgSsApiPort 和 DbgUiApiPort),並建立監聽這些口的線程。

這個算是描述最清楚的了。

四、總結

至此,對替換正在使用中的檔案有了初步的理解。

既MoveFileExW -> MoveFileWithProgressW -> BasepMoveFileDelayed -> HKLM/System/CurrentControlSet/Control/Session Manager/PendingFileRenameOperations

然後,ntldr引導,ntoskrnl.exe結果引導權,啟動smss.exe(Session Manager),在Autochk之後,檢查PendingFileRenameOperations,然後執行其中的檔案替換操作。最後smss啟動Winlogon進程,允許使用者登入。

因此此種方法可以替換幾乎所有的系統檔案,因為smss是系統的第一個UserMode的進程,此時被使用的檔案極少,不可能有人在它之前佔用檔案。

如果是替換系統檔案的話,比如smss.exe,就使用微軟的辦法,先把smss.exe移動到臨時檔案夾去,然後把新的smss.exe放到正確的目錄中。把臨時檔案家裡的smss.exe移動到NULL,並且是MOVEFILE_DELAY_UNTIL_REBOOT。這樣如果系統重新啟動的話,自然使用的是新的smss.exe,然後它再把臨時檔案夾裡的垃圾清除掉即可。其實此時不清除,等起來之後再清除也是可以的了,因為已經沒有東西在佔用那個臨時檔案夾裡的垃圾了。

如果是替換普通應用程式的話,只需要重新啟動應用程式即可,因為此時應用程式目錄裡的東西已經為新的檔案了。重新啟動只不過是為了刪除那個臨時檔案夾裡的垃圾而已。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.