Hell's Gate

Hell’s Gate

地狱之门

地狱之门的主要实现是直接系统调用来绕过用户级API的hook,这种技术可用于使用 Cobalt Strike 创建 LSASS 内存转储,同时不接触磁盘并规避 AV/EDR 监控的用户模式的API调用。

直接系统调用

对于windows而言,你可能经历过,一个简单的应用程序崩溃,导致整个系统崩溃,什么出现无法理解的蓝屏情况,而使用windbg也无法找出其存在问题,这是因为操作系统在一个real模式下运行,这意味着处理器在没有应用层次你隔离和保护的模式下运行。由于严重的系统内存损坏,错误的程序或者错误可能导致操作系统完全崩溃,因为对于可以访问或不访问的内存区域没有限制。
而保护模式的更新处理器和操作系统引入了许多保护措施,并且可以并且可以通过使用虚拟内存和特权级别或环将正在运行的程序相互隔离来保护系统免受崩溃。在 Windows 系统中,实际使用了其中两个环。应用程序在 用户模式下运行,相当于 ring 3,关键系统组件如内核和设备驱动程序在 内核模式下运行,对应于 ring 0。

使用这些保护环可以确保应用程序是隔离的,并且不能直接访问在 内核模式下运行的关键内存部分和系统资源。当应用程序需要执行特权系统操作时,处理器首先需要切换到 ring 0 以将执行流程切换到 kernel-mode。这是 系统调用到位的地方。

例如我们将文件保存在磁盘上的这个操作,操作系统需要访问文件系统和设备驱动程序。这些是特权操作,不应允许应用程序本身执行。直接从应用程序访问设备驱动程序可能会导致非常糟糕的事情。因此,进入内核模式之前的最后一个 API 调用负责将 dip 开关拉入内核区域。

因此许多AV的hook都会放在这里,这样他们就可以绕过执行流程,直接进入引擎,来监控可疑行为并拦截API调用
所以我们需要做的就是直接执行系统调用来绕过Windows和Native API,这样就能绕过用户模式的hook

地狱之门的实现

“地狱之门”是@am0nsec 和@RtlMateusz 在本文中创造的一个术语:
Hell’s Gate
其基本概念是通过读取 ntdll.dll 在主机上动态找到系统调用,然后从您自己的自定义实现中调用它们。
将现有代码转换为系统调用时,我们需要做的第一件事是弄清楚底层系统调用是什么

我们需要找到系统调用操作码并将我们的自定义函数指向它们

  1. 首先,我们的函数被分配给一个数组,我们将用从 ntdll 复制的操作码填充该数组。

  2. 调用新的自定义函数,就如同我们在调用普通函数一样
    例如这个新实现的NtOpenProcess函数,这比原来的OpenProcess复杂得多,这样就能规避掉常见的API用户态hook
    NtOpenProcess

Halo’s Gate

光环之门

对于Hell’s Gate而言,最初是一种非常有创意的方法,通过从PEB结构中解析 InMemoryOrderModuleLIst 来获取系统调用编号。通过找到 ntdll.dll 地址(通常是 InMemoryOrderModuleLIst 中的第一个条目),可以通过解析其导出以获取我们需要的必要函数的系统调用编号。

而Halo’s Gate是一种基于Hell’s Gate的新技术,用于解开WINAPI调用
Halo’s Gate 基本上检查被调用的 WINAPI 的第一个字节,如果它们应该是“4c8bd1b8”,那么 WINAPI 没有被钩住,一切正常进行,但是当第一个字节是“e9”时,jmp 汇编指令重定向程序执行到 AV/EDR 检查引擎,因此它被hook了

如果字节是“e9”,Halo’s Gate 解决了这个问题,通过向上或向下检查下一个或上一个系统调用的系统调用,如果它没有被hook,那么我们抓住系统调用并添加 +1 字节,因为它们都是有序的。

Tartarus’ Gate

光环之门的进化

Halo’s Gate并也不是万能的,因为并不是所有EDR都以相同的方式连接,所有我们必须绕过,并将其优化,在EDR中,很显然,它以字节“4c8bd1e9”开头
当WINAPI调用被挂起时
所以我们需要增加一个检查,检查第四个字节是否是e9,如果是,那么它将按照Halo’s Gate解开来绕过EDR
项目地址

Return Gate

返程门

地狱之门带你下地狱,返程之门带sysid回家

对于绝大多数的直接系统调用的项目而言,其核心操作可以分为两部分

  1. 绕过EDR监控获取sysid
  2. 使用sysid绕过EDR监控调用nt api

对于NT API的调用

1
2
3
4
mov     r10,rcx
mov eax,xxh
syscall
ret

因为当其在传入 eax 寄存器的值不同,存储的是系统调用号,即sysid,不同调用号针对syscall 进入内核调用的不同的内核函数。
而对于r3层的edr hook来说,会在api地址的前段加入inline hook
这样在进行API调用的时候就会强制跳转到一个地址,即为EDR的探针。
而这里有一个很好的项目,包括参数欺骗和系统调用检索。他们都滥用EH来破坏EDR
TamperingSyscalls

Return Gate实现

我们已经知道了

  1. EDR hook大部分不会影响到syscall;ret指令。
  2. 在执行syscall指令时sysid位于eax寄存器中。
  3. 使用空参数调用api被记录到的恶意程度较低。
  4. 部分EDR会监控自己的钩子是否被脱钩。
    所以ret 指令会将eax寄存器的值返回。

那么,就有了一个获取sysid的新手段,使用writeprocessmemory将Nt API的syscall指令修改为nop,再使用空参数调用api, 返回值即为该api的sysid,项目用Go实现了一段POC
项目地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
replace:= []byte{0x90,0x90}
raw:= []byte{0x0f,0x05}

//获取地址
apiName := "NtReadVirtualMemory"
nt := syscall.NewLazyDLL("ntdll").NewProc(apiName).Addr()

//替换
if *(*byte)(unsafe.Pointer(nt+18)) == 0x0f &&
*(*byte)(unsafe.Pointer(nt+19)) == 0x05 &&
*(*byte)(unsafe.Pointer(nt+20)) == 0xc3{
windows.WriteProcessMemory(0xffffffffffffffff,nt+18,(*byte)(unsafe.Pointer(&replace[0])),2,nil)
}

//空调用获取sysid
sysid,_,_ := syscall.Syscall(nt,0,0,0,0)
fmt.Printf("sysid: %d\n\n",sysid)

//恢复
windows.WriteProcessMemory(0xffffffffffffffff,nt+18,(*byte)(unsafe.Pointer(&raw[0])),2,nil)

Hell's Gate
https://glacierrrr.online/2022/11/09/Hell's Gate/
作者
Glacier
发布于
2022年11月9日
许可协议