前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >防止 Windows 上的内存检查

防止 Windows 上的内存检查

原创
作者头像
franket
发布于 2021-06-16 03:56:16
发布于 2021-06-16 03:56:16
4.3K0
举报
文章被收录于专栏:技术杂记技术杂记

什么,哪里,WTF?

像往常一样,我的反调试相关帖子,一切都从微软没有记录的一点无害标志开始。或者至少我是这么认为的。

这次的主要攻击者是NtMapViewOfSection,一个可以将段对象映射到给定进程的地址空间的系统调用,主要用于实现共享内存和内存映射文件(Win32 API 将是MapViewOfFile)。

代码语言:txt
AI代码解释
复制
NTSTATUS NtMapViewOfSection(
  HANDLE          SectionHandle,
  HANDLE          ProcessHandle,
  PVOID           *BaseAddress,
  ULONG_PTR       ZeroBits,
  SIZE_T          CommitSize,
  PLARGE_INTEGER  SectionOffset,
  PSIZE_T         ViewSize,
  SECTION_INHERIT InheritDisposition,
  ULONG           AllocationType,
  ULONG           Win32Protect);

通过在ntoskrnl's 中进行一些挖掘MiMapViewOfSection并在 Windows 标头中搜索已知常量,我们可以恢复大多数有效标志值背后的含义。

代码语言:txt
AI代码解释
复制
/* Valid values for AllocationType */
MEM_RESERVE                0x00002000
SEC_PARTITION_OWNER_HANDLE 0x00040000
MEM_TOPDOWN                0x00100000
SEC_NO_CHANGE              0x00400000
SEC_FILE                   0x00800000
MEM_LARGE_PAGES            0x20000000
SEC_WRITECOMBINE           0x40000000

最初我失败了ctrl+f并且没有意识到这0x2000是一个已知的标志,所以我开始深入挖掘。在同一个函数中,我们还可以发现标志的作用及其主要限制。

代码语言:txt
AI代码解释
复制
// --- MAIN FUNCTIONALITY ---
if (SectionOffset + ViewSize > SectionObject->SizeOfSection &&
    !(AllocationAttributes & 0x2000))
    return STATUS_INVALID_VIEW_SIZE;

// --- LIMITATIONS ---
// Image sections are not allowed
if ((AllocationAttributes & 0x2000) &&
    SectionObject->u.Flags.Image)
    return STATUS_INVALID_PARAMETER;

// Section must have been created with one of these 2 protection values
if ((AllocationAttributes & 0x2000) &&
    !(SectionObject->InitialPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
    return STATUS_SECTION_PROTECTION;

// Physical memory sections are not allowed
if ((Params->AllocationAttributes & 0x20002000) &&
    SectionObject->u.Flags.PhysicalMemory)
    return STATUS_INVALID_PARAMETER;

现在,这听起来像是一个沼泽标准MEM_RESERVE,您也可以VirtualAlloc(MEM_RESERVE)随心所欲,但是与此内存交互的 API 会以不同的方式对待它。

你可能会问有多大不同?好吧,在错误地将标志识别为未记录后,我继续尝试创建我可能创建的最大部分。一切都很顺利,直到我打开ProcessHacker内存视图。PC 几乎无法使用至少一分钟,此后黑客也有一段时间没有响应。随后的运行似乎没有抓住了整个系统但是它仍然采取长达4分钟NtQueryVirtualMemory调用返回。

我想你可以像鲍勃·罗斯所说的那样把这称为快乐的小事故。

原因

由于我很懒,所以我决定使用Windows Performance Recorder而不是潜入和倒退。这是一个使用 ETW 跟踪的漂亮工具,可以让您深入了解系统上发生的事情。然后可以在Windows 性能分析器中查看记录的跟踪。

这并没有说太多,但至少我们知道在哪里看。

在花了更多时间盯着每个人最喜欢的反编译器中的代码之后,它变得更加清楚发生了什么。我敢打赌,它会遍历给定内存范围的每个页表条目。而且因为我们一次处理数 TB 的数据,所以迭代次数超过 10 亿次。(MiQueryAddressState是一个很大的函数,我不认为一个简短的伪代码片段可以做到公正)

从我的测试来看,视图大小和所用时间之间的关系是完全线性的,这一事实也加强了这一点。为了进一步验证这个想法,我们还可以做一些快速的餐巾纸数学计算,看看它是否全部加起来:

代码语言:txt
AI代码解释
复制
instructions per second (ips) = 3.8Ghz * ~8
page table entries      (n)   = 12TB / 4096
time taken              (t)   = 3.5 minutes

instruction per page table entry = ips * t / n = ~2000

在我看来,这个数字看起来相当可信,所以,把所有的东西加起来,我会坚持当前的想法。

最小示例

代码语言:txt
AI代码解释
复制
// file handle must be a handle to a non empty file
void* section = nullptr;
auto  status  = NtCreateSection(&section,
                                MAXIMUM_ALLOWED,
                                nullptr,
                                nullptr,
                                PAGE_EXECUTE_READWRITE,
                                SEC_COMMIT,
                                file_handle);
if (!NT_SUCCESS(status))
    return status;

// Personally largest I could get the section was 12TB, but I'm sure people with more
// memory could get it larger.
void* base = nullptr;
for (size_t i = 46;  i > 38; --i) {
    SIZE_T view_size = (1ull << i);
    status           = NtMapViewOfSection(section,
                                          NtCurrentProcess(),
                                          &base,
                                          0,
                                          0x1000,
                                          nullptr,
                                          &view_size,
                                          ViewUnmap,
                                          0x2000, // <- the flag
                                          PAGE_EXECUTE_READWRITE);

    if (NT_SUCCESS(status))
        break;
}

请注意,理想情况下,您需要用这些部分包围代码,因为只有这些部分的保留部分会导致速度变慢。此外,事务也可以是需要非空文件的解决方案,而无需触及任何已存在的内容或创建用户可见的内容。

结论

我认为这是一种伟大而强大的技术,可以让人们分析您的代码。资源使用是合理的,设置它只需要几个系统调用,并且不太可能被意外触发。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
暂无评论
推荐阅读
编辑精选文章
换一批
物理地址读写驱动
没有用MmMapIoSpace,用了映射的方式对物理地址数据进行读写,之前测试MmMapIoSpace在win10较高版本用不了,貌似是不支持了。然后利用映射的方式测试的时候可以在win10下运行。用法和效果如下,加载驱动后,Read.exe用来读取物理地址的数据,限制为0x100字节大小,当然可以通过修改驱动代码来读取任意字节,我这里只是给了个demo;Write.exe则是对指定的物理地址进行写操作,限制了写入的大小为DWORD32,这里也可以通过修改驱动代码进行调整。
战神伽罗
2021/01/06
2.6K2
驱动开发:内核R3与R0内存映射拷贝
在上一篇博文《驱动开发:内核通过PEB得到进程参数》中我们通过使用KeStackAttachProcess附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这次我们将实现一个更加有趣的功能,在某些情况下应用层与内核层需要共享一片内存区域通过这片区域可打通内核与应用层的隔离,此类功能的实现依附于MDL内存映射机制实现。
王瑞MVP
2022/11/18
5950
驱动开发:内核R3与R0内存映射拷贝
ProcessGhosting-一套通用的免杀,自删除解决方案
本文来自项目https://github.com/hasherezade/process_ghosting
JDArmy
2022/06/06
8220
ProcessGhosting-一套通用的免杀,自删除解决方案
免杀必会- 规避杀软的库
在编写恶意软件时,我们时常会用到系统的一些库,库的使用是非常简单,好用的,只需要导入头文件,那么就可以使用相应的api或函数,但是如果用于免杀或者c2,但是在EDR和终端软件横行的现在,不太“好”,下面将是我们在做免杀时或自己开发c2时常用的一些库,有现成调用代码,复制粘贴即可使用。
Gamma实验室
2022/12/01
1.4K0
免杀360火绒defender小型项目改
APC注入函数,不查杀的原因在于典型函数QueueUserAPC暴露,导入表条目过多。
白帽子安全笔记
2024/10/28
1130
免杀360火绒defender小型项目改
3.5 Windows驱动开发:应用层与内核层内存映射
在上一篇博文《内核通过PEB得到进程参数》中我们通过使用KeStackAttachProcess附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这次我们将实现一个更加有趣的功能,在某些情况下应用层与内核层需要共享一片内存区域通过这片区域可打通内核与应用层的隔离,此类功能的实现依附于MDL内存映射机制实现。
王瑞MVP
2023/11/16
7960
3.5 Windows驱动开发:应用层与内核层内存映射
红队技巧--通过内存中PE执行绕过AV
payload选择metasploits的windows/x64/meterpreter_reverse_https,测试AV为Windows Defender,比如以下面的文件为例进行测试。
鸿鹄实验室
2021/04/15
7850
红队技巧--通过内存中PE执行绕过AV
LPC通信撸码笔记
LPC(Local Procedure Call),众所周知,是微软未公开(未文档化)的一种进程间通信方式,不仅可以用在应用层进程之间通信,还可以用在应用层和内核层通信。由于在驱动层并没有一种通用的机制主动发起向应用层的通信(minifilter在建立和应用层的端口通信后,可以主动发起通信),而LPC恰好可以弥补这一不足,所以便一探这陈酒。
franket
2021/08/10
9350
Kernel to User land: APC injection
When running in Kernel mode, it may be necessary to inject code into a User-land process. There are two ways that Asynchronous Procedure Calls (APCs) can be used to accomplish this goal.
战神伽罗
2019/11/07
9760
定长内存池
定长内存池就是一个固定内存申请或释放大小的内存池,其特点是:①性能达到极致。②不需要考虑内存碎片问题。
二肥是只大懒蓝猫
2024/02/06
1530
定长内存池
漏洞分析丨HEVD-0x5.NullPointerDereference[win7x86]
那么,空指针解引用,则就是把NULL页面地址的内容取出来,一般这么操作会报错0xC0000005内存访问违例,但是如果能控制NULL页面,则会使得对空指针解引用有一定的操作空间
极安御信安全研究院
2022/07/15
2610
漏洞分析丨HEVD-0x5.NullPointerDereference[win7x86]
C2基石--syscall模块及amsi bypass
最近读了一些C2的源码,其中shad0w的syscall模块具有很高的移植性,分享给有需要的朋友。
鸿鹄实验室
2021/08/25
7140
DLL 注入
根据MSDN,DLL 是一个库,其中包含可以由多个程序同时使用的代码和数据。 DLL 通常用于将程序模块化为单独的组件,如果模块存在,则每个模块都由主程序加载。这些模块通常扩展主程序的功能。
Khan安全团队
2022/01/16
5K0
免杀技术-使用纤程免杀
B站闲逛,发现了师傅一个优秀的项目,学习整理了一波笔记 原文链接:https://www.bilibili.com/video/BV1LA411B7Mk/?spm_id_from=333.999.0.
hyyrent
2023/03/29
2.2K0
免杀技术-使用纤程免杀
DNSStager v1.0 beta
#DNSStager v1.0 beta 代理在 notepad.exe 中注入检索到的 shellcode 并使用 Early Bird APC #include <stdint.h> #include <inttypes.h> #include <winsock2.h> #include <windns.h> #include <windows.h> #include <stdio.h> #include <tlhelp32.h> typedef struct in6_addr { unio
Khan安全团队
2022/01/24
2410
驱动开发:内核解析PE结构导出表
在笔者的上一篇文章《驱动开发:内核特征码扫描PE代码段》中LyShark带大家通过封装好的LySharkToolsUtilKernelBase函数实现了动态获取内核模块基址,并通过ntimage.h头文件中提供的系列函数解析了指定内核模块的PE节表参数,本章将继续延申这个话题,实现对PE文件导出表的解析任务,导出表无法动态获取,解析导出表则必须读入内核模块到内存才可继续解析,所以我们需要分两步走,首先读入内核磁盘文件到内存,然后再通过ntimage.h中的系列函数解析即可。
王瑞MVP
2023/05/31
3450
驱动开发:内核解析PE结构导出表
D盾防火墙防护绕过-[命令执行限制]
D盾防火墙的“命令执行限制”是通过多种方式来进行限制的,【组件限制】是通过禁止调用wscript.shell、shell.application组件来限制执行命令。
潇湘信安
2022/05/16
2.8K0
D盾防火墙防护绕过-[命令执行限制]
C/C++ 内存反射式DLL注入 [手动映射]
反射式注入 dll ,不会调用 LoadLibrary 这个 API,因此也无法使用 CreateToolhelp32Snapshot 遍历到这个模块。同时也不需要 DLL 留在磁盘上(可以通过网络下发,或加密后存放在磁盘),因此这种注入方式更加隐蔽。
王瑞MVP
2022/12/28
1.2K0
RedTeamTips--PEB隐藏
文章前先给各位师傅拜个早年啦,要过年了,公众号也会停更一段时间,年后回复啦。这篇文章中,我们将介绍如何来隐藏你程序的PEB信息。首先先来了解一下什么是PEB,其全程为Process Envirorment Block ,直译过来就是进程环境信息块,存放进程信息,每个进程都有自己的PEB信息。位于用户地址空间。其结构如下:
鸿鹄实验室
2021/04/01
6420
RedTeamTips--PEB隐藏
驱动开发:内核远程堆分配与销毁
在开始学习内核内存读写篇之前,我们先来实现一个简单的内存分配销毁堆的功能,在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间,一般而言内核中提供了ZwAllocateVirtualMemory这个函数用于专门分配虚拟空间,而与之相对应的则是ZwFreeVirtualMemory此函数则用于销毁堆内存,当我们需要分配内核空间时往往需要切换到对端进程栈上再进行操作,接下来LyShark将从API开始介绍如何运用这两个函数实现内存分配与使用,并以此来作为驱动读写篇的入门知识。
王瑞MVP
2023/05/15
2980
驱动开发:内核远程堆分配与销毁
相关推荐
物理地址读写驱动
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档