Hells Gate
type
status
date
slug
summary
tags
category
icon
password
简介
也就是地狱之门,涉及到的前置知识是PEB。
原理就是从内存里的
ntdll
中读取到的系统调用号进行系统直接调用来绕过敏感API函数的hook。主要来应对 对 Ring3 API 的 HOOK,不同版本的 Windows Nt*函数的系统调用号不同,。前置知识
PEB
可以在 x86 进程的线程环境块(TEB
)中的 fs:[0x30] 以及 x64 进程的 GS:[0x60] 中找到。这里就涉及到了两个API
看名称也可以看出来fs和gs嘛
可以看见TEB结构体里有PEB
先获得TEB、PEB的地址:
r $teb
,r $peb
PEB里一个属性
Ldr
指向了_PEB_LDR_DATA
结构,这个结构里就存储着所需的信息InLoadOrderModuleList
: 指的是模块加载的顺序 InMemoryOrderModuleList
: 指的是在内存的排列顺序 InInitializationOrderModuleLists
: 指的是模块初始化装载顺序那么到底用哪个,差别是什么可以在参考链接里的第一个先知文章里找到答案
双向链表的头部包含进程的加载模块。链表的每一个都是指向
LDR_DATA_TABLE_ENTRY
结构的指针所以
InMemoryOrderModuleList
里的Flink
的地址,指向了一个LDR_DATA_TABLE_ENTRY
Flink总是指向下一个
_LDR_DATA_TABLE_ENTRY
结构对应加载顺序的Flink
指针我们所需的就是
_LDR_DATA_TABLE_ENTRY->Flink.Flink
这个地址如果是
_LDR_DATA_TABLE_ENTRY->Flink
地址,就是我们第一个的模块记住0x0000014d`0a0223c0,下一个就用它
然后再记0x0000014d`0a0229e0,下一个用它
就这样可以循环下去
可以查看下dll载入内存的顺序
上面用到的-0x10是啥嘞,就是为了对齐。
这个结构如果是x86的就是8个字节,x64的就是16个字节
使用
InMemoryOrderModuleList
来查找我们要对齐,对齐方式就是-16个字节
如果不进行对齐的话
可以看见两图 明显不一样
实现一个遍历ntdll.dll里所有导出函数的代码,直接拿的cRIspr师傅的,然后我改了一下。
先定义了一个
LDR_MODULE
的结构体,存放_LDR_DATA_TABLE_ENTRY
因为是直接从内存中读取的嘛,所以也不需要搞偏移
地狱之门
前置知识过完了,就开始解读地狱之门的代码了
代码里先定义了俩结构体
然后又定义了几个函数原型
extern 定义了俩函数,是存放在
hellsgate.asm
里的HellsGate
:用来设置调用号HellDescent
:用来模拟系统调用进行调用然后进入到main方法,定义了TEB,又从TEB里找到了PEB,再解析导出表,进行判断
接下来就是定义上面结构体里,给它Api的Hash,Api的Hash就是
djb2
函数生成的直接测试下是不是
djb2
生成的然后就得重点看下
GetVxTableEntry
函数,因为这步就是取Syscall Number的三个参数
pModuleBase
:ntdll的地址pImageExportDirectory
:导出表pVxTableEntry
:需要找到函数的_VX_TABLE_ENTRY
结构先定位了函数名称表地址,函数地址表的地址,函数序号表的地址
然后遍历导出表,根据API的Hash取到对应的API
然后把地址 存到那个结构里
接着判断了下所在位置
其实这里 这样看 更清楚
这里的if其实就是为了判断
然后判断成功了,就左移搞一个0地址,与本来的syscall number进行或运算
最后就赋值了
_VX_TABLE_ENTRY
结构里的wSystemCall
main函数里的几个
GetVxTableEntry
就是取Syscall Number
最后调用了Payload,就是执行我们所需要的API。把那个大结构体传过去
这里面就是设置调用号,然后进行系统调用
最后运行下 尝试效果