0%
毅种循环

模块 67 - Syscalls - 重构经典注入

恶意软件开发课程 - Syscalls - 重构经典注入


模块 67 - Syscalls - 重构经典注入#

Syscalls - 重构经典注入#

简介#

在本模块中,我们将使用直接系统调用(Direct Syscalls)重新实现之前讨论过的经典进程注入技术。我们将把所有的 WinAPI 替换为它们对应的系统调用版本:

所需系统调用详解#

1. NtAllocateVirtualMemory#

这是 VirtualAllocEx 的底层版本。

NTSTATUS NtAllocateVirtualMemory(
  IN HANDLE           ProcessHandle,    // 目标进程句柄
  IN OUT PVOID        *BaseAddress,     // 返回分配后的基地址(指针的指针)
  IN ULONG_PTR        ZeroBits,         // 设为 0
  IN OUT PSIZE_T      RegionSize,       // 申请的大小(指针,会被修改)
  IN ULONG            AllocationType,   // MEM_COMMIT | MEM_RESERVE
  IN ULONG            Protect           // 内存保护属性
);
c

💡 初学者提示:引用传递

与 WinAPI 不同,NtAllocateVirtualMemory 要求 BaseAddressRegionSize 都通过地址传递(使用 &)。这是因为系统调用执行完后,可能会修改这些值。例如,即使你只申请 100 字节,系统也会按一页(4096 字节)进行向上取整,并把实际分配的大小填回 RegionSize

2. NtProtectVirtualMemory#

对应 VirtualProtectEx。同样要求 BaseAddressNumberOfBytesToProtect 是引用传递。

3. NtWriteVirtualMemory#

对应 WriteProcessMemory。参数逻辑与 WinAPI 几乎一致。

4. NtCreateThreadEx#

这是 CreateRemoteThread 的底层实现。它非常强大且灵活,但在基础注入中,我们只需将其大部分复杂参数设为 NULL 即可。

实战方案 A:直接获取函数地址 (GetProcAddress)#

这是最简单的方法。我们通过 GetModuleHandle 拿到 ntdll.dll,然后动态获取上述函数的地址并调用。

实战方案 B:使用 SysWhispers3 (间接系统调用)#

为了绕过 Hook,我们可以使用 SysWhispers3 生成间接系统调用代码。

操作步骤:

  1. 使用脚本生成代码: python syswhispers.py -m jumper_randomized -f NtAllocateVirtualMemory,NtProtectVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o SysWhispers
  2. 将生成的 .h, .c.asm 文件添加到 Visual Studio 项目。
  3. 在项目属性中启用 MASM (Microsoft Macro Assembler)
  4. .asm 文件的项类型设置为 Microsoft Macro Assembler

这样,当你调用 NtAllocateVirtualMemory 时,它会通过你自己的汇行代码跳转到内核,从而彻底无视 EDR 的监控。

实战方案 C:使用地狱之门 (Hell’s Gate)#

我们也可以集成地狱之门技术,在运行时动态搜寻 SSN。我们需要:

  1. 更新 VX_TABLE 结构体以包含四个新函数。
  2. 使用新的 Seed 生成 Djb2 哈希。
  3. main 函数中初始化表格并调用动态解析后的系统调用。

关键细节:内存对齐问题#

由于 NtAllocateVirtualMemory 会修改 RegionSize 的值(将其向上取整为 4096 的倍数),在编写代码时必须小心。

// 错误示例:
SIZE_T sSize = 272;
NtAllocateVirtualMemory(..., &sSize, ...); // sSize 现在变成了 4096
// 下一步写入时,你会尝试写入 4096 字节,这可能会导致缓冲区溢出或写入失败
NtWriteVirtualMemory(..., pPayload, sSize, ...); 
c

正确做法:始终使用一个原始副本保存 Payload 的真实大小。


🎯 总结#

在本模块中,我们学习了:

  1. API 替换映射:掌握了从高级 WinAPI 到低级 NtAPI 的转换关系。
  2. 底层调用约定:理解了 NtAPI 中普遍存在的“引用传递”要求及内存对齐逻辑。
  3. 工程实践:学会了如何在 Visual Studio 中集成 ASM 汇编代码,并通过三种不同的方案(动态调用、SysWhispers、地狱之门)实现隐蔽注入。

📚 下一步学习

下一个模块将探讨 Syscalls - Reimplementing Mapping Injection。我们将学习如何使用系统调用来实现更隐蔽的内存映射注入技术!