<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          難譯 | windbg 樂趣之道(上)

          共 23107字,需瀏覽 47分鐘

           ·

          2023-04-26 18:34

          前言

          Yarden Shafir 分享了兩篇非常通俗易懂的,關(guān)于 windbg 新引入的調(diào)試數(shù)據(jù)模型的文章。鏈接如下:

          part1:https://medium.com/@yardenshafir2/windbg-the-fun-way-part-1-2e4978791f9b

          part2:https://medium.com/@yardenshafir2/windbg-the-fun-way-part-2-7a904cba5435

          本文是第一部分的譯文。在有道詞典、必應(yīng)詞典、谷歌翻譯的大力幫助下完成,感謝以上翻譯工具,我只是一個(gè)搬運(yùn)工。強(qiáng)烈建議英文好的朋友閱讀原文,因?yàn)樵诜g的過程中不可避免的按我的理解做了調(diào)整。

          說明:

          1. 翻譯已征得原作者同意。
          953ea76229df089b916440c248f636a5.webptranslation-permission
          1. 鴿了太久了,對(duì)不住原作者

          2. 標(biāo)題實(shí)在想不到更好的翻譯了

          3. 作者的 github

          以下是譯文!


          不久前,WinDbg 添加了對(duì)新調(diào)試數(shù)據(jù)模型(debugger data model)的支持,這一變化徹底改變了我們使用 WinDbg 的方式。不再有可怕的 MASM 命令和晦澀的語法。無需再將地址或參數(shù)復(fù)制到記事本以便在后續(xù)命令中使用它們。不用再一遍又一遍地運(yùn)行相同的命令(傳遞不同的地址)來遍歷列表或數(shù)組。

          這是該指南的第一部分,因?yàn)槲艺J(rèn)為實(shí)際上不會(huì)有人從頭到尾讀完長(zhǎng)達(dá) 8000 字的 WinDbg 命令解釋。所以,我準(zhǔn)備了 2 篇 ?4000 字的文章!這樣會(huì)好些,對(duì)吧?

          在第一篇文章中,我們將學(xué)習(xí)如何使用這個(gè)新數(shù)據(jù)模型的基礎(chǔ)知識(shí) —— 使用自定義寄存器和新的內(nèi)置寄存器,遍歷對(duì)象,使用匿名類型來搜索、過濾、自定義對(duì)象。最后,我們將學(xué)習(xí)如何以一種比以前更好、更簡(jiǎn)單的方式解析數(shù)組和列表。

          在這兩篇文章中,我們將學(xué)習(xí)這個(gè)數(shù)據(jù)模型為我們提供的更復(fù)雜、更高級(jí)的方法和特性。現(xiàn)在我們都知道將會(huì)發(fā)生什么,準(zhǔn)備好一杯咖啡,讓我們開始吧!

          這個(gè)數(shù)據(jù)模型,可以在 WinDbg 中通過 dx 命令使用,是一個(gè)極其強(qiáng)大的工具,能夠定義自定義變量、結(jié)構(gòu)體、函數(shù)并使用很多其它新功能。它還允許我們使用 LINQ(一種建立在 SQL 數(shù)據(jù)庫語言之上的自然查詢語言)進(jìn)行查詢和過濾信息。

          這個(gè)數(shù)據(jù)模型已經(jīng)被文檔化了,甚至在 GitHub 上還有使用范例。此外,所有模塊都有對(duì)應(yīng)的文檔,可以在調(diào)試器中通過 dx -v <method> 查看。(您也可以通過運(yùn)行不帶 -vdx <method> 命令獲得相同的文檔 ) :

                
                dx?-v?Debugger.Utility.Collections.FromListEntry
          Debugger.Utility.Collections.FromListEntry?[FromListEntry(ListEntry,?[<ModuleName?|?ModuleObject>],?TypeName,?FieldExpression)?—?Method?which?converts?a?LIST_ENTRY?specified?by?the?‘ListEntry’?parameter?of?types?whose?name?is?specified?by?the?string?‘TypeName’?and?whose?embedded?links?within?that?type?are?accessed?via?an?expression?specified?by?the?string?‘FieldExpression’?into?a?collection?object.?If?an?optional?module?name?or?object?is?specified,?the?type?name?is?looked?up?in?the?context?of?such?module]

          除此之外,還有一些外部文檔,但我覺得有些事情需要進(jìn)一步解釋,并且這個(gè)特性值得更多的關(guān)注。

          譯注:

          debugger data model 文檔鏈接:https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/data-model-cpp-overview)

          使用范例 github 鏈接:https://github.com/microsoft/WinDbg-Samples)

          自定義寄存器(Custom Registers)

          首先,NatVis 允許我們添加自定義寄存器。有點(diǎn)像 MASM 中的 @$t1、@$t2、@$t3 等。只是,現(xiàn)在你可以起任何想要的名字,并且可以指定類型:

                
                dx?@$myString?=?"My?String"
          dx?@$myInt?=?123

          我們可以使用 dx @$vars 來查看所有變量,使用 dx @$vars.Remove("var name") ?來移除某個(gè)變量,或者使用 @$vars.Clear() 清除所有變量。我們還可以使用 dx 來處理更復(fù)雜的結(jié)構(gòu),比如 EPROCESS。您可能知道,公共調(diào)試符號(hào)(public PDBs)中的符號(hào)不包含類型信息。使用舊調(diào)試器,這并不總是一個(gè)問題,因?yàn)樵?MASM 中,反正也沒有類型,我們可以使用 poi 命令對(duì)指針進(jìn)行解引用。

                
                0: kd> dt nt!_EPROCESS poi(nt!PsInitialSystemProcess)
          +0x000 Pcb : _KPROCESS
          +0x2e0 ProcessLock : _EX_PUSH_LOCK
          +0x2e8 UniqueProcessId : (null)
          ...

          但當(dāng)變量不是指針時(shí),事情就變得更混亂了,比如 PsIdleProcess

                
                0:?kd>?dt?nt!_KPROCESS?@@masm(nt!PsIdleProcess)
          ???+0x000?Header???????????:?_DISPATCHER_HEADER
          ???+0x018?ProfileListHead??:?_LIST_ENTRY?[?0x00000048`0411017e?-?0x00000000`00000004?]
          ???+0x028?DirectoryTableBase?:?0xffffb10b`79f08010
          ???+0x030?ThreadListHead???:?_LIST_ENTRY?[?0x00001388`00000000?-?0xfffff801`1b401000?]
          ???+0x040?ProcessLock??????:?0
          ???+0x044?ProcessTimerDelay?:?0
          ???+0x048?DeepFreezeStartTime?:?0xffffe880`00000000
          ???...

          我們必須先使用顯式的 MASM 操作符來獲取 PsIdleProcess 的地址,然后將它當(dāng)作 EPROCESS 顯示出來。通過使用 dx,我們可以更聰明地直接使用 C 風(fēng)格的類型轉(zhuǎn)換對(duì)符號(hào)進(jìn)行強(qiáng)制轉(zhuǎn)換。但是當(dāng)我們嘗試把 nt!Psinitialsystemprocess 轉(zhuǎn)換為一個(gè)指向 EPROCESS 的指針:

                
                dx @$systemProc = (nt!_EPROCESS*)nt!PsInitialSystemProcess
          Error: No type (or void) for object at Address 0xfffff8074ef843a0

          我們得到了一個(gè)錯(cuò)誤。

          就像我提到的那樣,符號(hào)沒有類型。我們不能轉(zhuǎn)換沒有類型的東西。所以我們需要獲取符號(hào)的地址,并轉(zhuǎn)換成一個(gè)指向我們想要的類型的指針(在當(dāng)前示例中,PsInitialSystemProcess 已經(jīng)是一個(gè)指向 EPROCESS 的指針,所以我們需要將其地址轉(zhuǎn)換為一個(gè)指向 EPROCESS 指針的指針)。

                
                dx @$systemProc = *(nt!_EPROCESS**)&nt!PsInitialSystemProcess

          現(xiàn)在,我們有了一個(gè)有類型的變量,我們可以像在 C 中那樣訪問它的字段:

                
                0: kd> dx @$systemProc->ImageFileName

          @$systemProc->ImageFileName [Type: unsigned char [15]]
          [0] : 0x53 [Type: unsigned char]
          [1] : 0x79 [Type: unsigned char]
          [2] : 0x73 [Type: unsigned char]
          [3] : 0x74 [Type: unsigned char]
          [4] : 0x65 [Type: unsigned char]
          [5] : 0x6d [Type: unsigned char]
          [6] : 0x0 [Type: unsigned char]

          我們還可以對(duì)它進(jìn)行類型轉(zhuǎn)換以得到更好的輸出:

                
                dx?(char*)@$systemProc->ImageFileName

          (char*)@$systemProc->ImageFileName??:
          0xffffc10c8e87e710?:?"System"?[Type:?char?*]

          我們還可以使用 ToDisplayString 將它從 char* 轉(zhuǎn)換為 string。我們有兩個(gè)選項(xiàng) —— ToDisplayString("s"),將輸出結(jié)果轉(zhuǎn)換為字符串并將引號(hào)作為字符串的一部分,或者ToDisplayString("sb"),將刪除引號(hào):

                
                dx?((char*)@$systemProc->ImageFileName).ToDisplayString("s")

          ((char*)@$systemProc->ImageFileName).ToDisplayString("s")?:
          "System"
          ????Length???????????:?0x8


          dx?((char*)@$systemProc->ImageFileName).ToDisplayString("sb")

          ((char*)@$systemProc->ImageFileName).ToDisplayString("sb")?:
          System
          ????Length???????????:?0x6

          內(nèi)置寄存器(Built-in Registers)

          這很有趣,但對(duì)于進(jìn)程(和其他一些東西),還有一種更簡(jiǎn)單的方法。WinDbg 中的 NatVis 為我們提供了一些有用的“免費(fèi)”寄存器 —— curframe, curprocess, cursession, curstackcurthread。不難通過它們的名字猜出對(duì)應(yīng)的內(nèi)容,但還是看一看吧:

          @$curframe

          提供有關(guān)當(dāng)前幀的信息。我自己從來沒用過,但它也許有用:

                
                dx?-r1?@$curframe.Attributes

          @$curframe.Attributes????????????????
          ????InstructionOffset?:?0xfffff8074ebda1e1
          ????ReturnOffset?????:?0xfffff80752ad2b61
          ????FrameOffset??????:?0xfffff80751968830
          ????StackOffset??????:?0xfffff80751968838
          ????FuncTableEntry???:?0x0
          ????Virtual??????????:?1
          ????FrameNumber??????:?0x0

          @$curprocess

          一個(gè)包含當(dāng)前進(jìn)程信息的容器。但不是 EPROCESS (盡管包含它)。它包含了關(guān)于當(dāng)前進(jìn)程的易于訪問的信息,比如線程、加載的模塊、句柄等。

                
                dx?@$curprocess

          @$curprocess?????????????????:?System?[Switch?To]
          ????KernelObject?????[Type:?_EPROCESS]
          ????Name?????????????:?System
          ????Id???????????????:?0x4
          ????Handle???????????:?0xf0f0f0f0
          ????Threads?????????
          ????Modules?????????
          ????Environment?????
          ????Devices?????????
          ????Io

          我們不僅可以訪問 EPROCESS(通過 KernelObject ),還可以使用其他字段。例如,我們可以通過 @$curprocess.Io.Handles 訪問進(jìn)程持有的所有句柄。@$curprocess.Io.Handles 會(huì)返回一個(gè)由句柄值索引的句柄數(shù)組:

                
                dx?@$curprocess.Io.Handles

          @$curprocess.Io.Handles????????????????
          ????[0x4]???????????
          ????[0x8]???????????
          ????[0xc]???????????
          ????[0x10]??????????
          ????[0x14]??????????
          ????[0x18]??????????
          ????[0x1c]??????????
          ????[0x20]??????????
          ????[0x24]??????????
          ????[0x28]
          ????...

          System 進(jìn)程有很多句柄,這只是開始的幾個(gè)!讓我們來看看第一個(gè)(我們也可以通過 @$curprocess.Io.Handles[0x4] 來訪問它):

                
                dx?@$curprocess.Io.Handles.First()

          @$curprocess.Io.Handles.First()????????????????
          ????Handle???????????:?0x4
          ????Type?????????????:?Process
          ????GrantedAccess????:?Delete?|?ReadControl?|?WriteDac?|?WriteOwner?|?Synch?|?Terminate?|?CreateThread?|?VMOp?|?VMRead?|?VMWrite?|?DupHandle?|?CreateProcess?|?SetQuota?|?SetInfo?|?QueryInfo?|?SetPort
          ????Object???????????[Type:?_OBJECT_HEADER]

          我們可以看到句柄,句柄對(duì)應(yīng)的對(duì)象類型,它被授予的訪問權(quán)限,甚至有一個(gè)指向?qū)ο蟊旧淼闹羔槪ɑ蛘吒鼫?zhǔn)確地說,它指向的是對(duì)象頭)!

          這個(gè)寄存器還有很多東西可以探索,我鼓勵(lì)您去調(diào)查它們,但我不會(huì)全部展示。

          順便說一下,我是否提過 dx 允許 tab 補(bǔ)全?

          @$cursession

          顧名思義,這個(gè)寄存器為我們提供關(guān)于當(dāng)前調(diào)試會(huì)話的信息:

                
                dx?@$cursession

          @$cursession?????????????????:?Remote?KD:?KdSrv:Server=@{<Local>},Trans=@{NET:Port=55556,Key=1.2.3.4,Target=192.168.251.21}
          ????Processes???????
          ????Id???????????????:?0
          ????Devices?????????
          ????Attributes

          因此,我們可以獲得關(guān)于調(diào)試會(huì)話的信息,這總是很有趣。但是還可以找到更多有用的東西,比如 Processes 字段,它是所有進(jìn)程的數(shù)組,由 PID 索引。讓我們選一個(gè)吧:

                
                dx?@$cursession.Processes[0x1d8]

          @$cursession.Processes[0x1d8]?????????????????:?smss.exe?[Switch?To]
          ????KernelObject?????[Type:?_EPROCESS]
          ????Name?????????????:?smss.exe
          ????Id???????????????:?0x1d8
          ????Handle???????????:?0xf0f0f0f0
          ????Threads?????????
          ????Modules?????????
          ????Environment?????
          ????Devices?????????
          ????Io

          現(xiàn)在我們可以獲得每個(gè)進(jìn)程的全部有用信息!我們還可以通過過濾來搜索進(jìn)程(例如,通過進(jìn)程名、加載到進(jìn)程中的特定模塊、命令行中的字符串等等)。我稍后再解釋這些。

          @$curstack

          這個(gè)寄存器只包含一個(gè)字段 —— 幀,它以一種易于處理的方式向我們顯示當(dāng)前調(diào)用棧:

                
                dx?@$curstack.Frames

          @$curstack.Frames????????????????
          ????[0x0]????????:?nt!DbgBreakPointWithStatus?+?0x1?[Switch?To]
          ????[0x1]????????:?kdnic!TXTransmitQueuedSends?+?0x125?[Switch?To]
          ????[0x2]????????:?kdnic!TXSendCompleteDpc?+?0x14d?[Switch?To]
          ????[0x3]????????:?nt!KiProcessExpiredTimerList?+?0x169?[Switch?To]
          ????[0x4]????????:?nt!KiRetireDpcList?+?0x4e9?[Switch?To]
          ????[0x5]????????:?nt!KiIdleLoop?+?0x7e?[Switch?To]

          @$curthread

          為我們提供當(dāng)前線程的相關(guān)信息,就像 @$curprocess

                
                dx?@$curthread

          @$curthread?????????????????:?nt!DbgBreakPointWithStatus+0x1?(fffff807`4ebda1e1)??[Switch?To]
          ????KernelObject?????[Type:?_ETHREAD]
          ????Id???????????????:?0x0
          ????Stack???????????
          ????Registers???????
          ????Environment

          KernelObject 字段包含了 ETHREAD, ?Environment 字段包含了 TEB,除此之外,還包括線程 ID、調(diào)用棧和寄存器。

                
                dx?@$curthread.Registers

          @$curthread.Registers????????????????
          ????User????????????
          ????Kernel??????????
          ????SIMD????????????
          ????FloatingPoint

          寄存器被方便地分為用戶寄存器、內(nèi)核寄存器、SIMD 寄存器和浮點(diǎn)寄存器,我們可以分別查看它們:

                
                dx?-r1?@$curthread.Registers.Kernel

          @$curthread.Registers.Kernel
          ????cr0??????????????:?0x80050033
          ????cr2??????????????:?0x207b8f7abbe
          ????cr3??????????????:?0x6d4002
          ????cr4??????????????:?0x370678
          ????cr8??????????????:?0xf
          ????gdtr?????????????:?0xffff9d815ffdbfb0
          ????gdtl?????????????:?0x57
          ????idtr?????????????:?0xffff9d815ffd9000
          ????idtl?????????????:?0xfff
          ????tr???????????????:?0x40
          ????ldtr?????????????:?0x0
          ????kmxcsr???????????:?0x1f80
          ????kdr0?????????????:?0x0
          ????kdr1?????????????:?0x0
          ????kdr2?????????????:?0x0
          ????kdr3?????????????:?0x0
          ????kdr6?????????????:?0xfffe0ff0
          ????kdr7?????????????:?0x400
          搜索和過濾(Searching and Filtering)

          我們?cè)谇懊婧?jiǎn)要提到過,NatVis 允許我們做一些非常有用的操作 —— 通過類似 SQL 中的 Select、Where、Orderderby 及其它方法對(duì)信息進(jìn)行查找、過濾和排序。

          例如,讓我們嘗試找到所有沒啟用 high entropy ASLR 的進(jìn)程。該信息存儲(chǔ)在 EPROCESS->MitigationFlags 字段中,HighEntropyASLREnabled 的值是 0x20 (所有值都可以在這里和公共符號(hào)中找到)。

          首先,我們聲明一個(gè)值為 0x20 的新寄存器,這只是為了使代碼更具可讀性:

                
                0:?kd>?dx?@$highEntropyAslr?=?0x20

          @$highEntropyAslr?=?0x20?:?32

          然后創(chuàng)建查詢來遍歷所有進(jìn)程,只選擇那些沒有設(shè)置 HighEntropyASLREnabled 標(biāo)志位的進(jìn)程:

                
                dx?-r1?@$cursession.Processes.Where(p?=>?(p.KernelObject.MitigationFlags?&?@$highEntropyAslr)?==?0)

          @$cursession.Processes.Where(p?=>?(p.KernelObject.MitigationFlags?&?@$highEntropyAslr)?==?0)????????????????
          ????[0x910]??????????:?spoolsv.exe?[Switch?To]
          ????[0xb40]??????????:?IpOverUsbSvc.exe?[Switch?To]
          ????[0x1610]?????????:?explorer.exe?[Switch?To]
          ????[0x1d8c]?????????:?OneDrive.exe?[Switch?To]

          或者我們可以直接檢查 MitigationFlagsValues 并獲得相同的結(jié)果:

                
                dx?-r1?@$cursession.Processes.Where(p?=>?(p.KernelObject.MitigationFlagsValues.HighEntropyASLREnabled?==?0))

          @$cursession.Processes.Where(p?=>?(p.KernelObject.MitigationFlagsValues.HighEntropyASLREnabled?==?0))
          ????[0x910]??????????:?spoolsv.exe?[Switch?To]
          ????[0xb40]??????????:?IpOverUsbSvc.exe?[Switch?To]
          ????[0x1610]?????????:?explorer.exe?[Switch?To]
          ????[0x1d8c]?????????:?OneDrive.exe?[Switch?To]

          我們還可以使用 Select() 來顯示正在遍歷的對(duì)象的某些特定屬性。這里我們只查看每個(gè)進(jìn)程的線程數(shù):

                
                dx?@$cursession.Processes.Select(p?=>?p.Threads.Count())

          @$cursession.Processes.Select(p?=>?p.Threads.Count())????????????????
          ????[0x0]????????????:?0x6
          ????[0x4]????????????:?0xeb
          ????[0x78]???????????:?0x4
          ????[0x1d8]??????????:?0x5
          ????[0x244]??????????:?0xe
          ????[0x294]??????????:?0x8
          ????[0x2a0]??????????:?0x10
          ????[0x2f8]??????????:?0x9
          ????[0x328]??????????:?0xa
          ????[0x33c]??????????:?0xd
          ????[0x3a8]??????????:?0x2c
          ????[0x3c0]??????????:?0x8
          ????[0x3c8]??????????:?0x8
          ????[0x204]??????????:?0x15
          ????[0x300]??????????:?0x1d
          ????[0x444]??????????:?0x3f
          ????...

          我們還可以通過在命令末尾加上 ,d 來以十進(jìn)制格式顯示所有內(nèi)容。(b 表示以二進(jìn)制顯示,o 表示以八進(jìn)制顯示,s 表示以字符串顯示):

                
                dx?@$cursession.Processes.Select(p?=>?p.Threads.Count()),?d@$cursession.Processes.Select(p?=>?p.Threads.Count()),?d????????????????
          ????[0]??????????????:?6
          ????[4]??????????????:?235
          ????[120]????????????:?4
          ????[472]????????????:?5
          ????[580]????????????:?14
          ????[660]????????????:?8
          ????[672]????????????:?16
          ????[760]????????????:?9
          ????[808]????????????:?10
          ????[828]????????????:?13
          ????[936]????????????:?44
          ????[960]????????????:?8
          ????[968]????????????:?8
          ????[516]????????????:?21
          ????[768]????????????:?29
          ????[1092]???????????:?63
          ????...

          再看一個(gè)稍微復(fù)雜一點(diǎn)的示例 —— 查看某個(gè)特定進(jìn)程中每個(gè)線程的理想處理器(我隨機(jī)選擇了一個(gè)進(jìn)程,只是為了查看非 System 進(jìn)程的一些信息):

                
                dx?-r1?@$cursession.Processes[0x1b2c].Threads.Select(t?=>?t.Environment.EnvironmentBlock.CurrentIdealProcessor.Number)

          @$cursession.Processes[0x1b2c].Threads.Select(t?=>?t.Environment.EnvironmentBlock.CurrentIdealProcessor.Number)????????????????
          ????[0x1b30]?????????:?0x1?[Type:?unsigned?char]
          ????[0x1b40]?????????:?0x2?[Type:?unsigned?char]
          ????[0x1b4c]?????????:?0x3?[Type:?unsigned?char]
          ????[0x1b50]?????????:?0x4?[Type:?unsigned?char]
          ????[0x1b48]?????????:?0x5?[Type:?unsigned?char]
          ????[0x1b5c]?????????:?0x0?[Type:?unsigned?char]
          ????[0x1b64]?????????:?0x1?[Type:?unsigned?char]

          我們還可以使用 OrderBy 來獲得更好的輸出,例如獲取按字母順序排序的進(jìn)程列表:

                
                dx?-r1?@$cursession.Processes.OrderBy(p?=>?p.Name)

          @$cursession.Processes.OrderBy(p?=>?p.Name)????????????????
          ????[0x1848]?????????:?ApplicationFrameHost.exe?[Switch?To]
          ????[0x0]????????????:?Idle?[Switch?To]
          ????[0xb40]??????????:?IpOverUsbSvc.exe?[Switch?To]
          ????[0x106c]?????????:?LogonUI.exe?[Switch?To]
          ????[0x754]??????????:?MemCompression?[Switch?To]
          ????[0x187c]?????????:?MicrosoftEdge.exe?[Switch?To]
          ????[0x1b94]?????????:?MicrosoftEdgeCP.exe?[Switch?To]
          ????[0x1b7c]?????????:?MicrosoftEdgeSH.exe?[Switch?To]
          ????[0xb98]??????????:?MsMpEng.exe?[Switch?To]
          ????[0x1158]?????????:?NisSrv.exe?[Switch?To]
          ????[0x1d8c]?????????:?OneDrive.exe?[Switch?To]
          ????[0x78]???????????:?Registry?[Switch?To]
          ????[0x1ed0]?????????:?RuntimeBroker.exe?[Switch?To]
          ????...

          如果我們希望按降序排列,可以使用 OrderByDescending。

          但是,如果我們想要查看多個(gè)屬性該怎么辦呢?有辦法。

          匿名類型(Anonymous Types)

          我們可以聲明一個(gè)自定義的類型,它將是未命名的并且只在查詢作用域中有效,語法如下:Select(x => new {var1 = x.A, var2 = x.B,…})。

          我們把它用在前面的示例中。假設(shè)我們想要顯示每個(gè)進(jìn)程的進(jìn)程名和線程數(shù):

                
                dx?@$cursession.Processes.Select(p?=>?new?{Name?=?p.Name,?ThreadCount?=?p.Threads.Count()})

          @$cursession.Processes.Select(p?=>?new?{Name?=?p.Name,?ThreadCount?=?p.Threads.Count()})????????????????
          ????[0x0]???????????
          ????[0x4]???????????
          ????[0x78]??????????
          ????[0x1d8]?????????
          ????[0x244]?????????
          ????[0x294]?????????
          ????[0x2a0]?????????
          ????[0x2f8]?????????
          ????[0x328]
          ????...

          但是現(xiàn)在我們只看到進(jìn)程容器,而不是實(shí)際的信息。為了查看信息本身,我們需要使用 -r2 來多顯示一層。r 后面的數(shù)字表示遞歸層數(shù)。默認(rèn)值是 -r1-r0 將不顯示輸出,-r2 將顯示兩層,以此類推。

                
                dx?-r2?@$cursession.Processes.Select(p?=>?new?{Name?=?p.Name,?ThreadCount?=?p.Threads.Count()})

          @$cursession.Processes.Select(p?=>?new?{Name?=?p.Name,?ThreadCount?=?p.Threads.Count()})????????????????
          ????[0x0]???????????
          ????????Name?????????????:?Idle
          ????????ThreadCount??????:?0x6
          ????[0x4]???????????
          ????????Name?????????????:?System
          ????????ThreadCount??????:?0xeb
          ????[0x78]??????????
          ????????Name?????????????:?Registry
          ????????ThreadCount??????:?0x4
          ????[0x1d8]?????????
          ????????Name?????????????:?smss.exe
          ????????ThreadCount??????:?0x5
          ????[0x244]?????????
          ????????Name?????????????:?csrss.exe
          ????????ThreadCount??????:?0xe
          ????[0x294]?????????
          ????????Name?????????????:?wininit.exe
          ????????ThreadCount??????:?0x8
          ????[0x2a0]?????????
          ????????Name?????????????:?csrss.exe
          ????????ThreadCount??????:?0x10
          ????...

          這看起來已經(jīng)好多了,但是我們可以使用新的表格視圖讓它看起來更好(通過 -g 選項(xiàng)):

                
                dx?-g?@$cursession.Processes.Select(p?=>?new?{Name?=?p.Name,?ThreadCount?=?p.Threads.Count()})
          f2a77f790ea253b81810ae6f62b896d8.webpoutput-of-dx-g-cursession.Processes.Select

          這看起來太棒了。是的,這些標(biāo)題是可點(diǎn)擊的,點(diǎn)擊標(biāo)題會(huì)將表格排序!

          如果我們想看到以十進(jìn)制顯示的 PID 和線程數(shù),我們可以在命令的末尾加上 ,d

                
                dx?-g?@$cursession.Processes.Select(p?=>?new?{Name?=?p.Name,?ThreadCount?=?p.Threads.Count()}),d
          數(shù)組和鏈表(Arrays and Lists)

          dx 為我們提供了一種新的、更簡(jiǎn)單的方法來處理數(shù)組和列表。

          讓我們先來看看數(shù)組,語法是 dx *(TYPE(*)[Size])<pointer to array start>。

          作為示例,我們將轉(zhuǎn)儲(chǔ) PsInvertedFunctionTable 中的內(nèi)容,它的 TableEntry 字段包含了最多容納 256 個(gè)緩存模塊的數(shù)組。

          首先,我們將獲得該符號(hào)的指針,并將其轉(zhuǎn)換為 _INVERTED_FUNCTION_TABLE

                
                dx?@$inverted?=?(nt!_INVERTED_FUNCTION_TABLE*)&nt!PsInvertedFunctionTable

          @$inverted?=?(nt!_INVERTED_FUNCTION_TABLE*)&nt!PsInvertedFunctionTable?????????????????:?0xfffff8074ef9b010?[Type:?_INVERTED_FUNCTION_TABLE?*]
          ????[+0x000]?CurrentSize??????:?0xbe?[Type:?unsigned?long]
          ????[+0x004]?MaximumSize??????:?0x100?[Type:?unsigned?long]
          ????[+0x008]?Epoch????????????:?0x19e?[Type:?unsigned?long]
          ????[+0x00c]?Overflow?????????:?0x0?[Type:?unsigned?char]
          ????[+0x010]?TableEntry???????[Type:?_INVERTED_FUNCTION_TABLE_ENTRY?[256]]

          現(xiàn)在我們可以創(chuàng)建數(shù)組了。不幸的是,數(shù)組的大小必須是靜態(tài)的,不能使用變量,所以我們需要根據(jù) CurrentSize 手動(dòng)輸入(或者將它設(shè)置為 256,這是整個(gè)數(shù)組的大?。?。我們可以用表格視圖很好地顯示它:

                
                dx?-g?@$tableEntry?=?*(nt!_INVERTED_FUNCTION_TABLE_ENTRY(*)[0xbe])@$inverted->TableEntry
          fe44a674e3cd288f2b7704826a802dcf.webpoutput-of-dx-g-tableEntry-_INVERTED_FUNCTION_TABLE_ENTRY

          或者,我們可以使用 Take() 方法來獲得相同的結(jié)果,該方法接收一個(gè)數(shù)字并顯示指定數(shù)量的集合元素:

                
                dx?-g?@$inverted->TableEntry->Take(@$inverted->CurrentSize)

          我們也可以用同樣的方法來查看 UserInvertedFunctionTable (在我們切換到非 System 進(jìn)程的用戶態(tài)空間后),從 nt!KeUserInvertedFunctionTable 開始:

                
                dx?@$inverted?=?*(nt!_INVERTED_FUNCTION_TABLE**)&nt!KeUserInvertedFunctionTable

          @$inverted?=?*(nt!_INVERTED_FUNCTION_TABLE**)&nt!KeUserInvertedFunctionTable?????????????????:?0x7ffa19e3a4d0?[Type:?_INVERTED_FUNCTION_TABLE?*]
          ????[+0x000]?CurrentSize??????:?0x2?[Type:?unsigned?long]
          ????[+0x004]?MaximumSize??????:?0x200?[Type:?unsigned?long]
          ????[+0x008]?Epoch????????????:?0x6?[Type:?unsigned?long]
          ????[+0x00c]?Overflow?????????:?0x0?[Type:?unsigned?char]
          ????[+0x010]?TableEntry???????[Type:?_INVERTED_FUNCTION_TABLE_ENTRY?[256]]
          ????
          dx?-g?@$inverted->TableEntry->Take(@$inverted->CurrentSize)
          7288ee2e72f0ac5575c59a1ed23842db.webpdx-inverted-_INVERTED_FUNCTION_TABLE

          當(dāng)然,我們可以使用 Select()Where() 或者其他函數(shù)來過濾、排序或者選擇特定的字段進(jìn)行輸出,以得到完全滿足我們需求的結(jié)果。

          接下來要處理的是列表 —— Windows 中到處都是鏈表,你可以在任何地方找到它們。進(jìn)程、線程、模塊、DPCsIRPs、還有更多。

          幸運(yùn)的是,新數(shù)據(jù)模型提供了一個(gè)非常有用的方法—— Debugger.Utiilty.Collections.FromListEntry,它接收一個(gè)鏈表頭,鏈表中的對(duì)象類型和類型中包含 LIST_ENTRY 的字段名稱,并返回一個(gè)包含所有列表內(nèi)容的容器。

          讓我們以轉(zhuǎn)儲(chǔ)系統(tǒng)中所有的句柄表為例。我們的起點(diǎn)將是符號(hào) nt!HandleTableListHead,鏈表中的對(duì)象類型是 nt!HANDLE_TABLE ,連接列表的字段是 HandleTableList

                
                dx?-r2?Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead,?"nt!_HANDLE_TABLE",?"HandleTableList")

          Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead,?"nt!_HANDLE_TABLE",?"HandleTableList")????????????????
          ????[0x0]????????????[Type:?_HANDLE_TABLE]
          ????????[+0x000]?NextHandleNeedingPool?:?0x3400?[Type:?unsigned?long]
          ????????[+0x004]?ExtraInfoPages???:?0?[Type:?long]
          ????????[+0x008]?TableCode????????:?0xffff8d8dcfd18001?[Type:?unsigned?__int64]
          ????????[+0x010]?QuotaProcess?????:?0x0?[Type:?_EPROCESS?*]
          ????????[+0x018]?HandleTableList??[Type:?_LIST_ENTRY]
          ????????[+0x028]?UniqueProcessId??:?0x4?[Type:?unsigned?long]
          ????????[+0x02c]?Flags????????????:?0x0?[Type:?unsigned?long]
          ????????[+0x02c?(?0:?0)]?StrictFIFO???????:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?1:?1)]?EnableHandleExceptions?:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?2:?2)]?Rundown??????????:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?3:?3)]?Duplicated???????:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?4:?4)]?RaiseUMExceptionOnInvalidHandleClose?:?0x0?[Type:?unsigned?char]
          ????????[+0x030]?HandleContentionEvent?[Type:?_EX_PUSH_LOCK]
          ????????[+0x038]?HandleTableLock??[Type:?_EX_PUSH_LOCK]
          ????????[+0x040]?FreeLists????????[Type:?_HANDLE_TABLE_FREE_LIST?[1]]
          ????????[+0x040]?ActualEntry??????[Type:?unsigned?char?[32]]
          ????????[+0x060]?DebugInfo????????:?0x0?[Type:?_HANDLE_TRACE_DEBUG_INFO?*]
          ????[0x1]????????????[Type:?_HANDLE_TABLE]
          ????????[+0x000]?NextHandleNeedingPool?:?0x400?[Type:?unsigned?long]
          ????????[+0x004]?ExtraInfoPages???:?0?[Type:?long]
          ????????[+0x008]?TableCode????????:?0xffff8d8dcb651000?[Type:?unsigned?__int64]
          ????????[+0x010]?QuotaProcess?????:?0xffffb90a530e4080?[Type:?_EPROCESS?*]
          ????????[+0x018]?HandleTableList??[Type:?_LIST_ENTRY]
          ????????[+0x028]?UniqueProcessId??:?0x78?[Type:?unsigned?long]
          ????????[+0x02c]?Flags????????????:?0x10?[Type:?unsigned?long]
          ????????[+0x02c?(?0:?0)]?StrictFIFO???????:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?1:?1)]?EnableHandleExceptions?:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?2:?2)]?Rundown??????????:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?3:?3)]?Duplicated???????:?0x0?[Type:?unsigned?char]
          ????????[+0x02c?(?4:?4)]?RaiseUMExceptionOnInvalidHandleClose?:?0x1?[Type:?unsigned?char]
          ????????[+0x030]?HandleContentionEvent?[Type:?_EX_PUSH_LOCK]
          ????????[+0x038]?HandleTableLock??[Type:?_EX_PUSH_LOCK]
          ????????[+0x040]?FreeLists????????[Type:?_HANDLE_TABLE_FREE_LIST?[1]]
          ????????[+0x040]?ActualEntry??????[Type:?unsigned?char?[32]]
          ????????[+0x060]?DebugInfo????????:?0x0?[Type:?_HANDLE_TRACE_DEBUG_INFO?*]
          ????...

          看到 QuotaProcess 字段了嗎?該字段指向當(dāng)前句柄表所屬的進(jìn)程。由于每個(gè)進(jìn)程都有一個(gè)句柄表,這允許我們以一種不為人所知的方式枚舉系統(tǒng)中的所有進(jìn)程。這種方法在過去被 rootkit 用于枚舉進(jìn)程,而不被 EDR 產(chǎn)品檢測(cè)到。因此,要實(shí)現(xiàn)這一點(diǎn),我們只需要從句柄表列表中的每個(gè)條目中選擇 QuotaProcess (通過 Select() 方法)。為了讓輸出結(jié)果更易讀,我們還可以創(chuàng)建一個(gè)包含進(jìn)程名、PIDEPROCESS 指針的匿名容器:

                
                dx?-r2?(Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead,?"nt!_HANDLE_TABLE",?"HandleTableList")).Select(h?=>?new?{?Object?=?h.QuotaProcess,?Name?=?((char*)h.QuotaProcess->ImageFileName).ToDisplayString("s"),?PID?=?(__int64)h.QuotaProcess->UniqueProcessId})

          (Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead,?"nt!_HANDLE_TABLE",?"HandleTableList")).Select(h?=>?new?{?Object?=?h.QuotaProcess,?Name?=?((char*)h.QuotaProcess->ImageFileName).ToDisplayString("s"),?PID?=?(__int64)h.QuotaProcess->UniqueProcessId})

          [0x0]????????????:?Unspecified?error?(0x80004005)
          [0x1]
          ????Object???????????:?0xffffb10b70906080?[Type:?_EPROCESS?*]
          ????Name?????????????:?"Registry"
          ????PID??????????????:?120?[Type:?__int64]
          [0x2]
          ????Object???????????:?0xffffb10b72eba0c0?[Type:?_EPROCESS?*]
          ????Name?????????????:?"smss.exe"
          ????PID??????????????:?584?[Type:?__int64]
          [0x3]
          ????Object???????????:?0xffffb10b76586140?[Type:?_EPROCESS?*]
          ????Name?????????????:?"csrss.exe"
          ????PID??????????????:?696?[Type:?__int64]
          [0x4]
          ????Object???????????:?0xffffb10b77132140?[Type:?_EPROCESS?*]
          ????Name?????????????:?"wininit.exe"
          ????PID??????????????:?772?[Type:?__int64]
          [0x5]
          ????Object???????????:?0xffffb10b770a2080?[Type:?_EPROCESS?*]
          ????Name?????????????:?"csrss.exe"
          ????PID??????????????:?780?[Type:?__int64]
          [0x6]
          ????Object???????????:?0xffffb10b7716d080?[Type:?_EPROCESS?*]
          ????Name?????????????:?"winlogon.exe"
          ????PID??????????????:?852?[Type:?__int64]
          ...

          第一條結(jié)果屬于 System 進(jìn)程,它沒有 QuotaProcess,這就是查詢返回錯(cuò)誤的原因。但對(duì)于數(shù)組中的其他元素,應(yīng)該是完美的。如果我們想讓輸出結(jié)果更漂亮,可以在執(zhí)行 Select() 之前過濾掉 QuotaProcess == 0 的條目:

                
                dx?-r2?(Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead,?“nt!_HANDLE_TABLE”,?“HandleTableList”)).Where(h?=>?h.QuotaProcess?!=?0).Select(h?=>?new?{?Object?=?h.QuotaProcess,?Name?=?((char*)h.QuotaProcess->ImageFileName).ToDisplayString("s"),?PID?=?h.QuotaProcess->UniqueProcessId})

          如前所示,我們也可以在表格視圖中顯示這個(gè)列表,或者使用任何 LINQ 查詢來使輸出滿足我們的需要。

          第一部分到此結(jié)束,但不要擔(dān)心,第二部分就在這里。它包含了全部新奇的 dx 方法,比如一個(gè)新的反匯編器,自定義方法,可以真正工作的條件斷點(diǎn),以及更多。


          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天爽日日爽 | 国产小学生妹在线观看 | 91久久婷婷国产麻豆精品电影.co | 国产卡一卡二精品电影 | 可以看的av |