驱动开发入门 - 之二:Win7-x64 + VMWare (Win7-x64) + WinDbg 双机调试环境搭建
驅動開發入門 - 之二
Win7-x64 + VMWare (Win7-x64) + WinDbg
雙機調試環境搭建
*—— By EXP 2017-10-08 *
完整原文(轉載請注明出處,僅供分享學習,嚴禁用于商業用途)
1. 概述###
1.1. 前言
適讀人群:具備良好的C/C++開發經驗,一定的逆向工程基礎。
前置閱讀:《驅動開發入門 - 之一 :Win7 SP1 x64 驅動開發環境搭建》
為方便起見,在下文中使用【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簡介
——部分內容摘于博文:http://blog.csdn.net/keidoekd2345/article/details/50125747
在安裝微軟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傳輸速率 | 官方地址 |
4. 安裝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作為管道串口命名)
③ 添加一個串行端口:【添加】 --> 【串行端口】 --> 【下一步】 --> 【輸出到命名管道】 --> 【下一步】,如圖 3和圖 4。
圖 3 添加串行端口 圖 4 設置為管道串口④ 如圖 5設置如下值,點擊【完成】按鈕。
命名管道:\.\pipe\com_1 (會自動填上編號最小的可用串口)
【該端是服務器。】
【另一端是應用程序。】
【勾上】啟動時連接。
⑤ 最后回到如圖 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命令進行配置。
詳細的配置方式如下:
① 虛擬機開機后,正常登陸到Win7系統桌面(若已按照上文配置,當前所登陸到的Win7系統正處于【測試模式】,可以通過桌面右下角的水印驗證,如圖 8所示。某些系統會屏蔽這個水印,此時可以通過命令【bcdedit /enum】確認testsigning的值是否為Yes以判斷系統當前是否處于測試模式)。
② 如圖 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做雙機調試。
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版本的符號路徑下載的站點:
https://developer.microsoft.com/en-us/windows/hardware/download-symbols
以本文所采用的操作系統版本為例,選擇【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:
重新編譯并簽名VS2010_WDK_Demo驅動項目,拷貝VS2010_WDK_Demo.sys到GuestOS中,并使用DriverMonitor / InstDrv裝載并啟動該驅動,則可以在WinDbg中捕獲到剛才添加的內核消息“Hello, Driver By VS2010”,如圖 19所示。
圖 19 調試一個簡單的驅動程序9.4. 加入斷點調試
由于驅動程序中沒有斷點,驅動程序被裝載后轉瞬就運行完了。
為了便于調試,這次在驅動程序的入口函數DriverEntry中加入INT 3系統中斷的匯編代碼,如圖 20所示(此處只演示效果,暫不說明如何在x64系統中嵌入匯編代碼,若有需要了解可見附錄):
重新編譯并簽名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的使用后,其他驅動程序的調試方式也是大同小異,此處就不再一一敘述了。
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 = 0x0000000000000000: 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進程
11. 附錄2: WinDbg常用命令/操作
可跳轉到此頁面查詢:
WinDbg 命令手冊
12. 附錄3:WDK(x64)+匯編的混合編譯
——部分內容參考于博文:http://blog.csdn.net/cosmoslife/article/details/9071949
使用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系統中斷匯編代碼:
③ 如圖 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)。
⑥ 右鍵【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平臺。
⑧ (重要)點擊【Object File】查看*.asm文件編譯所生成的目標文件*.obj的輸出位置。由于配置值使用了宏變量,可【點擊配置值】 --> 【下拉】 --> 【編輯】 --> 【宏】,找到對應的變量查看其真實值。
如圖 33所示,配置值為【(IntDir)</font><fontcolor="blue">其中<fontcolor="red">(IntDir)</font><font color="blue">%(FileName)</font>.obj】。 其中<font color="red">(IntDir)</font><fontcolor="blue"> 其中<fontcolor="red">(IntDir)為宏變量,查得其值為x64\amd64</font>
%(FileName)泛指所編譯的*.asm文件名稱(不含后綴),如當前所編譯的fun.asm文件,%(FileName)的值則為fun。
因此對于fun.asm匯編文件而言,$(IntDir)%(FileName).obj的真實值為x64\amd64\fun.obj,記下這個值。
⑨ 驅動工程是通過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所示。
⑩ 最后編譯項目:【生成】–>【(重新)生成解決方案】,如無意外則編譯成功,如圖 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 _DriverEntry@8 referenced in function _GsDriverEntry@8
#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 _DriverEntry@8 referenced in function _GsDriverEntry@8
1>1>d:\01_wor~1\c\vs2008\re\helloddk\helloddk\bufferoverflowk.lib(gs_support.obj) : error LNK2019: unresolved external symbol _DriverEntry@8 referenced in function _GsDriverEntry@8
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: =======================================================
異常原因:
這是一個鏈接錯誤,表示系統在鏈接時找不到入口函數_DriverEntry@8。
在VS2008 / VS2010中默認的編譯方式是采用C++方式的,而這個錯誤意思是C編譯器對DriverEntry進行編譯后的結果,前綴“_”是C編譯器特有的,后綴“@8”是所有參數的長度。所以C++編譯器一定是把DriverEntry編譯成了系統無法認識的另一副模樣了(實際上,C++編譯器會把它編譯成以“?DriverEntry@@”開頭的一串很長的符號)。
解決方案:
在報錯的函數DriverEntry前面加上extern "C"修飾符即可。
extern "C"提醒編譯器要使用C編譯格式編譯DriverEntry函數,這樣編譯生成的函數名稱為“_DriverEntry@8”,鏈接器即可正確地識別出符號了。
需要注意的是,若報錯的不是函數DriverEntry ,而是其他函數XXXXX,則也需要在前面添加extern "C"修飾符。
修改后的代碼如下:
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則還得把這兩個文件再次交換。
總結
以上是生活随笔為你收集整理的驱动开发入门 - 之二:Win7-x64 + VMWare (Win7-x64) + WinDbg 双机调试环境搭建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字母框如何影响UI内容的理解
- 下一篇: shiro学习(4):shiro认证流程