鏈接庫)
在CSDN上刷到這個問題時我第一反應是有點復雜——求CSDN的技術大佬幫忙提取一下軟件里面的dll文件發(fā)帖人通常是把某個軟件裝在電腦里想從里面拿幾個dll文件出來??赡苁菫榱藗浞?、為了分析、為了修復另一個軟件的報錯也可能是想看看別人是怎么寫的。這類需求在論壇里隔三差五就會出現(xiàn)但真正能把提取dll這件事講清楚、講透、講得不踩坑的帖子卻很少。我自己早期搞逆向分析、軟件封裝、系統(tǒng)遷移時也反復跟dll文件打交道踩過文件被占用、提取出來缺依賴、32位和64位搞混等各種坑。今天就把這套東西系統(tǒng)整理一遍從dll文件是什么、什么時候需要提取到具體的提取方案、工具選型、常見問題排查盡量用大白話加實操記錄的方式講明白。不管你是剛接觸dll的新手還是已經會復制粘貼但不太理解原理的進階用戶這篇文章都能讓你少走不少彎路。1. 先搞清楚dll文件到底是什么為什么有人要提取它1.1 dll文件的本質動態(tài)鏈接庫不是加密包dll的全稱是Dynamic Link Library也就是動態(tài)鏈接庫。你可以把它理解成一個軟件運行時需要調用的零件倉庫。軟件主程序exe本身只負責管流程真正干活的功能模塊——比如彈窗繪制、網絡請求解碼、圖片格式解析、加密算法運算——都放在一堆dll文件里。主程序在啟動或運行到某個功能時才動態(tài)把對應的dll加載進內存調用里面的函數(shù)。這種設計的直接好處就是多個軟件可以共用同一個dll不必每個exe里都塞一份相同代碼省磁盤、省內存也方便廠商單獨更新某個模塊。比如很多軟件都會復制一份msvcp140.dll到自己的目錄里而這個文件其實來自微軟的Visual C運行庫。也正因為dll是零件倉庫當你看到某個軟件目錄下躺著幾十上百個dll時根本不需要驚訝。像工業(yè)軟件、游戲、大型工具套件自帶幾十個甚至幾百個dll是很常見的事。1.2 常見需求場景不只是破解這一條路很多人一聽到提取dll就往破解方向想但實際工作中合法的、正經的需求占了大頭。我自己歸納了一下最常見的場景有以下幾類系統(tǒng)修復某個軟件報錯找不到xxx.dll但你又不想重裝整個軟件于是從原安裝包、從另一臺同配置電腦里把這個dll提取出來補上。版本備份與遷移老版本軟件升級前先把它依賴的dll備份下來防止新版本不兼容導致功能回退。學習與研究想看看某個軟件調用了哪些系統(tǒng)API、做了什么邏輯從dll里導出函數(shù)、看導入表、分析數(shù)據(jù)段這是很多安全研究者和技術愛好者的入門功課。封裝便攜版把軟件綠色化把所有依賴的dll和資源文件提取出來放到一起做到免安裝運行。二次開發(fā)有些廠商提供了dll形式的SDK你需要在自己的程序里動態(tài)調用這些dll的導出函數(shù)第一步當然是把dll從官方安裝包中提取出來。這些需求的共通點是dll文件本身是軟件的一部分提取之后用于備份、修復、研究或集成而不是用來繞過授權。后者我既不做也不寫這篇文章只講正路子。1.3 先從要不要提取想清楚很多dll根本不該手動碰在動手之前我想先潑一盆冷水。dll不是純文本它是PE格式的二進制文件Portable Executable內部結構包含DOS頭、PE頭、節(jié)區(qū)表、導入表、導出表、資源段等。直接拿記事本打開看到的全是亂碼。所以提取dll這件事本質上是從指定位置把二進制文件完整復制出來而不是解包出某種代碼。另外一點要提醒如果是Windows系統(tǒng)目錄里的dll比如C:WindowsSystem32下的絕大多數(shù)屬于系統(tǒng)組件不應該去提取、覆蓋、刪除。微軟對系統(tǒng)文件有專門的文件保護機制你強行替換輕則觸發(fā)系統(tǒng)文件檢查報錯重則導致系統(tǒng)不穩(wěn)定。普通用戶遇到某某dll缺失的報錯時優(yōu)先級應該是先用系統(tǒng)工具修復再考慮從可信來源復制而不是亂七八糟的下載站下個dll修復工具亂裝一通。所以這篇文章里的提取默認指你有權訪問的、非系統(tǒng)關鍵路徑下的軟件dll比如自己電腦上安裝的第三方軟件目錄、官方安裝緩存包中的dll。這本身不需要任何破解手段最多就是繞開權限和占用問題。2. 提取前的基本功先摸清目標dll的位置和狀態(tài)2.1 先做兩件事定位和確認不管用什么方案動手前必須先搞清楚兩個問題你要的dll在哪、它現(xiàn)在處于什么狀態(tài)。第一是位置。第三方軟件安裝后dll一般出現(xiàn)在以下幾個地方軟件安裝目錄根目錄比如C:Program FilesSomeApp。軟件的bin、lib、plugins、runtime等子目錄。Windows的System32或SysWOW64目錄如果這個軟件被系統(tǒng)級集成。安裝包緩存目錄比如C:ProgramDataPackage Cache這類位置。%AppData%或%LocalAppData%下部分UWP應用或用戶級軟件會放在這里。定位方式很簡單拿到軟件快捷方式右鍵→打開文件所在位置基本就能看到主程序目錄。更穩(wěn)妥的是打開任務管理器切到詳細信息頁簽找到對應軟件的進程右鍵→打開文件所在位置這樣定位到的目錄一定是正在使用的dll所在目錄。第二是狀態(tài)。你要提取的dll是否正被某個進程占用決定了你能不能直接復制。如果直接復制時報文件正在被另一個程序使用就說明它已經加載到某個進程內存里了。這時候就有兩條路要么從進程內存中抓取方案三要么先關掉相關軟件再復制方案一。2.2 必備工具清單不需要重型武器提取dll這件事老實說并不需要什么高端工具。手頭有一臺Windows電腦、一雙能看提示信息的眼睛再加幾個免費小工具基本就夠用了。我平時常用的工具清單如下工具用途是否需要安裝難度文件資源管理器定位dll、直接復制系統(tǒng)自帶入門7-Zip解壓exe/msi安裝包提取內部文件綠色版即可入門Process Explorer查看進程加載的dll、提取已加載dll免安裝中等proc_dump抓取進程內存中的模塊導出命令行工具進階Dependencies查看dll的依賴關系、導出函數(shù)免安裝進階資源管理器任務管理器結束占用進程、查看PID系統(tǒng)自帶入門這些工具的共同點是不需要破解不需要注冊機官方渠道都能下載到。我不會推薦任何帶捆綁或者來源不明的dll修復大全之類的軟件那才是真正會把你電腦搞壞的東西。2.3 權限和32/64位的判斷提前確認提取前我強烈建議你先確認兩件事否則后面十有八九要返工。第一是權限。如果你要復制的dll位于Program Files、System32這類高權限目錄直接在資源管理器里復制粘貼可能會被拒。解決辦法是右鍵資源管理器選擇以管理員身份運行或者先把目標文件復制到當前用戶有權限的目錄比如桌面、文檔文件夾再做后續(xù)處理。第二是位數(shù)判斷。dll分32位和64位兩種不能混用。怎么判斷一個dll是32位還是64位最簡單的方法裝一個Dependencies工具微軟官方有一些支持庫但Dependencies更好用把dll拖進去工具會直接顯示它的PE格式是x86還是x64。沒有工具的情況下還有一個土辦法打開命令行進入dll所在目錄用dumpbin /headers需要Visual Studio環(huán)境或者where /r C: xxx.dll配合file命令檢查但這些對小白不太友好。注意64位系統(tǒng)上System32目錄里放的是64位dllSysWOW64目錄里放的是32位dll名字雖然反直覺但這是Windows的設計。3. 四種最常用的dll提取方案與操作步驟3.1 方案一最基礎的文件復制法別嫌簡單適用場景軟件已經安裝完成dll就在安裝目錄下且該軟件當前沒有運行。操作步驟很簡單定位到軟件安裝目錄找到目標dll。右鍵復制粘貼到你要保存的地方。如果復制時提示權限不足或文件被占用先關閉軟件再以管理員身份打開資源管理器重試。這個方案的優(yōu)點是零學習成本不依賴任何外部工具。缺點也很明顯如果dll被占用你就復制不出來如果dll在安裝包內部而非安裝目錄那你根本找不到它。所以它只能算基礎中的基礎。有一種情況要特別說明你在安裝目錄下找到的dll很可能不是完整的有效版本。比如某些軟件在啟動時會動態(tài)生成配置并寫入dll同目錄下的外部文件你復制出的dll本身沒問題但它依賴的配置、子目錄、資源文件沒有跟著復制所以提取出來看著有文件放到另一臺機器上卻跑不起來。這不算提取失敗而是只提取dll、沒有提取完整依賴導致的。后續(xù)要驗證有效性時我會在第5章詳細說依賴檢查的方法。3.2 方案二從安裝包中解出dll沒有安裝也能拿適用場景你只有軟件的安裝程序setup.exe、installer.msi、.exe安裝包還沒安裝或者安裝目錄里沒有你想要的dll但你懷疑它在安裝包里。很多安裝包本質上是一個自解壓壓縮殼里面打包了真正的安裝數(shù)據(jù)和文件流。用7-Zip直接打開setup.exe有時候能像看壓縮包一樣看到內部目錄結構。具體做法確保已安裝7-Zip。右鍵點擊安裝程序選擇打開壓縮包不能用解壓先打開看結構。在打開的窗口里你會看到類似[0]、[1]編號的流或者$TEMP之類的目錄逐層進入直到看到.dll、.exe、.cab、.msi等文件。選中目標dll拖出來即可。這里有個關鍵點如果安裝包里面是一個.msi文件不要直接解壓要用管理器模式提取這在方案四里說明。如果安裝包是Inno Setup封裝的怎么判斷用7-Zip打開后能看到{app}、{tmp}這種占位目錄基本就是Inno Setup那就用Inno Setup Unpacker這類專用工具它能更完整地解出內部文件。7-Zip雖然能解出一部分但往往拿不到所有打包的組件。從安裝包提取有三點好處一是不需要先安裝完整軟件二是可以精確拿到原始未注冊的dll文件三是安裝包內的dll通常沒有被占用復制過程干凈利落。但這一招也有局限安裝包可能對內部文件做了壓縮甚至異或混淆直接解出來的是經過處理的樁文件而不是真正的dll。我在處理國內一些老牌軟件時遇到過好幾次解出來的文件大小不對、頭部信息損壞這時候只能先正常安裝再從安裝目錄提取。3.3 方案三從運行中的進程里抓取dll繞過文件占用適用場景軟件正在運行dll已經加載進內存但磁盤上的文件被鎖定無法復制。這一招也是做動態(tài)分析的人最常用的基本功。這里要用到Process ExplorerSysinternals套件里的經典工具微軟官方免費免安裝直接運行exe即可。操作步驟以管理員身份啟動Process Explorer。在進程列表里找到目標軟件的主進程通常和軟件同名比如MyApp.exe。如果你不懂怎么找可以先打開軟件再看。雙擊進程打開進程屬性面板切到Image或Strings頁簽——注意不同版本的Process Explorer界面不同新版通常在底部會有該進程加載的所有dll列表。在dll列表里找到目標dll選中它右鍵→Create Diff Image或者通過Strings查看詳細路徑。關鍵一步右鍵目標dll→Save As把它保存到本機任意位置。這個Save As操作實際是把該dll的完整內存鏡像寫出來得到的就是一份可用的dll文件副本。它最大的意義在于即使原始文件被刪除、被標記為待刪除、或被獨占鎖定只要它在內存中加載著你就能把它摳出來。我實際使用中發(fā)現(xiàn)的注意點如果你想要的是某個已經被hook或者被修改過的dll從內存里抓出來的是運行時被修改后的版本而不是磁盤上的原始版本。做逆向分析時要注意這一點兩種版本可能不等同。Process Explorer的dll列表刷新頻率有限如果你剛啟動軟件最好等幾秒讓列表穩(wěn)定后再保存。即便軟件當前運行正常也要先確認進程有權限訪問。用管理員身份運行Process Explorer能避免很多Access Denied報錯。如果在Process Explorer里找不到目標dll還可以用命令行工具proc_dump定向抓取發(fā)布模塊。這個用法比較高級普通提取用不上我在這里只提一句proc_dump可以做進程的內存dump然后你用PE工具從dump文件里檢查模塊對動態(tài)分析是很有用的路子。3.4 方案四從MSI安裝包中提取dll利用管理安裝模式適用場景你的安裝包是.msi格式或者setup.exe引導之后會在某個緩存目錄留下.msi文件你想不安裝直接拿到里面的dll。Windows Installer提供一個官方支持的管理安裝administrative install功能用命令行就能把MSI中的文件解到指定目錄。操作命令如下msiexec /a 路徑到你的安裝包.msi /qb TARGETDIRD:提取目錄參數(shù)說明/a啟用管理安裝模式它不會在系統(tǒng)里注冊軟件只是把安裝文件解壓到TARGETDIR指定的位置。/qb只顯示基本進度條界面不需要你點按鈕。TARGETDIR解壓目標目錄必須寫完整路徑路徑末尾不要省掉反斜杠盡量別有中文和空格避免出現(xiàn)解析問題。執(zhí)行完以后在D:提取目錄下通常會出現(xiàn)一個類似安裝后的目錄結構你進入對應子目錄就能找到目標dll。如果MSI包的某個文件被設置成僅在安裝時才生成這種模式解出來的可能是原始模板而不是最終落地的文件這一點同樣要在后續(xù)驗證時注意。我自己處理setup.exe時常用Resource Hacker或者Universal Extractor一類工具先解出內層的.msi再跑上面這條命令。整個過程比直接裝一遍軟件要快而且不污染系統(tǒng)。3.5 提取后的校驗與歸檔復制出來并不是終點很多新手容易在這里翻車費了老大勁把dll復制出來了結果放到另一臺電腦上一運行還報錯就認為提取失敗了。其實文件本身很可能沒錯是忽略了三件事。第一是校驗文件是否完整。用右鍵→屬性→數(shù)字簽名查看簽名是否有效或用PowerShell命令Get-FileHash D:提取目錄your.dll -Algorithm SHA256如果軟件原版有簽名提取出來的dll哈希值應該和原文件一致除非你從內存里抓的是修改版。不一致時要警惕提取過程出問題。第二是記錄原文件的時間戳和版本號。在文件屬性→詳細信息里能看到文件版本、產品版本。我在做遷移備份時會把原始位置、原文件名、版本號、提取日期記到一個文本文件里和dll放一起。這不僅方便你事后追溯也方便你將來反查這個dll到底是哪個軟件裝的。第三是檢查依賴關系。dll之間是會互相調用的一個dll可能依賴另一個dll。你只把目標dll提取出來但它的依賴dll沒提取放到干凈環(huán)境比如精簡版Windows虛擬機里自然跑不起來。關于依賴檢查的詳細操作我會在第5章展開講。4. 常見問題與排查技巧實錄4.1 文件被占用、權限不足Windows最經典的攔路虎我在給同事遠程指導時90%的人第一步就會卡在這個問題上。明明找到了dll一復制就彈文件正在被另一程序使用或需要管理員權限。排障順序如下先確認軟件是否還在運行任務管理器里把對應進程全部結束注意有些軟件會留常駐后臺進程托盤區(qū)圖標不算結束要去任務管理器詳細信息里一個個找。如果結束進程后還是被占用有可能是Windows資源管理器緩存或殺毒軟件的實時防護在訪問該目錄。這時候把殺毒軟件實時防護臨時關掉再試或者直接進安全模式操作。如果提示權限不足在資源管理器里對目標文件夾右鍵→屬性→安全→編輯給當前用戶加完全控制權限或者直接用管理員身份運行資源管理器。還不行就用方案三從進程內存里抓。這里我提供一個很少人提的小技巧用handle.exeSysinternals的另一個工具可以精確查到底是誰占用了這個dllhandle.exe 你的dll文件名它會列出占用該文件的進程PID和句柄類型你能看到是主程序占用還是某個插件進程占用。知道是誰占用才能高效決定結束哪個進程。4.2 提取出的dll在另一臺電腦上不能用依賴缺失和運行庫缺失這種情況最典型也最容易讓新手崩潰。把dll復制到另一臺電腦后軟件還是報無法定位程序輸入點或無法加載DLL。問題大概率出在兩個方面第一目標dll依賴了其他dll而這些依賴沒有跟著過去。解決方法是用Dependencies工具打開dll文件查看它的Imports導入表把缺失的依賴模塊一并提取。Dependencies會在左側列出一棵依賴樹缺失的項會用紅色或黃色標出來。第二目標dll本身依賴了Visual C運行庫、.NET運行時等系統(tǒng)組件。這類dll就算你復制一百個過去沒有運行庫照樣跑不起來。報找不到MSVCP140.dll這類錯誤時正確解法是裝對應版本的Visual C Redistributable而不是去網上隨便下載一個dll丟進System32。注意在純技術交流時我??吹接腥苏f從另一臺電腦拷dll過來就能修復這個說法只在特定條件下成立。除非你有十足把握確認目標系統(tǒng)缺的就是這一個文件且版本兼容否則后果是修好了這一個報錯又冒出三個新報錯。我真的建議優(yōu)先用運行庫安裝包和系統(tǒng)自帶修復工具。4.3 32位dll被當成64位用或者反過來Windows 64位系統(tǒng)上32位進程運行時需要的是SysWOW64目錄下的32位dll64位進程需要的是System32目錄下的64位dll。名字聽著反直覺但這是微軟系統(tǒng)的老規(guī)矩。如果你提取出來的dll放錯位置最常見的報錯是不是有效的Win32應用程序或者應用程序無法啟動 0xc000007b。判斷dll位數(shù)的方法除了用Dependencies還有一個輕量級技巧用記事本打開dll不可能得到結果但可以看它的頭部。用任意十六進制工具打開dll找到PE頭區(qū)域如果顯示PE..L說明是64位PE..d?說明是32位準確說在0x5C偏移處的機器碼0x8664代表x640x014c代表x86。對新手來說我建議直接用Dependencies看兩秒鐘就有結論。4.4 殺毒軟件攔截提取操作并不是誤報那么簡單提取dll時殺毒軟件突然彈窗檢測到可疑操作這種情況碰到過好幾次。有真正誤報的也有因為你操作方式不規(guī)范導致報警的。經驗是先把提取出來的dll放到單獨文件夾用Virustotal之類的在線掃描服務查一下哈希值看看實際檢出率。如果確認文件來源可信可以在本地殺毒軟件里設置排除目錄再繼續(xù)。但我不建議為了提取一個dll把整個殺毒軟件關掉這是很多人的壞習慣中一次招就得不償失。另外提一句從內存中抓取的dll文件其PE結構經過內存對齊和磁盤對齊方式不一樣某些安全軟件會把它識別為格式異常。這在分析工作中很正常不代表文件有毒。5. 提取完之后的正確姿勢驗證、分析和善后5.1 用Dependencies解讀你的dll底細提取dll只是開始你真正想干的事大概率在后面。這里我強烈建議你學一下Dependencies這個工具它比老牌工具Dependency Walker好用太多。用法很簡單把dll文件拖進Dependencies窗口它會自動解析PE頭列出以下關鍵信息架構x86、x64、ARM64。導入表Imports當前dll調用了哪些外部dll的哪些函數(shù)。導出表Exports當前dll為其他程序提供了哪些函數(shù)。延遲加載導入表。依賴樹以圖形方式展開所有依賴項缺失項會高亮。導入表常被大家忽略但它是判斷這個dll適合在什么環(huán)境用的重要依據(jù)。比如一個dll導入了USER32.dll里的MessageBoxW說明它很可能有GUI交互導出表里如果包含某個特定前綴的函數(shù)名往往暗示它是某個插件的接口dll。5.2 驗證數(shù)字簽名和文件信息不碰來路不明的文件提取完dll我建議你養(yǎng)成一個習慣先看數(shù)字簽名。右鍵dll→屬性→數(shù)字簽名如果顯示簽名無效或者無法驗證簽名而原始文件是有簽名的那說明你提取的版本不對、被篡改過或者從內存提取時破壞了簽名區(qū)。在涉密、安全敏感的項目里這種文件要直接棄用。再一個點是文件屬性里的原始文件名和文件版本。很多軟件自帶的dll版本號會寫在Version Info資源段里。你看一眼版本號就能判斷自己的提取對象是不是最新版。不同版本的dll之間可能存在函數(shù)集差異這在二次開發(fā)時是致命問題——你調用的導出函數(shù)在舊版dll里可能壓根不存在。善后工作也很重要。提取出來的dll和原始軟件之間可能存在授權綁定、聯(lián)網校驗等機制。把dll單獨抽出來用于其他環(huán)境時如果出現(xiàn)意外彈窗或者功能失效不要第一時間懷疑提取沒提取好先思考這個軟件本身的保護機制。這一點尤其要在心里有數(shù)。6. 從一枚dll延伸出去你可以繼續(xù)學習什么dll提取只是入口順著這條路可以深挖的知識比你想象中多得多。我自己就是先學會提取dll后來一步步走到PE解析、函數(shù)調用Hook、資源修改這條路上的。至少有三個方向值得延伸PE文件格式花半天時間讀懂DOS頭、PE頭、節(jié)區(qū)表、導入表、導出表之后你再看到dll就不會只把它當文件而是一套有結構的數(shù)據(jù)。Windows進程加載機制理解系統(tǒng)是怎么把dll映射進進程地址空間的LoadLibrary和靜態(tài)導入的區(qū)別在哪里為什么有些dll改個名字就加載失敗。導出函數(shù)分析用Dependencies查看導出表找出你想調用的函數(shù)配合官方文檔或者反匯編工具去理解它的行為這就是很多SDK逆向工作的起點。我個人在實際操作中最大的體會是很多人一上來就追求高級工具反而在基礎的文件復制、安裝包解壓、進程管理上栽跟頭。其實dll提取這件事七八成場景靠的是耐心和細心——耐心找到目標文件細心判斷它的位數(shù)、版本、依賴和占用狀態(tài)剩下兩三成才是工具技巧的比拼。最后再分享一個小技巧不管用哪一種方案提取dll我都建議在操作前建一個以軟件名版本號日期命名的文件夾把提取出的dll、對應的依賴清單、提取方式說明放進去。這個習慣看著不起眼但當你需要回退版本、復現(xiàn)問題、給同事交接時它能幫你省下大把時間。我就是靠這個習慣在前幾年做系統(tǒng)遷移時幾乎零成本地恢復了十幾個老軟件的運行環(huán)境沒有一次翻車。