共用方式為


應用程式驗證工具 - 常見問題 (常見問題)

一般問題

以下是關於應用程式驗證器一般使用方式所收到的問題清單。

什麼是應用程式驗證器?

應用程式驗證器是運行時間驗證工具,可用來尋找Microsoft Windows 應用程式中的 Bug。 因為它是運行時間工具,因此必須練習應用程式程式碼才能進行驗證。 因此,良好的測試涵蓋範圍至關重要。

應用程式驗證工具的一般使用案例是針對感興趣的應用程式啟用它(請參閱以下關於如何執行這項操作的問題),然後執行您為應用程式撰寫的所有測試。 您將會收到調試程式中斷或驗證程式記錄專案形式中找到之任何 Bug 的通知。

如何? 卸載應用程式驗證器?

若要卸載應用程式驗證器,請按兩下 [開始],選取 [新增或移除程式],然後按兩下 [移除程式],然後按兩下 [應用程式驗證程式],然後按兩下 [移除] 來存取控制面板。

如何? 啟動應用程式驗證器?

安裝應用程式驗證器之後,您可以在程式清單中存取它,或在命令行上輸入Appverif.exe來加以啟動。 若要這樣做,請移至 [啟動] 功能表的命令提示字元或 [執行] 方塊。 輸入appverif.exe,然後按 Enter 鍵。 這會啟動應用程式驗證器。

Appverifer.exe二進位檔會安裝在系統目錄中,並用來進行工具設定。

記錄會儲存在哪裡?

記錄會儲存在 %USERPROFILE%\AppVerifierLogs 中

如果我在使用應用程式驗證器時發生問題,該怎麼辦?

請確定您執行的是最新版本。 請考慮在不同的電腦上或甚至是 Windows 版本上嘗試相同的應用程式。

應用程式驗證器是否驗證 Managed 程式代碼?

AppVerifier 關心作業系統與應用程式之間的介面。 因此,除非您的 Managed 程式代碼對與堆積、句柄、重要區段等必須執行的原生 API 執行 Interop。您的測試案例不會讓您與已驗證的介面進行任何互動。

建議您利用Managed偵錯小幫手來驗證您的Managed程式碼。 如需詳細資訊,請參閱 使用 Windows 調試程式對 Managed 程式代碼進行偵錯。

是否支援ARM64EC?

應用程式驗證器不支援ARM64EC。

調試程序問題

以下是收到有關調試程序的問題清單。

為什麼我收到錯誤,告訴我我需要調試程式?

應用程式驗證器內的基本身份驗證層要求您在調試程式下執行應用程式。 如果您在選取測試之前沒有與應用程式相關聯的調試程式,您會收到一個對話方塊,提醒您必須在調試程式下執行應用程式,才能取得記錄的資訊。

如何? 除錯程式下執行我的應用程式?

請參閱調試程式安裝和安裝主題 - 開始使用 Windows 偵錯

如何? 沒有任何其他檢測的測試堆疊擴充?

一般而言,堆疊擴充應該確實與其他驗證層隔離測試,包括堆積。 原因是:每個驗證層都會「擷取」API 或具有某些例程的導出點。

例如,對 CreateFileA 的呼叫將會是 appvocre 的呼叫!NS_SecurityChecks::CreateFileA,可能會呼叫 appvcore!NS_FillePaths::CreateFileA,可能會呼叫 kernel32!CreateFileA,可能會呼叫驗證器!AVrfpNtCreateFile,它會呼叫 ntdll!NtCreateFile。 您可以看到檢測已新增 3 個 「堆疊」函式呼叫,每個函式呼叫可能且會耗用更多堆疊。

在下列案例中,LH-verifier.dll會「擷取」每個 DllMain,而「檢測」堆積程式代碼路徑將會新增更多堆疊使用量。 由於調試程式的插入線程不會使用IMAGE_NT_HEADERS預設值,因此初始認可的堆疊將不足以完成線程的APC狀態(APC 狀態執行初始化程式代碼的線程)。

如果您想要使用 Stack-Ckecs,可能是唯一應該使用的其他驗證層,如果 FirstChanceAccessViolation。

使用 !avrf 擴充功能時,我會收到「未為此程式啟用應用程式驗證程式...」

收到的完整錯誤: Application verifier is not enabled for this process. Use appverif.exe tool to enable it.

您可能只啟用填充碼驗證層,且/或已啟用「純」模式的堆積。 這些都是一些可能的原因。

測試案例問題

以下是針對不同測試案例收到的問題清單。

如何在我的服務上啟用應用程式驗證器,但不能啟用其他人?

在 System32 目錄中製作svchost.exe複本,並呼叫複本 「Mysvchost.exe」。

使用 regedit,開啟 HKLM\System\CurrentControlSet\Services\MyService。

編輯值 「ImagePath」,其類似 「%SystemRoot%\system32\svchost.exe -k myservice」。,並將svchost.exe變更為 」Mysvchost.exe“。

將 「Mysvchost.exe」 新增至 AppVerifier 清單,並檢查所需的測試。

重新開機。

如何? 在從 WOW64 下執行的 32 位應用程式啟動的 64 位應用程式上執行應用程式驗證器?

簡單版本:在指定應用程式上啟用驗證程式設定的黃金規則,是符合工具和目標進程的位性。 也就是說:針對 32 位應用程式使用 32 位appverif.exe(兩者都在 WoW64 下執行),並使用原生 64 位原生目標的 64 位AppVerif.exe。

完整版本:應用程式驗證器設定是「核心」設定和「填充碼」設定的適當聯集。

核心設定 - 核心設定會儲存在 [圖像檔執行選項] 底下。

啟動應用程式會讀取 「調試程式」值。 因此,如果您想要讓 32 位devenv.exe啟動 64 位my.exe並在調試程式下執行,則必須使用 WoW6432Node 下的 32 位登錄機碼。 32 位進程的其他值會同時從原生 IFEO 和 WoW6432Node 這兩個位置讀取。

原因如下:在 WoW 下執行的 32 位進程是執行 Wow64 模擬迴圈的 64 位進程。 因此,每個 32 位進程都是 64 位進程,然後是 32 位進程。 64 位 IFEO 會在Wow64cpu.dll程式代碼上啟用驗證器,而 32 位 IFEO 會在 32 位程式代碼上啟用驗證器。

從用戶的觀點來看,verifier.dll會載入兩次(一次在64位世界中,一次是在32位世界中)。 由於大多數人並不關心驗證wow64cpu.dll,因此 32 位進程最可接受的行為就是只驗證 32 位部分。 這就是為什麼「永遠符合位」的黃金規則適用的原因。

如何? 偵錯在非互動式視窗站台中執行的服務

若要偵錯在非互動式視窗站台中執行的服務,請執行下列動作(只有在您使用 ntsd/windbg 時才適用):

將機碼新增至登錄的 HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image 檔案執行選項。 此金鑰的名稱應該是行程的名稱(service.exe)。

建立名為 Debugger 的REG_SZ值,並將此值設定為調試程式所在的路徑。 它必須包含完整路徑,而不只是調試程序的名稱。 此命令應該包含 –server 選項,以及調試程序應該接聽的特定埠或埠範圍。 例如 c:\debuggers\ntsd.exe –server tcp:port=5500:5600 –g –G。

使用 –remote 選項執行調試程式,以聯機到調試程序伺服器。 例如:如果您使用伺服器上的範圍,windbg.exe –remote tcp:=localhost,port=55xx,其中 'xx' 是介於 00 到 99 的一些數位。

AppVerifier 是否進行洩漏偵測? 在 Windows 7 和更新版本下,有 [洩漏] 檢查選項會在進程流失記憶體時偵測到。 在先前的操作系統下,AppVerifier 不會測試應用程式是否有洩漏偵測,而是尋找其他記憶體問題。

針對安全性考慮,建議使用哪些測試?

  • 堆積
  • 處理
  • 鎖定
  • 堆疊 (僅適用於可關閉電腦的服務和重要程式)

請記住,ObsoleteAPICalls 只會對 MSDN 中列為過時或已淘汰之 API 的每個呼叫發出警告。 如果應用程式切換至新的 API 很重要,您應該依大小寫來決定。 有些 API 很危險,有些 API 只是被具有更多選項的較新 API 取代。 如需詳細資訊,請參閱撰寫安全程序代碼的第二節<危險 API>一節。

對於需要高度可靠的應用程式,例如服務和伺服器程式,您也應該啟用 Stacks 檢查。 這會藉由停用堆疊成長來檢查堆疊認可大小是否足夠。 如果應用程式立即結束堆疊溢位,這表示應用程式必須以較大的堆疊認可大小重新編譯。 如果您是測試人員,並在使用 Stacks 檢查時遇到應用程式的問題,請提出 Bug、將錯誤指派給您的開發人員,並持續進行測試。

測試特定問題

以下是有關測試的問題清單。 按兩下問題以查看回應:

重要區段流失很重要嗎?

每當您洩漏重要區段時,就會洩漏下列內容:事件句柄、少量的核心集區和小型堆積配置。 如果進程結束時,這些會清除。

如果你的程序應該保持活很長時間,那麼這些洩漏可以咬你。 由於修正程式在 99% 的案例中非常簡單(開發人員只是忘記呼叫 RtlDeleteCriticalSection),因此您應該加以解決。

我們是否可以以程式設計方式處理堆疊溢位?

在初始線程函式中建立例外狀況處理程式不保證會攔截可能引發的潛在堆疊溢位。 這是因為分派例外狀況的程序代碼也需要一點點堆疊,才能在目前的啟用記錄上執行。 因為我們剛剛失敗堆疊延伸模組,因此很可能我們會在嘗試分派第一個堆疊時逐步執行認可堆疊的結尾,並引發第二個例外狀況。 雙重錯誤例外狀況會無條件終止進程。

LoaderLock 測試會提供呼叫 DestroyWindow 的錯誤。 為什麼無法在 DllMain 中呼叫 DestroyWindow? 您不會控制要中斷連結的線程。 如果它與建立窗口的線程不同,則您無法終結視窗。 因此,您會洩漏視窗,而下次視窗收到訊息時,就會因為 Wndproc 已卸除而當機。

您需要先終結視窗,才能取得進程中斷連結。 危險不是會卸除 user32。 危險在於您正在卸除。 因此,視窗收到的下一則訊息會當機處理,因為user32會將訊息傳遞給Wndproc,而 Wndproc 不再存在。

Microsoft Windows 作業系統具有線程親和性。 進程中斷連結不會。 載入器鎖定不是真正的大問題:問題是 Dllmain。 Process-detach 是 DLL 上次執行程式代碼的時間。 在返回之前,您必須擺脫一切。 但是,由於 Windows 具有線程親和性,因此如果您位於錯誤的線程上,就無法清除視窗。

如果有人已安裝全域勾點,載入器鎖定會進入圖片中(例如spy++ 正在執行)。 在此情況下,您會輸入潛在的死結案例。 同樣地,解決方案是先終結視窗,再取得進程中斷連結。

增加初始堆疊認可是否昂貴,以避免溢位?

當您認可堆疊時,您只會保留頁面檔案空間。 不會對效能造成影響。 實際上不會使用物理記憶體。 如果您實際接觸您認可的堆疊空間,則唯一的額外成本就會發生。 但無論如何,即使您未事先認可堆疊,也會發生這種情況。

讓我們看看讓所有服務在svchost.exe防彈中執行的成本為何。 在測試計算機上,我得到9個svchost.exe進程,總共有139個線程。 如果我們在 32K 為每個線程設定預設堆疊,我們大約需要 32K x 200 ~ 6.4 Mb 的頁面檔案空間,才能預先認可所有堆棧。

這是一個相當小的價格來支付可靠性。

保留堆疊大小呢?

有一些有趣的專案,例如 IA64/AMD64 上的例外狀況分派需要「非預期」的額外堆棧。 RPC 背景工作線程上可能會發生一些處理,其堆疊需求已超過合理的測量嘗試。

首先,您應該了解處理中所有線程集區。 具有 alertable-wait-threads 的 NT-Thread-Pool 有時很特別,因為例如,如果您使用 SQL 的資料庫元件,它會在使用者 APC 的目標線程上使用可警示的睡眠。 這可能會導致巢狀呼叫發生問題。

一旦您知道所有線程集區,請瞭解如何控制其堆疊需求。 例如,RPC 會讀取堆疊認可的登錄機碼。 WDM 幫浦線程會從映射取得該線程。 對於其他線程集區,里程可能會有所不同。

當您所有線程都清楚時,您可以採取一些動作。 只有線程來去去經常,沒有巨大的保留空間才有助於解決空間分散的問題。 如果您有控件中的穩定線程集區,則可能在減少保留空間方面也有優勢。 這確實有助於節省堆積的位址空間和用戶的位址空間。

是否有建議如何為 LINKER_STACKCOMMITSIZE=挑選正確的大小?

值應該依頁面大小來分隔(視 CPU 而定 4k/8k)。 以下是判斷您需要的大小的一些指導方針:

  1. 將具有潛在未系結深度的任何遞歸函式(或至少用戶難以理解的高深度)轉換為反覆式。

  2. 減少alloca使用量。 使用堆積或 safealloca。

  3. 執行預製,並縮減堆疊大小檢查(例如8k)。 修正標示為使用太多堆疊的函式。

  4. 將堆疊認可設定為 16k。

  5. 使用應用程式驗證器的「堆疊」檢查,在調試程式下執行一堆測試。

  6. 當你看到堆棧溢位決定最壞的罪犯,並修正他們。 (請參閱步驟 5。

  7. 當您無法再減少 8k 的堆疊使用量時。 如果您為 > 64k,發生問題,請縮減回 64k,並查看步驟 6。 否則,請移至步驟 5。

堆積測試的記憶體需求為何?

如需完整的堆積測試,您需要 256 MB 的 RAM 和至少 1GB 的頁面檔案。 針對一般堆積測試,您至少需要 128 MB 的 RAM。 沒有特定的處理器或磁碟需求。

為什麼我收到ALL_ACCESS停止?

任何使用 _ALL_ACCESS 的應用程式都會轉譯它所存取的對象,因為稽核記錄不會反映您實際使用 物件完成的工作,而只會反映您要求對物件執行的動作。

這個條件為更狡猾的攻擊創造了偽裝。 正在掃描攻擊活動的系統管理員,對於要求ALL_ACCESS密鑰 X 的人員而言,不會有任何問題,因為特定應用程式一律會執行此動作。 系統管理員會認為「人員可能只是執行 Word」。 系統管理員不能告訴駭客已經滲透到我的帳戶,現在正在探查系統,以確定我擁有什麼存取權,他可以利用他的惡意結束。 可能性有無限多種。

ALL_ACCESS的 ACL 問題在於,您必須一律授與它。 如果我們想要有一天拒絕您刪除特定密鑰的存取權,則我們無法存取。 即使您實際上並未刪除密鑰,但我們還是會中斷應用程式,因為您會要求刪除存取權。

為什麼我不會從堆積和鎖定測試取得任何記錄?

這些測試是操作系統內建的驗證層(而非套件中),並在調試程式中回報錯誤。 如果您執行已啟用這些測試且沒有損毀的應用程式,則它們不會回報任何問題。

如果您確實遇到當機,則必須在調試程式下執行,或將應用程式傳遞至開發人員,以更密切地測試。

為什麼錯誤插入無法運作?

根據客戶意見反應,AppVerifier 組建中每百萬分之一的故障插入機率已變更為 2007 年 2 月之後發行的元件。 因此,0n20000 的機率是 2%,0n500000 為 50%,依此計算。

!avrf –flt 調試程序擴充功能可用來變更調試程式中實時的機率。 不過,應該開啟進程的低資源模擬檢查,才能正常運作。

!avrf 調試程序擴充功能是隨附於調試程式套件的一部分exts.dll。 支援機率變更的 !avrf 變更位於最新的調試程式套件中。 如果您遇到錯誤插入的問題,請更新調試程式和 AppVerifier 套件。

為什麼洩漏驗證器不會報告特定資源流失?

載入 DLL 或 EXE 模組時,洩漏驗證器不會報告任何資源流失。 卸除模組時,如果模組所配置的任何資源尚未釋放,洩漏驗證程式就會發出停止。

若要檢查載入 DLL 或 EXE 所設定的資源,請使用 !avrf -leak 調試程序擴充功能。

另請參閱

應用程式驗證器 - 概觀

應用程式驗證器 - 功能

應用程式驗證器 -測試應用程式

應用程式驗證器 - 應用程式驗證器內的測試

應用程式驗證器 - 停止程式代碼和定義

應用程式驗證器 - 偵錯應用程式驗證器停止