当前位置:主页 > 查看内容

防止 Windows 上的内存检查

发布时间:2021-06-19 00:00| 位朋友查看

简介:什么,哪里,WTF? 像往常一样,我的反调试相关帖子,一切都从微软没有记录的一点无害标志开始。或者至少我是这么认为的。 这次的主要攻击者是 NtMapViewOfSection ,一个可以将段对象映射到给定进程的地址空间的系统调用,主要用于实现共享内存和内存映射文……

什么,哪里,WTF?

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

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

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 标头中搜索已知常量,我们可以恢复大多数有效标志值背后的含义。

/* 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是一个已知的标志,所以我开始深入挖掘。在同一个函数中,我们还可以发现标志的作用及其主要限制。

// --- 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是一个很大的函数,我不认为一个简短的伪代码片段可以做到公正)

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

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

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

最小示例

// 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;
}

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

结论

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


本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:数据挖掘之聚类分析总结(建议收藏) 下一篇:没有了

推荐图文

  • 周排行
  • 月排行
  • 总排行

随机推荐