1. 程式人生 > >之二:Win7-x64 + VMWare (Win7-x64) + WinDbg 雙機除錯環境搭建

之二:Win7-x64 + VMWare (Win7-x64) + WinDbg 雙機除錯環境搭建

驅動開發入門 - 之二
Win7-x64 + VMWare (Win7-x64) + WinDbg
雙機除錯環境搭建

—— By EXP 2017-10-08

完整原文下載(轉載請註明出處,僅供分享學習,嚴禁用於商業用途)

1. 概述

 1.1. 前言

  為方便起見,在下文中使用【HostOS】指代【物理機/宿主機/除錯機】,用【GuestOS】指代【虛擬機器/客戶機/被除錯機】。

  WinDbg是一款雙機除錯工具,它安裝在HostOS上,HostOS與GuestOS通過串列埠相連線,使用時需要在HostOS用WinDbg除錯GuestOS上執行的核心程式。
  由於使用兩臺物理機做雙機除錯的成本較高、可操作性較低,因此本文雙機除錯的環境是基於物理機(HostOS)與VMWare虛擬機器(GuestOS)搭建的

  之所以使用虛擬機器搭建雙機除錯環境,主要出於以下幾個方面考慮:
  ① 驅動程式執行在系統核心,在調測時需要把作業系統設定到測試模式,極大降低安全性。
  ② 經驗不足的情況下編寫核心程式很容易導致系統藍屏,在HostOS除錯風險過大。
  ③ HostOS無法除錯自己。到VS2010為止的IDE均不支援驅動程式的除錯功能,只能在作業系統中載入驅動時除錯,而載入驅動程式的作業系統是無法除錯自身的(遇到INT3中斷的時候整個系統會進入假死狀態),因此需要藉助GuestOS。

 1.2. 名詞解析

名詞 英文原文 解析
HostOS Host Operating System 物理機/宿主機/除錯機
GuestOS Guest Operating System 虛擬機器/客戶機/被除錯機
COM Cluster Communication Port 序列通訊埠
KD Kernel Debug 核心除錯

 1.3 WinDbg簡介

  在安裝微軟Windows除錯工具集後,可以在安裝目錄下發現四個偵錯程式程式,分別是:cdb、ntsd、kd和WinDbg。
  其中cdb和ntsd只能除錯使用者程式,kd主要用於核心除錯(有時候也用於使用者態除錯)。這三者的一個共同特點是都只有控制檯介面,以命令列形式工作。
  而WinDbg在使用者態、核心態下都能夠發揮除錯功能,特別地,它採用了視覺化的使用者介面。所以絕大部分情況下,我們在談及Windows除錯工具時都直接指向WinDbg,而不談及其他三者。

  WinDbg支援原始碼級的除錯(類似於VC自帶的偵錯程式),而且在使用者態和核心態下,都支援兩種除錯模式,即“實時除錯模式(Living)”和“事後除錯模式(Postmortem)”。
  實時除錯模式(Living):是被除錯的目標物件(Target)當前正在運行當中,偵錯程式可以實時分析、修改被除錯目標的狀態,如暫存器、記憶體、變數,除錯exe可執行程式或雙機實時除錯都屬於這種模式。
  事後除錯模式(Postmortem):是被除錯的目標物件(Target)已經結束了,現在只是事後對它保留的快照進行分析,這個快照稱為轉儲檔案(Dump檔案)。

2. 作業系統與預裝元件

  ① HostOS系統版本: Win7 SP1 x64 (必須升級到SP1版本)
  ② GuestOS系統版本: Win7 SP1 x64 (必須升級到SP1版本)
  ③ 在HostOS安裝VS2010驅動開發環境的相關元件(詳見《驅動開發入門 - 之一》,此處不再複述),之所以選擇VS2010環境,是因為VS2008在x64環境下的混合彙編能力較弱,不便於後續的開發除錯工作

3. 相關工具安裝

表 1 工具清單
目標機器 工具 版本 用途 備註 下載
HostOS VS2010驅動開發
環境的相關元件
HostOS VMWare 11.1.2 安裝GuestOS
的虛擬機器
用於搭建隔離環境
除錯驅動程式
HostOS WinDbg 6.11 Windows平臺下的
驅動程式除錯工具
用於配合GuestOS
雙機除錯驅動程式
官方地址
CSDN
HostOS windbg-雙機除錯.bat 6.11 使得windbg連線到GuestOS的啟動指令碼 配合WinDbg使用,
已固化啟動引數
CSDN
HostOS Win7符號檔案 Win7 SP1 x64 WinDbg除錯程式碼用 相當於Win系統核心程式的原始碼檔案 官方地址
GuestOS 開啟Windows測試環境.bat
關閉Windows測試環境.bat
調測環境變更指令碼 把作業系統永久切換到測試模式並關閉驅動簽名校驗 CSDN
GuestOS DriverMonitor 3.2.0 驅動程式裝載器 XP x86用於安裝、啟動核心程式的除錯工具,Win7 x64可能不相容 CSDN
GuestOS InstDrv 1.3.0 驅動程式裝載器 Win7用於安裝、啟動核心程式的除錯工具 CSDN
GuestOS DebugView 4.81 核心驅動訊息捕獲器 配合DriverMonitor或InstDrv使用,用於捕獲核心程式的DbgPrint / KdPrint語句所列印訊息 CSDN
HostOS
GuestOS
VirtualKD 3.0 核心除錯加速器 配合WinDbg使用,提高HostOS與GuestOS傳輸速率 官方地址

3. 安裝VMware虛擬機器及GuestOS

  由於VMWare11之後的虛擬機器和系統安裝都比較簡單,此處就不詳述了,僅說明一下步驟:
  ① 在HostOS安裝VMWare虛擬機器
  ② 在虛擬機器安裝Win7 x64 SP1作業系統(GuestOS)
  ③ 為了便於HostOS與GuestOS的檔案互動,安裝VMWare Tools(VMWare 已自帶:【選單】 –> 【虛擬機器】 –> 【安裝VMWare Tools】)
  ④ 在GuestOS中執行【開啟Windows測試環境.bat】指令碼使GuestOS關閉驅動簽名校驗,並進入測試模式
  ⑤ 在GuestOS中安裝 DriverMonitor / InstDrv 和 DebugView

注:
 若第 ④ 步的指令碼下載地址已失效,可手動在GuestOS的DOS控制檯輸入以下命令:

 【開啟Windows測試環境.bat】指令碼主要是兩個指令:
 bcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS // 關閉驅動數字簽名校驗
 bcdedit /set testsigning on // 開啟系統測試模式

 【關閉Windows測試環境.bat】指令碼是配套的兩個還原指令:
 bcdedit -set loadoptions DENABLE_INTEGRITY_CHECKS // 啟動驅動數字簽名校驗
 bcdedit /set testsigning off // 關閉系統測試模式

5. 配置VMWare的虛擬管道串列埠

  當雙機都是物理機時,HostOS與GuestOS是用物理串列埠連線的。
  但是在GuestOS是虛擬機器的情況下,就不可能使用物理串列埠了,此時需要在GuestOS上設定一個用虛擬的管道串列埠,步驟如下:

  ① 在虛擬機器關機狀態下,選擇【編輯虛擬機器設定】,如圖 1。

這裡寫圖片描述

圖 1 編輯虛擬機器設定

  ② 在【硬體】選項卡【移除印表機】,如圖 2。
  這是因為印表機預設佔用了串列埠COM_1,為了使得下文的配置無需修改,這裡建議刪除印表機(不刪除印表機也可以,但後面的配置請自行修改為COM_2作為管道串列埠命名)

這裡寫圖片描述

圖 2 移除印表機

  ③ 新增一個串列埠:【新增】 –> 【串列埠】 –> 【下一步】 –> 【輸出到命名管道】 –> 【下一步】,如圖 3和圖 4。

這裡寫圖片描述

圖 3 新增串列埠
這裡寫圖片描述

圖 4 設定為管道串列埠

  ④ 如圖 5設定如下值,點選【完成】按鈕。
   命名管道:\.\pipe\com_1 (會自動填上編號最小的可用串列埠)
   【該端是伺服器。】
   【另一端是應用程式。】
   【勾上】啟動時連線。

這裡寫圖片描述

圖 5 設定虛擬管道串列埠引數

  ⑤ 最後回到如圖 6所示的介面,選中剛才新建的【串列埠】,在I/O模式【勾選】輪詢時主動放棄 CPU(Y),點選【確定】即可。

這裡寫圖片描述

圖 6 設定串列埠IO模式

6. 在GuestOS增設除錯模式的作業系統

  首先區分GuestOS中作業系統的幾種模式:
  >> 正常模式:初裝作業系統時的預設狀態
  >> 測試模式:利用bcdedit命令開啟系統的TestSigning開關,使系統處於可以裝載未認證驅動程式的狀態(若已按上文所述操作,當前的GuestOS已處於此狀態)
  >> 除錯模式:利用bcdedit命令開啟系統的debug和bootdebug 開關,使系統上執行的程式處於可以被另一個系統除錯的狀態

  本節的最終目標就是在 [測試模式] 的基礎上再增加 [除錯模式],更具體地描述,就是在開機的作業系統列表中新增一個被標識為【啟用除錯程式】的作業系統,如圖 7所示(其中“Win-7雙擊除錯模式”是自定義的系統名稱,“啟用除錯程式”表示該系統處於除錯模式
  在XP時代,通過修改C:\boot.ini配置檔案可以實現此目的。但Win7系統已經沒有這個檔案了,需要通過bcdedit命令進行配置。

這裡寫圖片描述

圖 7 系統列表

  詳細的配置方式如下:
  ① 虛擬機器開機後,正常登陸到Win7系統桌面(若已按照上文配置,當前所登陸到的Win7系統正處於【測試模式】,可以通過桌面右下角的水印驗證,如圖 8所示。某些系統會遮蔽這個水印,此時可以通過命令【bcdedit /enum】確認testsigning的值是否為Yes以判斷系統當前是否處於測試模式)。

這裡寫圖片描述

圖 8 測試模式水印

  ② 如圖 9和圖 10所示,以管理員身份執行DOS控制檯在控制檯中依次輸入以下命令:

bcdedit /copy {current} /d “Win7-雙機除錯模式” // 這是系統副本的名字,任意即可
bcdedit /timeout 10

  這兩條命令的作用是把當前所登陸的作業系統,複製一份副本,命名為【Win7-雙機除錯模式】。新的系統會出現在開機時的作業系統列表中,該列表的呈現時間為10秒。

這裡寫圖片描述

圖 9 使用管理員執行DOS
這裡寫圖片描述

圖 10 複製當前作業系統

  ③ 重啟GuestOS,此時可以看到在作業系統列表中多出第一項【Win7-雙機除錯模式】,這就是剛才複製的系統副本。選擇這個系統登陸到桌面。

這裡寫圖片描述

圖 11 作業系統列表

  ④ 以管理員身份執行DOS控制檯,在控制檯中依次輸入以下命令使得系統進入除錯模式:

bcdedit /debug ON
bcdedit /bootdebug ON

  再輸入以下命令可檢視作業系統在除錯模式下使用的串列埠配置:

bcdedit /dbgsettings

  如圖 12所示為除錯模式的配置引數,其中【debugtype=Serial】表示使用串列埠做除錯,【debugport=1】表示串列埠埠為COM_1,【baudrate=115200】為波特率,表示HostOS與GuestOS通過此虛擬串列埠交換資料的傳輸速率(約等效於10KB/s,暫時保持預設值即可)。

這裡寫圖片描述

圖 12 設定當前系統為除錯模式

  這裡需要注意的是,若上文小節【5 配置VMWare的虛擬的管道串列埠】中所配置的串列埠不是COM_1,這裡可以使用以下命令 修改串列埠號等 除錯模式的引數:

bcdedit /dbgsettings serial debugport:1 baudrate:115200

  ⑤ 到此就已經成功添加了一個除錯模式的作業系統了,重啟後可在系列列表中看見【Win-7雙擊除錯模式 [啟用除錯程式]】(如圖 13),這個就是之後要用來除錯驅動用的系統。

這裡寫圖片描述

圖 13 作業系統列表

  ⑥ 為了便於之後開機後都處於除錯模式,可以通過右鍵【計算機】 –> 【屬性】 –> 【高階系統設定】 –> 【高階】 –> 【啟動和故障恢復】 –> 【設定】 修改預設的作業系統、以及作業系統列表的顯示時間,如圖 14所示:

這裡寫圖片描述

圖 14 修改預設的作業系統

7. WinDbg的安裝與配置

  只有HostOS需要安裝WinDbg,步驟如下:
  ① 安裝dbg_x86_6.11.1.404.msi到HostOS任意位置
  ② 複製windbg_cn.exe到安裝目錄(此為漢化介面入口)
  ③ 複製 [windbg_cn-雙機除錯.bat] 和 [windbg-雙機除錯.bat] 指令碼到安裝目錄(這兩個指令碼功能相同,區別只是一個漢化版、一個英文版)
  ④ 根據上文設定的虛擬管道串列埠,右鍵編輯bat指令碼的啟動引數(若使用COM_1串列埠則無需修改):

 start “” windbg_cn.exe -b -k com:pipe,port=\.\pipe\com_1,baud=115200,reconnect -y   // 中文指令碼
 start “” windbg.exe -b -k com:pipe,port=\.\pipe\com_1,baud=115200,reconnect -y   // 英文指令碼

8. 驗證WinDbg配置(連線GuestOS)

  ① 啟動虛擬機器,進入【win7-雙機除錯模式 [啟動除錯程式]】系統(注:除錯模式的系統在啟動過程有兩個系統斷點,若不通過WinDbg跳過斷點,系統會陷入中斷狀態無法進入桌面)。
  ② 執行 [windbg_cn-雙機除錯.bat] 指令碼,若指令碼配置的啟動引數與GuestOS設定的虛擬管道串列埠引數一致,則可以明顯看到宿主系統和虛擬系統連線成功的提示,如圖 15。
  ③ 在系統啟動過程中,會出現多次【int 3】系統中斷,需要在WinDbg的【kd>】中輸入命令【g】以跳過中斷,直到登陸到桌面。
  ④ 成功進入桌面後,就可以開始使用WinDbg做雙機除錯。

這裡寫圖片描述

圖 15 WinDbg連線GuestOS

9. 雙機除錯

 9.1. 什麼是符號檔案

  類似於在C/Java的IDE中除錯原始碼,WinDbg在除錯驅動程式時也需要用到原始碼,在Windows中把這種原始碼稱之為符號檔案(Symbol Files)
  符號檔案是一個數據信息檔案,以*.pdb副檔名標識。它包含了應用程式二進位制檔案(如*.sys、*.dll、*.exe)的除錯資訊(如程式中所有變數資訊),專用於除錯。符號檔案與二進位制檔案的編譯版本密切,當二進位制檔案被重新編譯時,上次編譯所產生的pdb檔案就過時了,不能再用於除錯工作。
  用 Visual C++ 和 WinDbg 除錯程式時都要用到符號檔案,但最終生成的可執行檔案在執行時並不需要符號檔案。
  例如每個 Windows 作業系統下有一個 GDI32.dll 檔案,編譯器在編譯該 DLL 的時候會產生一個 GDI32.pdb 檔案。一旦我們擁有了這個GDI32.pdb檔案,那麼便可以用它來除錯並跟蹤到 GDI32.dll 內部。

 9.2. 符號檔案路徑設定

  WinDbg是支援在除錯時自動線上下載對應符號檔案的。但是符號檔案內容也不少(某些符號檔案線上下載需要幾分鐘,不便於除錯),建議把離線安裝包下載到本地先預安裝。

  這個是微軟提供的各個Windows版本的符號路徑下載的站點:

  以本文所採用的作業系統版本為例,選擇【Windows 7 Service Pack 1 x64 retail symbols, all languages】下載,如圖 16:

這裡寫圖片描述

圖 16 選擇合適的符號檔案版本

  下載成功後,將其安裝到HostOS的任意位置即可。
  本文所選擇的符號檔案安裝目錄為:E:\04_work\re\Symbol
  安裝成功後,配置環境變數:
   ① 右擊【計算機】–>【屬性】–>【高階系統設定】–>【高階選項卡】–>【環境變數】
   ② 在【系統變數】中新建四個變數:

變數名 變數值 備註
_NT_SYMBOL_DIR E:\04_work\re\Symbol 符號檔案安裝目錄
_NT_SYMBOL_PATH %_NT_SYMBOL_DIR%;symsrv*symsrv.dll*%_NT_SYMBOL_DIR%
*http://msdl.microsoft.com/download/symbols
符號檔案檢索位置
_NT_SOURCE_PATH 根據實際情況按需配置(可不配) 編譯驅動生成的符號檔案目錄
_NT_ALT_SYMBOL_PATH 根據實際情況按需配置(可不配) 其他符號檔案目錄

注:在環境變數 _NT_SYMBOL_PATH 指定了兩個路徑:第一個是本地符號檔案安裝目錄,第二個是線上符號檔案站點。 它表示如果在本地安裝目錄%_NT_SYMBOL_DIR%下找不到所需的Symbol File,就從微軟的Symbol Server上下載並儲存到%_NT_SYMBOL_DIR%目錄。

  重新執行WinDbg連線到GuestOS,從控制檯的連線資訊可以看到WinDbg已成功找到符號檔案路徑位置。點選【檔案】 –> 【符號檔案路徑】 可以發現系統變數 _NT_SYMBOL_PATH 所指定的符號檔案路徑已被載入到WinDbg,如圖 17所示:

這裡寫圖片描述

圖 17 符號檔案路徑設定

 9.3. 除錯一個驅動程式

  以之前的VS2010_WDK_Demo驅動專案為例(該專案通過EasySYSchs生成,已生成模板程式碼,編譯後可直接被系統載入執行,詳見《驅動開發入門 - 之一》,此處不再複述)。
  在VS2010_WDK_Demo.cpp中找到入口函式DriverEntry,使用DbgPrint函式列印一句核心除錯訊息,如圖 18:

這裡寫圖片描述

圖 18 新增核心除錯訊息語句

  重新編譯並簽名VS2010_WDK_Demo驅動專案,拷貝VS2010_WDK_Demo.sys到GuestOS中,並使用DriverMonitor / InstDrv裝載並啟動該驅動,則可以在WinDbg中捕獲到剛才新增的核心訊息“Hello, Driver By VS2010”,如圖 19所示。

這裡寫圖片描述

圖 19 除錯一個簡單的驅動程式

 9.4. 加入斷點除錯

  由於驅動程式中沒有斷點,驅動程式被裝載後轉瞬就執行完了。
  為了便於除錯,這次在驅動程式的入口函式DriverEntry中加入INT 3系統中斷的彙編程式碼,如圖 20所示(此處只演示效果,暫不說明如何在x64系統中嵌入彙編程式碼,若有需要了解可見附錄)

這裡寫圖片描述

圖 20 新增系統中斷

  重新編譯並簽名VS2010_WDK_Demo驅動專案。
  把HostOS編譯目錄中生成的符號檔案VS2010_WDK_Demo.pdb設定到WinDbg中(【檔案】 –> 【原始檔路徑】),使得WinDbg可以在除錯過程中檢視驅動程式的原始碼,如圖 21所示。
  然後拷貝驅動程式VS2010_WDK_Demo.sys到GuestOS中,簽名後使用DriverMonitor / InstDrv裝載並啟動該驅動,此時GuestOS因為系統中斷會陷入假死狀態,按【Ctrl+Alt】釋放滑鼠到HostOS,發現WinDbg已執行到斷點位置並暫停,如圖 22所示。
  在WinDbg上方的工具欄提供了對驅動程式做除錯的按鈕,左側為原始碼區,右側則是控制檯,如圖 23所示為單步除錯的過程。
  熟悉WinDbg的使用後,其他驅動程式的除錯方式也是大同小異,此處就不再一一敘述了。

這裡寫圖片描述

圖 21 設定原始檔路徑
這裡寫圖片描述

圖 22 驅動程式陷入中斷
這裡寫圖片描述

圖 23 驅動程式除錯

10. 附錄1:利用VirtualKD提高除錯的傳輸速率

  在除錯的過程中可能會發現WinDbg經常會不斷列印一堆意義不明XML stream訊息刷屏(如圖 24),在列印期間WinDbg與GuestOS均處於無法操作的假死狀態

SXS.DLL: Read 0 bytes from XML stream; HRESULT returned = 0x00000001
SXS.DLL: Creating 8828 byte file mapping
C:\Users\Administrator\Desktop\DriverGenius\security\kxescan\kfc_dps.datSXS.DLL: Read 756 bytes from XML stream; HRESULT returned = 0x00000000
   00000000: 3c-3f-78-6d-6c-20-76-65-72-73-69-6f-6e-3d-22-31 (<?xml version="1)
   00000010: 2e-30-22-20-65-6e-63-6f-64-69-6e-67-3d-22-55-54 (.0" encoding="UT)
   00000020: 46-2d-38-22-20-73-74-61-6e-64-61-6c-6f-6e-65-3d (F-8" standalone=)
   00000030: 22-79-65-73-22-3f-3e-0d-0a-3c-21-2d-2d-20-43-6f ("yes"?>..<!-- Co)
   00000040: 70-79-72-69-67-68-74-20-28-63-29-20-4d-69-63-72 (pyright (c) Micr)
   00000050: 6f-73-6f-66-74-20-43-6f-72-70-6f-72-61-74-69-6f (osoft Corporatio)
   00000060: 6e-20-2d-2d-3e-0d-0a-3c-61-73-73-65-6d-62-6c-79 (n -->..<assembly)
這裡寫圖片描述

圖 24 HostOS與GuestOS互動資料刷屏

  這種訊息實際上是HostOS與GuestOS在互動資料,當在GuestOS開啟某些程序時就可能會觸發。當需要互動的資料量很大的時候,就會造成WinDbg與GuestOS雙雙陷入假死狀態,直到資料互動完成。那麼要解決假死狀態的方法自然就是想辦法使得HostOS與GuestOS儘快完成資料互動。
  在前面配置虛擬管道串列埠的時候,有一個波特率引數,預設值就是【baudrate=115200】,該值直接制約了HostOS與GuestOS互動資料的傳輸速率(115200 baudrate等效於115200 bit per secon,約為10KB/s)。但是串列埠波特率的取值範圍為300、600、1200、2400、4800、9600、19200、38400、43000、56000、57600、115200,可以發現預設值已經是最大值了,無法再上調波特率。

  為此需要藉助MS提供的另一個工具VirtualKD:其原理是先在HostOS與GuestOS預裝後門程序,然後利用KD的擴充套件DLL功能向GuestOS附加到這個程序產生一條虛擬管道,WinDbg可以藉助該管道在HostOS與GuestOS之間進行除錯。相比於使用串列埠,VirtualKD的資料互動速率有極大的提升(微軟官方測試速率最高為6MB/S,即使在VMWare平臺也可達到150KB/s)。

  VirtualKD的安裝和使用都比較簡單,具體步驟如下:
  ① 把從官方下載的VirtualKD.exe在HostOS與GuestOS中分別拷貝一份。
  ② 分別在HostOS與GuestOS中執行VirtualKD.exe解壓
  ③ 在GuestOS中執行解壓目錄中的 \target\vminstall.exe,由於是非Win10系統,必須取消勾選【Replace kdcom.dll】,其他引數可以不修改,點選【install】按鈕安裝(如圖 25),安裝成功後會提示重啟
  ④ 重啟後在作業系統列表會新增一個系統副本,副本名稱就是剛才定義的名稱,使用它進入系統(如圖 26)
  ⑤ 在HostOS中執行解壓目錄中的vmmon64.exe,點選【Debugger path…】按鈕選擇WinDbg安裝目錄下的【windbg.exe】(此方式不支援選擇漢化版的入口),最後點選【Run debugger】,VirtualKD會自動啟動WinDbg並連線到GuestOS(如圖 27)。
  ⑥ 在WinDbg除錯期間不能關閉VirtualKD程序

這裡寫圖片描述

圖 25 在GuestOS安裝VirtualKD
這裡寫圖片描述

圖 26 作業系統列表新增VirtualKD除錯系統
這裡寫圖片描述

圖 27 在HostOS配置VirtualKD執行WinDbg

11. 附錄2: WinDbg常用命令/操作

  可跳轉到此頁面查詢:

12. 附錄3:WDK(x64)+彙編的混合編譯

  使用WinDbg除錯驅動程式的時候,已經涉及程式碼編寫了。而其中一個泛用的特例就是在C/C++程式碼中嵌套匯編的INT3系統中斷指令。
  因此此節詳細說明一下如何在x64的C/C++驅動程式中嵌入彙編程式碼,並將其編譯到一起。

  在x86的編譯平臺中是支援使用__asm{ … }語法進行內聯彙編的,亦即可以直接把彙編程式碼直接寫到C/C++程式碼之中,例如:

NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING reg_path) 
{ 
    DbgPrint("This is x86 C/C++"); 

    __asm {
        int 3       ; 系統中斷
    }

    DbgPrint("This is x86 C/C++"); 
    return STATUS_SUCCESS; 
}

  但是在x64編譯平臺是不支援內聯彙編的
  x64平臺要求把彙編程式碼統一寫到 *.asm 檔案中,通過彙編編譯器(VS預設為ml64.exe)編譯成 *.obj 目標檔案,最後與 C/C++ 程式碼的目標檔案link到一起生成*.exe可執行檔案(或*.sys驅動檔案)。

  在WDK驅動專案中,詳細的操作方式如下(這裡還是以在之前的VS2010_WDK_Demo驅動專案中新增INT3系統中斷為例)
  ① 在WDK專案中新建資料夾asm,再新建檔案fun.asm(檔名任意,字尾必須為*.asm
  ② 在fun.asm中編寫INT3系統中斷彙編程式碼:

.CODE           ; 宣告為程式碼段,類似的還有.DATA資料段

int_3 PROC      ; 函式/過程,紅色部分是其名稱,可被C/C++聲明後直接呼叫
    int 3
    ret
int_3 ENDP

END

  ③ 如圖 28,在VS2010_WDK_Demo.h 標頭檔案的 extern “C” { … } 程式碼塊中新增彙編函式的外部宣告,使其可以被呼叫C/C++程式碼(至於為什麼要在extern “C”修飾符內做函式宣告,可見附錄4的【13.1 [error LNK 2019] 】

extern "C" { 
    ......
    void int_3(void);
    ......
} 
這裡寫圖片描述

圖 28 在*.h標頭檔案宣告*.asm的外部函式

  ④ 之後就可以在VS2010_WDK_Demo.cpp 原始檔中直接呼叫 int_3() 函數了,如圖 29:

這裡寫圖片描述

圖 29 在*.cpp原始檔呼叫*.asm的外部函式

  ⑤ 但是現在WDK工程還不能編譯成功,原因是WDK不知道如何編譯fun.asm檔案。為此需要再為*.asm檔案指定一套編譯規則,方法如下:
  右鍵【專案】 –> 【生成自定義】 –> 勾選【masm】,這組操作意為為WDK專案增加彙編檔案的編譯規則MASM(如圖 30)。

這裡寫圖片描述

圖 30 為WDK工程新增新的編譯規則(MASM)

  ⑥ 右鍵【fun.asm】 –> 【屬性】 –> 【配置屬性】 –> 【常規】 –> 【項型別】 –> 【 Microsoft Macro Assembler】(此選項只有在執行第⑤步後才會出現) –> 【應用】,這組操作意為使用預設的MASM編譯器編譯*.asm檔案(如圖 31)。

這裡寫圖片描述

圖 31 為*.asm彙編檔案指定MASM編譯器

  ⑦ 之後左側會增加一項【Microsoft Macro Assembler】,這就是MASM編譯器的配置項。
  點選【Command Line】檢視編譯指令碼: x64平臺的編譯指令碼為ml64.exe, Win32平臺的編譯指令碼為ml.exe(如圖 32)。
  由於當前工程是64位WDK專案,因此若編譯指令碼不是ml64.exe,需要在配置管理器新增x64平臺。

這裡寫圖片描述

圖 32 確認MASM編譯器的彙編編譯指令碼是否正確

  ⑧ (重要)點選【Object File】檢視*.asm檔案編譯所生成的目標檔案*.obj的輸出位置。由於配置值使用了巨集變數,可【點選配置值】 –> 【下拉】 –> 【編輯】 –> 【巨集】,找到對應的變數檢視其真實值。
  如圖 33所示,配置值為【$(IntDir)%(FileName).obj】。
  其中$(IntDir)為巨集變數,查得其值為x64\amd64\
  %(FileName)泛指所編譯的*.asm檔名稱(不含字尾),如當前所編譯的fun.asm檔案,%(FileName)的值則為fun
  因此對於fun.asm彙編檔案而言,$(IntDir)%(FileName).obj的真實值為x64\amd64\fun.obj,記下這個值。

這裡寫圖片描述

圖 33 確認*.asm彙編檔案編譯所生成的目標檔案位置

  ⑨ 驅動工程是通過WDK的build命令進行編譯的(在VS2010中是驅動工程目錄下的BuildDrv.bat指令碼),但是build命令不會自動LINK到*.asm彙編檔案的目標檔案,直接影響就是在編譯*.cpp原始檔時,找不到*.asm彙編檔案所宣告的函式。
  為此需要告訴build指令碼,在編譯*.cpp的時候要和哪些*.asm的目標檔案進行LINK。
  事實上,*.asm是先於*.cpp被編譯成目標檔案的,亦即在編譯*.cpp的時候,可以把*.asm的目標檔案作為*.cpp的庫檔案,而*.asm的目標檔案位置,在第⑧步的時候已經查到了。
  爾後只需要修改WDK的sources檔案,新增屬性項【TARGETLIBS】,指定值為*.asm的目標檔案(在本例中就是x64\amd64\fun.obj),如圖 34所示。

這裡寫圖片描述

圖 34 為驅動工程指定*.asm的目標檔案作為連結庫檔案

  ⑩ 最後編譯專案:【生成】–>【(重新)生成解決方案】,如無意外則編譯成功,如圖 35:

這裡寫圖片描述

圖 35 成功編譯含*.asm彙編檔案的驅動工程

注:
 在64位驅動工程中混合彙編編譯的方式,暫時只適用於VS2010。
 在VS2008的驅動工程中,即使使用相同步驟配置,其DDK的build.bat指令碼卻無法呼叫MASM編譯器ml64.exe對*.asm彙編檔案進行編譯,亦即在編譯*.cpp時無法自動得到*.asm的目標檔案並進行LINK。

13. 附錄4:常見異常解決方案

 13.1. [error LNK 2019] - unresolved external symbol [email protected] referenced in function [email protected]

#include<ntddk.h> 

VOID DriverUnload(PDRIVER_OBJECT driver) 
{ 
    DbgPrint("load Driver\r\n"); 
}

NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING reg_path) 
{ 
    DbgPrint("Hello, WDK Demo!"); 
    driver->DriverUnload=DriverUnload; 
    return STATUS_SUCCESS; 
}

  以上述驅動程式原始碼為例,在使用VS2008 / VS2010 編譯時報錯如下:

1>DDKBLD: ================ Build warnings =======================
1>1>BufferOverflowK.lib(gs_support.obj) : error LNK2019: unresolved external symbol [email protected] referenced in function [email protected]
1>1>d:\01_wor~1\c\vs2008\re\helloddk\helloddk\bufferoverflowk.lib(gs_support.obj) : error LNK2019: unresolved external symbol [email protected] referenced in function [email protected]
1>1>d:\01_wor~1\c\vs2008\re\helloddk\helloddk\objchk_win7_x86\i386\HelloDDK.sys : fatal error LNK1120: 1 unresolved externals
1>1>d:\01_wor~1\c\vs2008\re\helloddk\helloddk\objchk_win7_x86\i386\helloddk.sys : error LNK1120: 1 unresolved externals
1>DDKBLD: =======================================================

  異常原因:
    這是一個連結錯誤,表示系統在連結時找不到入口函式[email protected]
    在VS2008 / VS2010中預設的編譯方式是採用C++方式的,而這個錯誤意思是C編譯器對DriverEntry進行編譯後的結果,字首“_”是C編譯器特有的,字尾“@8”是所有引數的長度。所以C++編譯器一定是把DriverEntry編譯成了系統無法認識的另一副模樣了(實際上,C++編譯器會把它編譯成以“[email protected]@”開頭的一串很長的符號)。
    
  解決方案:
    在報錯的函式DriverEntry前面加上extern “C”修飾符即可。
    extern “C”提醒編譯器要使用C編譯格式編譯DriverEntry函式,這樣編譯生成的函式名稱為“[email protected]”,連結器即可正確地識別出符號了。
    需要注意的是,若報錯的不是函式DriverEntry ,而是其他函式XXXXX,則也需要在前面新增extern “C”修飾符。
    修改後的程式碼如下:

#include<ntddk.h> 

VOID DriverUnload(PDRIVER_OBJECT driver) 
{ 
    DbgPrint("load Driver\r\n"); 
} 

extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING reg_path) 
{ 
    DbgPrint("Hello, WDK Demo!"); 
    driver->DriverUnload=DriverUnload; 
    return STATUS_SUCCESS; 
}

 13.2. GuestOS安裝VirtualKD後若退出TestSigning模式則無法啟動Windows

  GuestOS安裝VirtualKD後,若再使用以下命令關閉系統的測試模式,則會出現如圖 36所示的情況,無法登入系統,錯誤程式碼為0xc0000428

bcdedit /set testsigning off // 關閉系統測試模式

這裡寫圖片描述

圖 36 無法啟動Windows

  異常原因:
    GuestOS安裝VirtualKD後,C:\Windows\System32\kdcom.dll會被替換成供VirtualKD使用的另一個同名檔案kdcom.dll,原kdcom.dll會被備份為kdcom_old.dll
    需知kdcom.dll是Windows中極其重要的檔案,負責除錯驅動程式以及核心模組,它在windows開機時就會被載入到記憶體中,如果損壞會導致藍屏。
    而由於VirtualKD的kdcom.dll簽名可能是過期失效(或未被認可)的,此後若關閉系統的測試模式,系統在啟動時會重新發起對kdcom.dll檔案的簽名校驗,最終因校驗不通過導致系統啟動失敗。
    
  解決方案:
    在系統關閉測試模式之前,恢復原有的kdcom.dll檔案即可 (若很不幸地你的GuestOS在恢復kdcom.dll前已經關閉了測試模式,可以嘗試還原VM快照或者用PE登陸系統替換kdcom.dll檔案)。

    開啟C:\Windows\System32目錄,可以發現有兩個檔案:kdcom.dll與kdcom_old.dll
    右鍵檢視kdcom.dll屬性,在詳細資訊一欄可知這是VirtualKD使用的檔案,而另一個kdcom_old.dll原檔案。只需備份kdcom.dll,然後把kdcom_old.dll重新命名為kdcom.dll即可。
    需要注意的是,恢復kdcom.dll檔案後VirtualKD就會失效了,若下次需要使用VirtualKD則還得把這兩個檔案再次交換。

這裡寫圖片描述

圖 37 C:\Windows\System32\kdcom.dll
這裡寫圖片描述

圖 38 VirtualKD的kdcom.dll

相關推薦

Win7-x64 + VMWare (Win7-x64) + WinDbg 除錯環境搭建

驅動開發入門 - 之二Win7-x64 + VMWare (Win7-x64) + WinDbg雙機除錯環境搭建 —— By EXP 2017-10-08 完整原文下載(轉載請註明出處,僅供分享學習,嚴禁用於商業用途) 1. 概述

Win7除錯環境搭建配置VMware的管道虛擬串列埠

轉:http://www.16boke.com/article/detail/171 WinDbg除錯核心時,被設計為雙機除錯,需要另一臺計算機(除錯機)來除錯被除錯的計算機(被除錯機),WinDbg必須安裝在除錯機上,除錯機與被除錯機通過串列埠相連線。   環境: 主機:

Win7除錯環境搭建常見問題

轉:http://www.16boke.com/article/detail/175 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適合除錯機的相應位數

Win7除錯環境搭建除錯

  轉:http://www.16boke.com/article/detail/174 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適

Win7除錯環境搭建配置WinDbg

  轉:http://www.16boke.com/article/detail/173 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適

Win7除錯環境搭建配置GuestOS的啟動項

轉:http://www.16boke.com/article/detail/172 環境:   主機:Win7 虛擬機器:VMware 11.1.0 build-2496824 虛擬機器內作業系統(又稱GuestOS):Win7 WinDbg:適合除錯機的相應位數

WinDbg+VMWare除錯環境搭建

因為要學習一下驅動開發,需要搭建一個除錯環境,我按照《寒江獨釣——windows核心安全程式設計》一書搭建了一個WinDbg+VMWare的雙機除錯環境,這其中遇到了一些小問題,雖然只是一些細節問題,但是如果初次遇到的話還是讓人有點抓狂的,我記錄下來,希望幫到和我遇到一樣問

搭建VS2017+WDK10+WinDBG除錯Win7環境過程遇到的坑與解決(WinDBG找不到串列埠、security_cookie導致的藍屏、看不到除錯訊息等)

一直使用Visual Studio + WDK的方式開發Windows驅動,最近想在VS2017下安裝WDK10開發驅動,結果遇到問題了,首先是沒法實現雙機除錯,然後是編譯出來的驅動在Win7平臺下一載入就藍屏,定位到是security_cookie的問題,緊接

winDbg + VMware + window 聯調環境搭建

真機調試 net 服務 x64 。。 .exe 鏈接 成了 內核開發 這裏簡單的介紹一下內核開發雙機聯調的搭建環境,盡管網上有很多類似的文章,但看了很多總是不太舒服,覺得不太明白,所以自己實踐一下總結一篇。下面就拿我的環境簡單介紹,希望別人可以看懂。準備工具:裝虛擬機VMw

libevent學習Windows7(Win7)下編譯libevent

Linux下編譯參考原始碼中的README檔案即可,這裡主要記錄Windows下的編譯。一.準備工作去官網下載最新的穩定釋出版本libevent-2.0.22-stable二.使用VS2012編譯1.解

4.AngularJS四大特征 雙向數據綁定

sco font int out grep 模型 多行文本 pan oot AngularJS四大特征之二: 雙向數據綁定 (1)方向一:把Model數據綁定到View上——此後不論何時只要Model發生了改變,則View中的呈現會立即隨之改變!實現方法: {{ }}、

linux學習日常的基礎命令收集

幫助文檔 gedit 查看 日期 取整 style 位置 某月 linux 1、 ls 2、pwd  顯示當前目錄所在位置 3、date  日期時間 4、cal  日歷   默認顯示當前該月   cal 2012 :查看2012年的日歷   cal 月 年 : 查看某年某月

【只怕沒有幾個人能說清楚】系列Unity中的特殊文件夾

物體 avi ebp time 編輯模式 tro hive 預覽 打包 參考:http://www.manew.com/thread-99292-1-1.html 1. 隱藏文件夾 以.開頭的文件夾會被忽略。在這種文件夾中的資源不會被導入,腳本不會被編譯。也不會出現

態運維分享 服務型CMDB的消費場景

新增 iso20000 那種 .cn 關聯 通知 變更 不同 維護 近年來,CMDB在IT運維管理中的價值逐步得到認可,使用CMDB的期望值也日益增長。然而,CMDB實施和維護的高成本卻一直是建設者們的痛點。那麽今天,我們來探討一下如何通過消費來持續驅動CMDB的逐步完善。

UVM序列篇sequence和item(上)

技術 一點 目標 idt 需要 開始 掛載 ron 前行 無論是自駕item,穿過sequencer交通站,通往終點driver,還是坐上sequence的大巴,一路沿途觀光,最終跟隨導遊停靠到風景點driver,在介紹如何駕駛item和sequence,遵守什麽交規,最終

Horizon7.1部署Horizon Composer服務器安裝

vmware horizon composerHorizon Composer是個可選服務,如果計劃部署鏈接克隆桌面池(可以節省90%磁盤利用率),則需要安裝。我在windows2016上部署的Sql Server2016,ip是X.X.X.2,並在建立一個名為Horizon Composer的數據庫,防火墻

【2017-07-01】Linux應用開發工程師面試問題記錄關於結構體的大小及內存對齊問題

偶數 而且 strong span net 但是 開發 f11 flag Tencent後臺服務器開發有一道題是計算一個結構體的sizeof的大小: struct strData { int m_Int; char m_Char; short m_Short; char

Linux時間子系統Alarm Timer

數據 類型 oid mtime orm 分別是 type mon 超時 一、前言 嚴格來講Alarm Timer也算POSIX Timer一部分,包含兩種類型CLOCK_REALTIME_ALARM和CLOCK_BOOTTIME_ALARM。分別是在CLOCK_REALTI

Modbus庫開發筆記Modbus消息幀的生成

不同的 command dwr 分別是 slave 識別碼 align 數據格式 .com 前面我們已經對Modbus的基本事務作了說明,也據此設計了我們將要實現的主從站的操作流程。這其中與Modbus直接相關的就是Modbus消息幀的生成。Modbus消息幀也是實現Mod

玩玩微信公眾號Java版接收、處理及返回微信消息

log med iou set arch weixin b- rom data- 前面已經配置了微信服務器,那麽先開始最簡單的接收微信消息吧~ 可以用我們的微信號來直接進行測試,下面先看測試效果圖: 這是最基本的文本消息的接收、處理及返回,來看看是怎麽實現的