Windows內(nèi)核調(diào)試器_第1頁
Windows內(nèi)核調(diào)試器_第2頁
Windows內(nèi)核調(diào)試器_第3頁
Windows內(nèi)核調(diào)試器_第4頁
Windows內(nèi)核調(diào)試器_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、Windows 內(nèi)核調(diào)試器Windows 內(nèi)核調(diào)試 器原理淺析SoBeIt前段時(shí)間 忽然對內(nèi)核調(diào)試器實(shí)現(xiàn)原來發(fā)生 了興趣,于是簡單分析了一 下當(dāng)前 windows 下主流內(nèi)核調(diào)試器原理,并模 仿原理自己也寫了個(gè)極其簡 單的調(diào)試器 :WinDBGWinDBG 和用戶調(diào)試器一點(diǎn)很大不 同是內(nèi)核調(diào)試器在一臺機(jī)器上 啟動(dòng), 通過串口調(diào)試 另一個(gè)相聯(lián)系的以 Debug 方式啟 動(dòng)的系統(tǒng),這個(gè)系統(tǒng)可以是 虛擬機(jī)上的系 統(tǒng),也可以是另一臺機(jī)器上的 系統(tǒng) (這只是微 軟推薦和實(shí)現(xiàn)的 方法,其實(shí)象 SoftICE 這類 內(nèi)核調(diào)試器可以實(shí)現(xiàn)單機(jī)調(diào)試 。很多人認(rèn)為主 要功能都是 在 WinDBG 里實(shí)現(xiàn) ,事實(shí)上并

2、不是那么一回事, windows 已經(jīng)把 內(nèi)核調(diào)試的機(jī) 制集成進(jìn)了內(nèi)核, WinDBG 、 kd 之類的內(nèi)核調(diào)試器要做 的僅僅 是通過串行發(fā) 送特定格式數(shù)據(jù)包來進(jìn)行聯(lián)系, 比如中斷系統(tǒng)、下斷點(diǎn)、顯 示內(nèi)存數(shù)據(jù)等 等。然后把收到的數(shù)據(jù)包經(jīng) 過 WinDBG 處理顯示 出來。在進(jìn)一步 介紹 WinDBG 之 前,先介紹兩個(gè)函數(shù):KdpTrace 、 KdpStub , 我在 windows 異常處理流程 一文里簡單提過這兩個(gè)函 數(shù)。 現(xiàn)在再提一下 , 當(dāng)異常發(fā)生于 內(nèi)核態(tài)下,會調(diào)用 KiDebugRoutine 兩次,異常發(fā)生于用戶態(tài) 下,會調(diào)用 KiDebugRoutine 一次,而且第一次調(diào)用

3、都是剛 開始處理異常的 時(shí)候。當(dāng) WinDBG 未被加載 時(shí) KiDebugRoutine 為 KdpStub , 處理也很簡單 , 主 要是對 由 int 0x2d引起的異 常如 DbgPrint 、 DbgPrompt 、加載卸載 SYMBOLS(關(guān) 于 int 0x2d 引起的異常將 在后面詳細(xì)介紹 等,把 Context.Eip 加 1,跳過 int 0x2d后面跟著 的 int 0x3指令。真正實(shí)現(xiàn) 了 WinDBG 功能 的函數(shù)是 KdpTrap ,它負(fù)責(zé)處理所有STATUS_BREAKPOINT和 STATUS_SINGLE_STEP(單步 異常。STATUS_BREAKPOIN

4、T的 異常包括 int 0x3、 DbgPrint 、 DbgPrompt 、加載卸 載 SYMBOLS 。 DbgPrint 的處理最 簡單, KdpTrap 直接向調(diào)試 器發(fā)含有字符串 的包 。 DbgPrompt 因?yàn)槭且敵霾⒔邮兆?符串, 所以先將含 有字符串的包發(fā) 送出去,再陷入循環(huán)等待接 收來自調(diào)試器的含有回復(fù)字符串 的包。 SYMBOLS 的加載和卸載 通過調(diào)用 KdpReportSymbolsStateChange , int 0x3斷點(diǎn)異常 和 int 0x1單 步異常 (這兩個(gè) 異常基本上是內(nèi)核調(diào)試器處理得 最多的異常 通過調(diào) 用 KdpReportExceptionSt

5、ateChange , 這兩個(gè)函數(shù)很相似 , 都是通過 調(diào)用 KdpSendWaitContinue 函數(shù)。 KdpSendWaitContinue 可 以說是內(nèi)核調(diào)試 器功能的大管 家,負(fù)責(zé)各個(gè)功能的分派。這個(gè) 函數(shù)向內(nèi)核調(diào)試器發(fā)送要發(fā) 送的信息,比 如當(dāng)前所有寄存器狀態(tài),每次單 步后我們都可以發(fā)現(xiàn)寄存器 的信息被更新 ,就是內(nèi)核調(diào)試器接受它發(fā)出的 包含最新機(jī)器狀態(tài)的包;還有 SYMBOLS 的 狀態(tài),這樣加載和卸載 了 SYMBOLS 我們都能在內(nèi)核調(diào)試器里 看到相應(yīng)的反 應(yīng)。然后 KdpSendWaitContinue 等待從內(nèi)核調(diào)試器發(fā)來的包 含命令的包, 決定下一步該干什么。讓我們來

6、 看看 KdpSendWaitContinue 都能干些什么 :case DbgKdReadVirtualMemoryApi:KdpReadVirtualMemory(&ManipulateState,&MessageData,ContextRecord ;break;case DbgKdReadVirtualMemory64Api:KdpReadVirtualMemory64(&ManipulateState,&MessageData,ContextReco rd;break;case DbgKdWriteVirtualMemoryApi:KdpWriteVi

7、rtualMemory(&ManipulateState,&MessageData,ContextRecor d;break;case DbgKdWriteVirtualMemory64Api:KdpWriteVirtualMemory64(&ManipulateState,&MessageData,ContextRec ord;break;case DbgKdReadPhysicalMemoryApi:KdpReadPhysicalMemory(&ManipulateState,&MessageData,ContextRecor d;break

8、;case DbgKdWritePhysicalMemoryApi:KdpWritePhysicalMemory(&ManipulateState,&MessageData,ContextReco rd;break;case DbgKdGetContextApi:KdpGetContext(&ManipulateState,&MessageData,ContextRecord; break;case DbgKdSetContextApi:KdpSetContext(&ManipulateState,&MessageData,ContextReco

9、rd; break;case DbgKdWriteBreakPointApi:KdpWriteBreakpoint(&ManipulateState,&MessageData,ContextRecord; break;case DbgKdRestoreBreakPointApi:KdpRestoreBreakpoin(&ManipulateState,&MessageData,ContextRecord ;break;case DbgKdReadControlSpaceApi:KdpReadControlSpace(&ManipulateState,&a

10、mp;MessageData,ContextRecord ;break;case DbgKdWriteControlSpaceApi:KdpWriteControlSpace(&ManipulateState,&MessageData,ContextRecord ;break;case DbgKdReadIoSpaceApi:KdpReadIoSpace(&ManipulateState,&MessageData,ContextRecord; break;case DbgKdWriteIoSpaceApi:KdpWriteIoSpace(&Manipul

11、ateState,&MessageData,ContextRecord; break;case DbgKdContinueApi:if (NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus != FALSE return ContinueSuccess; else return ContinueError;break;case DbgKdContinueApi2:if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus != FALSE KdpGetStateChange(&

12、amp;ManipulateState,ContextRecord;return ContinueSuccess; else return ContinueError;break;case DbgKdRebootApi:KdpReboot(;break;case DbgKdReadMachineSpecificRegister:KdpReadMachineSpecificRegister(&ManipulateState,&MessageData,Con textRecord;break;case DbgKdWriteMachineSpecificRegister:KdpWri

13、teMachineSpecificRegister(&ManipulateState,&MessageData,Co ntextRecord;break;case DbgKdSetSpecialCallApi:KdSetSpecialCall(&ManipulateState,ContextRecord;break;case DbgKdClearSpecialCallsApi:KdClearSpecialCalls(;break;case DbgKdSetInternalBreakPointApi:KdSetInternalBreakpoint(&Manipul

14、ateState;break;case DbgKdGetInternalBreakPointApi:KdGetInternalBreakpoint(&ManipulateState;break;case DbgKdGetVersionApi:KdpGetVersion(&ManipulateState;break;case DbgKdCauseBugCheckApi:KdpCauseBugCheck(&ManipulateState;break;case DbgKdPageInApi:KdpNotSupported(&ManipulateState;break;

15、case DbgKdWriteBreakPointExApi:Status = KdpWriteBreakPointEx(&ManipulateState,&MessageData,ContextRecord;if (Status ManipulateState.ApiNumber = DbgKdContinueApi;ManipulateState.u.Continue.ContinueStatus = Status;return ContinueError;break;case DbgKdRestoreBreakPointExApi:KdpRestoreBreakPoint

16、Ex(&ManipulateState,&MessageData,ContextReco rd;break;case DbgKdSwitchProcessor:KdPortRestore (;ContinueStatus = KeSwitchFrozenProcessor(ManipulateState.Processor;KdPortSave (;return ContinueStatus;case DbgKdSearchMemoryApi:KdpSearchMemory(&ManipulateState, &MessageData, ContextRecor

17、d;break;讀寫內(nèi)存、搜索 內(nèi)存、設(shè)置 /恢復(fù)斷 點(diǎn)、繼續(xù)執(zhí)行、重啟等等, WinDBG 里的功能是不 是都能實(shí)現(xiàn)了 ? 呵呵。每次內(nèi)核 調(diào)試器接管系統(tǒng)是通過調(diào)用 在 KiDispatchException 里調(diào)用 KiDebugRoutine(KdpTrace,但我們知道要讓 系統(tǒng)執(zhí)行到 KiDispatchException 必須是系統(tǒng)發(fā)生了異常。 而內(nèi)核調(diào)試 器與被調(diào)試系統(tǒng) 之間只是通過 串口聯(lián)系,串口只會發(fā)生中斷, 并不會讓系統(tǒng)引發(fā)異常。那 么是怎么讓系 統(tǒng)產(chǎn)生一個(gè)異常呢 ? 答案就在 KeUpdateSystemTime 里,每當(dāng) 發(fā)生時(shí)鐘中斷 后在 HalpClockInter

18、rupt 做了一些底層處理 后就會跳轉(zhuǎn)到這 個(gè)函數(shù)來更新 系統(tǒng)時(shí)間 (因?yàn)?是跳轉(zhuǎn)而不是調(diào)用,所以 在 WinDBG 斷下來后回溯堆棧是不 會發(fā)現(xiàn) HalpClockInterrupt 的地址的 ,是系統(tǒng)中調(diào)用最頻 繁的幾個(gè)函數(shù) 之一。在 KeUpdateSystemTime 里會判 斷 KdDebuggerEnable 是否為 TRUE , 若為 TRUE 則 調(diào)用 KdPollBreakIn 判斷是否有 來自內(nèi)核調(diào)試器 的包含中斷信 息的包,若有則調(diào)用 DbgBreakPointWithStatus ,執(zhí)行一個(gè) int 0x3指令,在異常 處理流程進(jìn)入了 KdpTrace 后將根據(jù)處理不同

19、 向內(nèi)核 調(diào)試器發(fā)包并 無限循環(huán)等待內(nèi)核調(diào)試的回應(yīng)。 現(xiàn)在能理解為什么在 WinDBG 里中斷系統(tǒng)后 堆?;厮菘梢砸来伟l(fā)現(xiàn)KeUpdateSystemTime->RtlpBreakWithStatusInstruction, 系統(tǒng)停在了 int 0x3指令上 (其實(shí) int 0x3已經(jīng)執(zhí)行過了,只不過 Eip 被減 了 1而已 ,實(shí)際 已經(jīng)進(jìn) 入 KiDispatchException->KdpTrap,將控制權(quán)交給了內(nèi)核調(diào) 試器。 系統(tǒng)與調(diào) 試器交互的方法除了 int 0x3外 , 還有 DbgPrint 、 DbgPrompt 、 加載和卸 載 symbols , 它們共同通過

20、調(diào)用 DebugService 獲得服務(wù)。NTSTATUS DebugService(ULONG ServiceClass,PVOID Arg1,PVOID Arg2NTSTATUS Status;_asm mov eax, ServiceClassmov ecx, Arg1mov edx, Arg2int 0x2dint 0x3mov Status, eaxreturn Status;ServiceClass 可以是 BEAKPOINT_PRINT(0x1、BREAKPOINT_PROMPT(0x2、 BREAKPOINT_LOAD_SYMBOLS(0x3、 BREAKPOINT_UNLOA

21、D_SYMBOLS(0x4。為什么后面要跟 個(gè) int 0x3, M$的說法 是為了 和 int 0x3共享代碼 (我沒弄明白啥意思 -_-,因 為 int 0x2d的陷 阱處理程序是 做些處理后跳到 int 0x3的陷阱 處理程序中繼續(xù)處理。但事 實(shí)上對這 個(gè) int 0x3指令并沒有任何處理,僅 僅是把 Eip 加 1跳過它。所 以這個(gè) int 0x3可以換成任何字節(jié)。int 0x2d和 int 0x3生成的異常 記錄結(jié)(EXCEPTION_RECORDExceptionRecord.ExceptionCode都是STATUS_BREAKPOINT(0x80000003,不同是 int 0

22、x2d產(chǎn)生的異常的 ExceptionRecord.NumberParameters>0且 ExceptionRecord.ExceptionInformation 對應(yīng)相應(yīng)的 ServiceClass 比如 BREAKPOINT_PRINT等。事實(shí) 上,在內(nèi)核調(diào)試器被掛 接后,處理 DbgPrint 等 發(fā)送字符給內(nèi) 核調(diào)試器不再是通過 int 0x2d陷阱服務(wù),而 是直接發(fā)包。用 M$的話說 , 這樣更安全 , 因?yàn)椴挥谜{(diào)用 KdEnterDebugger 和 KdExitDebugger 。 最后說一 下被調(diào)試系統(tǒng)和內(nèi)核調(diào)試器之間 的通信。被調(diào)試系統(tǒng)和內(nèi)核 調(diào)試器之間通 過串口發(fā)數(shù)

23、據(jù)包進(jìn)行通信 , Com1的 IO 端口地 址為 0x3f8, Com2的 IO 端口地址為 0x2f8。在被調(diào)試系 統(tǒng)準(zhǔn)備要向內(nèi)核調(diào)試器發(fā)包之 前先會 調(diào)用 KdEnterDebugger 暫停其它處理器的運(yùn)行 并獲取 Com 端口自旋鎖 (當(dāng) 然,這都是對多處理器 而言的 ,并設(shè)置端口標(biāo)志 為保存狀態(tài)。發(fā)包結(jié)束后 調(diào)用 KdExitDebugger 恢復(fù)。每個(gè)包就象網(wǎng)絡(luò) 上的數(shù)據(jù)包一樣,包含包頭和 具體內(nèi)容。包 頭的格式如下:typedef struct _KD_PACKET ULONG PacketLeader;USHORT PacketType;USHORT ByteCount;ULO

24、NG PacketId;ULONG Checksum; KD_PACKET, *PKD_PACKET;PacketLeader 是四個(gè)相同字節(jié)的 標(biāo)識符標(biāo)識發(fā)來的包,一般的 包是 0x30303030, 控制包是 0x69696969, 中斷被調(diào)試系統(tǒng)的包是 0x62626262。 每次讀一個(gè)字 節(jié),連續(xù)讀 4次來識別出包。中 斷系統(tǒng)的包很特殊,包里數(shù) 據(jù)只有 0x62626262。包標(biāo)識符后是包的大 小、類型、包 ID 、檢測碼等,包 頭后面就是跟 具體的數(shù)據(jù)。這點(diǎn)和網(wǎng)絡(luò)上傳輸 的包很相似。還有一些相似 的地方比如每 發(fā)一個(gè)包給調(diào)試器都會收到一 個(gè) ACK 答復(fù)包,以確定調(diào)試器 是否收到。若

25、收到的是一 個(gè) RESEND 包或者很 長時(shí)間沒收到回應(yīng),則會再發(fā) 一次。對于向調(diào)試器發(fā)送輸 出字符串、報(bào)告 SYMBOL 情況等 的包都是一接收 到 ACK 包就立 刻返回,系統(tǒng)恢復(fù)執(zhí)行,系統(tǒng)的表現(xiàn)就是會卡那么短短一下 。 只有報(bào)告狀態(tài) 的包才會等待內(nèi)核調(diào)試器的每個(gè) 控制包并完成對應(yīng)功能,直 到發(fā)來的包包 含繼續(xù)執(zhí)行的命令為止。無論發(fā) 包還是收包,都會在包的末 尾加一 個(gè) 0xaa ,表示結(jié)束。現(xiàn)在我們 用幾個(gè)例子來看看調(diào)試流程。記得我以 前問過 jiurl 為什么 WinDBG 的單步那么慢 (相對 softICE , 他居然說沒覺 得慢 ?*$&$(&(&(我 f

26、t ?,F(xiàn)在可 以理解為什么 WinDBG 的單步和從操 作系統(tǒng)正常執(zhí)行中斷下來為什么 那么慢了。單步慢是因?yàn)槊?單步一次除了 必要的處理外,還得從串行收發(fā) 包,怎么能不慢。中斷系統(tǒng) 慢是因?yàn)橹挥?等到時(shí)鐘中斷發(fā)生執(zhí)行到 KeUpdateSystemTime 后被調(diào)試系統(tǒng)才會接受來 自 WinDBG 的中斷 包?,F(xiàn)在我們研究一下為什么在 KiDispatchException 里不能下斷點(diǎn)卻可以用單步跟 蹤KiDispatchException 的原因。 如果在 KiDispatchException 中某處下了斷 點(diǎn),執(zhí)行到 斷點(diǎn)時(shí)系統(tǒng)發(fā)生異常又重新回 到 KiDispatchExceptio

27、n 處 , 再執(zhí) 行到 int 0x3,如此往復(fù)造成了死循 環(huán),無法不能恢復(fù)原來被斷 點(diǎn) int 0x3所修改的代碼 。但對于 int 0x1,因?yàn)樗囊鹗且?為 EFLAG 寄存中 TF 位 被置位 , 并且每次都自動(dòng)被復(fù) 位,所以系統(tǒng)可以被繼續(xù)執(zhí)行而 不會死循環(huán)。 現(xiàn)在我們知道 了內(nèi)部機(jī)制, 我 們就可以調(diào)用 KdXXX 函數(shù)實(shí)現(xiàn)一個(gè)類似 WinDBG 之類的內(nèi)核調(diào) 試器, 甚至可以替換 KiDebugRoutine(KdpTrap為自己的函數(shù) 來自己實(shí)現(xiàn)一 個(gè)功能更強(qiáng)大的調(diào)試器,呵呵。SoftICESoftICE 的原理 和 WinDBG 完全不 一樣。它通過替換正常系統(tǒng)中 的中斷 處

28、理程序來獲 得系統(tǒng)的控制權(quán),也正因?yàn)檫@樣 它才能夠?qū)崿F(xiàn)單機(jī)調(diào)試。它 的功能實(shí)現(xiàn)方 法很底層,很少依賴與 windows 給的接口函數(shù),大部分功能 的實(shí)現(xiàn)都是 靠 IO 端口讀寫等 來完成的。SoftICE 替換 了 IDT 表中以下的中斷 (陷阱 處理 程序:0x1:單步陷阱處理程 序0x2: NMI不可屏蔽中斷0x3:調(diào)試陷阱處理程 序0x6:無效操作碼陷阱 處理程序0xb :段不存在陷阱處 理程序0xc :堆棧錯(cuò)誤陷阱處 理程序0xd :一般保護(hù)性錯(cuò)誤 陷阱處理程序0xe :頁面錯(cuò)誤陷阱處 理程序0x2d :調(diào)試服務(wù)陷阱處理程序0x2e :系統(tǒng)服務(wù)陷阱處理程序0x31:8042鍵盤控制器中

29、斷處 理程序0x33:串口 2(Com2中斷處理程序0x34:串口 1(Com1中斷處理程序0x37:并口中斷處理程序0x3c :PS/2鼠標(biāo)中斷處理程序0x41:未使用(這是在 PIC 系統(tǒng)上更換 的中斷。如果是 APIC 系統(tǒng)的話更換的中斷號 有不同,但同 樣是更換這些中斷處理程序 其中關(guān)鍵 是替換了 0x3 調(diào)試陷 阱處理程序和 0x31 i8042鍵盤中斷處理 驅(qū)動(dòng)程序 (鍵盤是由 i8042芯 片控制的 , SoftICE 從這兩個(gè) 地方獲取系統(tǒng)的 控制權(quán)。啟 動(dòng) softICE 服務(wù)后 SoftICE 除了更換 了 IDT 里的處理程序,還有幾 點(diǎn)重要的,一 是 HOOK 了 i8

30、042prt.sys 里 的 READ_PORT_UCHAR函數(shù),因?yàn)?在對 0x60端口讀后,會改 變 0x64端口對應(yīng)控 制寄存器的狀態(tài)。所以在 SoftICE 的鍵盤中斷控 制程序讀了 0x60端口后并返回控制權(quán)給正常 的鍵盤 中斷控制程序 后,不要讓它再讀一次。還有就 是把物理內(nèi)存前 1MB 的地址 空間通過調(diào) 用 MmMapIoSpace 映射到虛擬的地址空間里,里 面包括顯存物理 地址,以后重 畫屏幕就通過修改映射到虛擬地 址空間的這段顯存內(nèi)容就行 了。如果顯示 模式是彩色模式,那么顯存起始地址 是 0xb8000, CRT 索引寄 存器端 口 0x3d4, CRT 數(shù)據(jù)寄 存器端

31、口 0x3d5。如果顯示模式是單色 模式, 那么顯存起始 地址是 0xb0000, CRT 索引寄存器端口 0x3b4, CRT 數(shù)據(jù)寄存 器端口 0x3b5。 首先寫索引 寄存器選擇要進(jìn)行設(shè)置的顯示控 制內(nèi)部寄存器之 一 (r0-r17, 然后將參數(shù)寫到其數(shù)據(jù)寄存器端 口。i8042鍵盤控制器 中斷控制驅(qū)動(dòng)程序在每按下一 個(gè)鍵和彈起一個(gè)鍵都 會被觸發(fā)。 SoftICE 在 HOOK 了正常的鍵盤中 斷控制程序獲得系統(tǒng)控制權(quán)后 , 首先從 0x60端口讀出按下鍵的 掃描碼然后向 0x20端口發(fā)送通用 EOI(0x20表示中斷已結(jié) 束,如果沒有按下激活熱鍵 (ctrl+d,則返回正常鍵盤中斷 處

32、理程序。如果是按下熱鍵則會判斷控制臺 (就是那個(gè)等待 輸入命令的顯示 代碼的黑色屏 幕 是否被激活 ,未被激活的話則先激活。然后 設(shè)置 IRQ1鍵 盤中斷的優(yōu)先 級為最高,同時(shí)設(shè)置兩 個(gè) 8259A 中斷控制器里的中斷屏蔽寄 存器 (向 0x21和 0xa1發(fā)中斷 掩碼, 要屏蔽哪個(gè) 中斷就把哪一位設(shè)為 1 , 只 允許 IRQ1(鍵盤中斷 、 IRQ2(中斷控制器 2級聯(lián)中斷 ,因?yàn)?PS/2鼠 標(biāo)中斷 是歸 8259A-2中斷控制器管的,只有開 放 IRQ2才能響應(yīng)來 自 8259A-2管理 的中斷 、 IRQ12(PS/2鼠標(biāo)中斷,如果有的話 ,使系統(tǒng)這時(shí)只響應(yīng) 這 3個(gè) 中斷。新的鍵 盤和鼠標(biāo)中斷處理程序會建立一 個(gè)緩沖區(qū),保存一定數(shù)量的 輸入掃描信息 。當(dāng)前面的工作都完成后會進(jìn)入 一段循環(huán)代碼,負(fù)責(zé)處理鍵 盤和鼠標(biāo)輸入 的掃描碼緩沖區(qū),同時(shí)不斷地更 新顯存的映射地址緩沖區(qū)重 畫屏幕 (這

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論