├── .gitattributes ├── .gitignore ├── ForceThreadSuspend.sln ├── SuspendCore ├── SuspendCore.h ├── SuspendCore.vcxproj ├── SuspendCore.vcxproj.filters └── main.cpp ├── SuspenderProcess ├── SuspenderProcess.vcxproj ├── SuspenderProcess.vcxproj.filters └── main.cpp └── TargetProcess ├── TargetProcess.vcxproj ├── TargetProcess.vcxproj.filters └── main.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /ForceThreadSuspend.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SuspendCore", "SuspendCore\SuspendCore.vcxproj", "{6D3626CB-C40F-4D61-B64F-CE20EFC429CD}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TargetProcess", "TargetProcess\TargetProcess.vcxproj", "{506AC6AA-BB55-4C9E-B19A-6149B50CD7A7}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SuspenderProcess", "SuspenderProcess\SuspenderProcess.vcxproj", "{C2F10B0F-4B8A-4644-9E88-8910FD1B14A4}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Win32 = Debug|Win32 15 | Release|Win32 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {6D3626CB-C40F-4D61-B64F-CE20EFC429CD}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {6D3626CB-C40F-4D61-B64F-CE20EFC429CD}.Debug|Win32.Build.0 = Debug|Win32 20 | {6D3626CB-C40F-4D61-B64F-CE20EFC429CD}.Release|Win32.ActiveCfg = Release|Win32 21 | {6D3626CB-C40F-4D61-B64F-CE20EFC429CD}.Release|Win32.Build.0 = Release|Win32 22 | {506AC6AA-BB55-4C9E-B19A-6149B50CD7A7}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {506AC6AA-BB55-4C9E-B19A-6149B50CD7A7}.Debug|Win32.Build.0 = Debug|Win32 24 | {506AC6AA-BB55-4C9E-B19A-6149B50CD7A7}.Release|Win32.ActiveCfg = Release|Win32 25 | {506AC6AA-BB55-4C9E-B19A-6149B50CD7A7}.Release|Win32.Build.0 = Release|Win32 26 | {C2F10B0F-4B8A-4644-9E88-8910FD1B14A4}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {C2F10B0F-4B8A-4644-9E88-8910FD1B14A4}.Debug|Win32.Build.0 = Debug|Win32 28 | {C2F10B0F-4B8A-4644-9E88-8910FD1B14A4}.Release|Win32.ActiveCfg = Release|Win32 29 | {C2F10B0F-4B8A-4644-9E88-8910FD1B14A4}.Release|Win32.Build.0 = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /SuspendCore/SuspendCore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #define WIN32_LEAN_AND_MEAN 5 | 6 | namespace SuspendCore 7 | { 8 | class CSuspendCore 9 | { 10 | public: 11 | void SuspendThread(DWORD dwThreadId); 12 | }; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /SuspendCore/SuspendCore.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {6D3626CB-C40F-4D61-B64F-CE20EFC429CD} 15 | Win32Proj 16 | SuspendCore 17 | 18 | 19 | 20 | StaticLibrary 21 | true 22 | v120_xp 23 | MultiByte 24 | 25 | 26 | StaticLibrary 27 | false 28 | v120_xp 29 | true 30 | MultiByte 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Use 46 | Level3 47 | Disabled 48 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 49 | true 50 | SuspendCore.h 51 | MultiThreadedDebug 52 | 53 | 54 | Windows 55 | true 56 | 57 | 58 | 59 | 60 | Level3 61 | Use 62 | MaxSpeed 63 | true 64 | true 65 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 66 | true 67 | SuspendCore.h 68 | MultiThreaded 69 | 70 | 71 | Windows 72 | true 73 | true 74 | true 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Create 83 | Create 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /SuspendCore/SuspendCore.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | 19 | 20 | Header Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /SuspendCore/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "SuspendCore.h" 7 | 8 | 9 | static auto g_dwSleepAddress = (DWORD)GetProcAddress(LoadLibraryA("kernel32"), "Sleep"); 10 | static void __declspec(naked) SleepStub() 11 | { 12 | __asm { 13 | push 0xFFFFFFFF /* INFINITE */ /* 0x2 */ 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop /* 0x5 */ 19 | } 20 | /* 0x7 */ 21 | } 22 | 23 | 24 | void SuspendCore::CSuspendCore::SuspendThread(DWORD dwThreadId) 25 | { 26 | auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); 27 | if (!hThread || hThread == INVALID_HANDLE_VALUE) { 28 | printf("OpenThread fail! Error: %u\n", GetLastError()); 29 | return; 30 | } 31 | printf("Thread handle(%p) successfully created!\n", hThread); 32 | 33 | auto dwOwnerProcessId = GetProcessIdOfThread(hThread); 34 | if (!dwOwnerProcessId) { 35 | printf("GetProcessIdOfThread fail! Error: %u\n", GetLastError()); 36 | return; 37 | } 38 | printf("Thread: %u Owner process found! PID: %u\n", dwThreadId, dwOwnerProcessId); 39 | 40 | auto hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwOwnerProcessId); 41 | if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { 42 | printf("OpenProcess fail! Error: %u\n", GetLastError()); 43 | return; 44 | } 45 | printf("Process handle(%p) successfully created!\n", hProcess); 46 | 47 | auto dwSuspendRet = ::SuspendThread(hThread); 48 | if (dwSuspendRet == (DWORD)-1) { 49 | printf("SuspendThread fail! Error: %u\n", GetLastError()); 50 | return; 51 | } 52 | printf("Thread: %u successfully suspended!\n", dwThreadId); 53 | 54 | CONTEXT ctx; 55 | ctx.ContextFlags = CONTEXT_CONTROL; 56 | if (GetThreadContext(hThread, &ctx) == FALSE) { 57 | printf("GetThreadContext fail! Error: %u\n", GetLastError()); 58 | ResumeThread(hThread); 59 | return; 60 | } 61 | printf("Thread context(%p) found! Eip: %p\n", ctx, ctx.Eip); 62 | 63 | DWORD dwOldProtect = 0; 64 | auto bProtectRet = VirtualProtect(SleepStub, 0x7, PAGE_EXECUTE_READWRITE, &dwOldProtect); 65 | if (bProtectRet == FALSE) { 66 | printf("VirtualProtect fail! Error: %u\n", GetLastError()); 67 | ResumeThread(hThread); 68 | return; 69 | } 70 | printf("Stub protect adjust completed!\n"); 71 | 72 | (*(BYTE*)((DWORD)SleepStub + 2)) = 0xE9; // Jump 73 | (*(DWORD*)((DWORD)SleepStub + 3)) = (g_dwSleepAddress - ctx.Eip - 0x7 /* stub size */); // Target addr 74 | printf("Stub successfully re-write completed!\n"); 75 | 76 | SIZE_T writtenByteSize = 0; 77 | auto bWriteRet = WriteProcessMemory(hProcess, (LPVOID)(ctx.Eip), SleepStub, 0x7, &writtenByteSize); 78 | if (bWriteRet == FALSE) { 79 | printf("WriteProcessMemory fail! Error: %u\n", GetLastError()); 80 | ResumeThread(hThread); 81 | return; 82 | } 83 | printf("Stub writed to: %p 0x7/0x%x bytes!\n", ctx.Eip, writtenByteSize); 84 | 85 | auto dwResumeRet = ::ResumeThread(hThread); 86 | if (dwResumeRet == (DWORD)-1) { 87 | printf("ResumeThread fail! Error: %u\n", GetLastError()); 88 | return; 89 | } 90 | printf("Thread: %u successfully resumed!\n", dwThreadId); 91 | 92 | if (CloseHandle(hThread) == FALSE || CloseHandle(hProcess) == FALSE) { 93 | printf("CloseHandle fail! Error: %u\n", GetLastError()); 94 | return; 95 | } 96 | printf("Handles cleared!\n"); 97 | } 98 | 99 | -------------------------------------------------------------------------------- /SuspenderProcess/SuspenderProcess.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {C2F10B0F-4B8A-4644-9E88-8910FD1B14A4} 15 | Win32Proj 16 | SuspenderProcess 17 | 18 | 19 | 20 | Application 21 | true 22 | v120_xp 23 | MultiByte 24 | 25 | 26 | Application 27 | false 28 | v120_xp 29 | true 30 | MultiByte 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | true 56 | MultiThreadedDebug 57 | 58 | 59 | Console 60 | true 61 | 62 | 63 | 64 | 65 | Level3 66 | 67 | 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 72 | true 73 | MultiThreaded 74 | 75 | 76 | Console 77 | true 78 | true 79 | true 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /SuspenderProcess/SuspenderProcess.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /SuspenderProcess/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #pragma comment( lib, "psapi.lib" ) 8 | 9 | #include "../SuspendCore/SuspendCore.h" 10 | #ifdef _DEBUG 11 | #pragma comment( lib, "../Debug/SuspendCore.lib" ) 12 | #else 13 | #pragma comment( lib, "../Release/SuspendCore.lib" ) 14 | #endif 15 | using namespace SuspendCore; 16 | static CSuspendCore suspendCore; 17 | 18 | 19 | typedef NTSTATUS(NTAPI* lpRtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN); 20 | lpRtlAdjustPrivilege RtlAdjustPrivilege = nullptr; 21 | 22 | typedef NTSTATUS(WINAPI* lpNtQueryInformationThread)(HANDLE, LONG, PVOID, ULONG, PULONG); 23 | lpNtQueryInformationThread NtQueryInformationThread = nullptr; 24 | 25 | std::vector vThreadIdList; 26 | 27 | 28 | int main() 29 | { 30 | HMODULE hNtdll = LoadLibraryA("ntdll"); 31 | assert(hNtdll); 32 | 33 | RtlAdjustPrivilege = (lpRtlAdjustPrivilege)GetProcAddress(LoadLibraryA("ntdll"), "RtlAdjustPrivilege"); 34 | assert(RtlAdjustPrivilege); 35 | 36 | NtQueryInformationThread = (lpNtQueryInformationThread)GetProcAddress(LoadLibraryA("ntdll"), "NtQueryInformationThread"); 37 | assert(NtQueryInformationThread); 38 | 39 | 40 | auto GetThreadStartAddress = [](HANDLE hThread) -> DWORD { 41 | DWORD dwCurrentThreadAddress = 0; 42 | NtQueryInformationThread(hThread, 0x9, &dwCurrentThreadAddress, sizeof(dwCurrentThreadAddress), NULL); 43 | return dwCurrentThreadAddress; 44 | }; 45 | 46 | auto GetThreadOwner = [](HANDLE hProcess, DWORD dwStartAddress) -> std::string { 47 | char cFileName[2048] = { 0 }; 48 | GetMappedFileNameA(hProcess, (LPVOID)dwStartAddress, cFileName, 2048); 49 | return cFileName; 50 | }; 51 | 52 | 53 | BOOLEAN boAdjustPrivRet; 54 | RtlAdjustPrivilege(20, TRUE, FALSE, &boAdjustPrivRet); 55 | 56 | 57 | printf("Target Process: "); 58 | DWORD dwTargetPID = 0; 59 | std::cin >> dwTargetPID; 60 | auto hProcess = OpenProcess(SYNCHRONIZE, FALSE, dwTargetPID); 61 | if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { 62 | printf("Target process %u is not active!\n", dwTargetPID); 63 | return 0; 64 | } 65 | CloseHandle(hProcess); 66 | 67 | 68 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTargetPID); 69 | if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { 70 | printf("Target process: %u couldn't be opened!\n", dwTargetPID); 71 | return 0; 72 | } 73 | 74 | 75 | auto GetThreadList = [](DWORD dwProcessId) -> void { 76 | auto hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL); 77 | THREADENTRY32 ti = { 0 }; 78 | ti.dwSize = sizeof(ti); 79 | 80 | if (Thread32First(hSnap, &ti)) 81 | { 82 | do { 83 | if (dwProcessId == ti.th32OwnerProcessID) 84 | vThreadIdList.push_back(ti.th32ThreadID); 85 | } while (Thread32Next(hSnap, &ti)); 86 | } 87 | CloseHandle(hSnap); 88 | }; 89 | GetThreadList(dwTargetPID); 90 | 91 | 92 | for (const auto & dwThreadId : vThreadIdList) 93 | { 94 | printf("[*] Thread found! %u processing...\n", dwThreadId); 95 | 96 | auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); 97 | if (!hThread || hThread == INVALID_HANDLE_VALUE) { 98 | printf("#Error: Thread: %u couldn't be opened!\n", dwThreadId); 99 | continue; 100 | } 101 | 102 | auto dwThreadAddress = GetThreadStartAddress(hThread); 103 | if (!dwThreadAddress) { 104 | printf("#Error: Thread: %u start address not found!\n", dwThreadId); 105 | continue; 106 | } 107 | 108 | auto szThreadOwner = GetThreadOwner(hProcess, dwThreadAddress); 109 | if (szThreadOwner.empty()) { 110 | printf("#Error: Thread: %u owner module not found!\n", dwThreadId); 111 | continue; 112 | } 113 | 114 | printf("\tThread: %p(%u) Adr: %p Owner: %s\n", hThread, dwThreadId, dwThreadAddress, szThreadOwner.c_str()); 115 | CloseHandle(hThread); 116 | } 117 | vThreadIdList.clear(); 118 | 119 | 120 | printf("\n\n- Target Thread ID: "); 121 | DWORD dwTargetTID = 0; 122 | std::cin >> dwTargetTID; 123 | 124 | suspendCore.SuspendThread(dwTargetTID); 125 | printf("Suspend work completed!\n"); 126 | 127 | 128 | CloseHandle(hProcess); 129 | printf("\n\nCompleted!\n"); 130 | Sleep(INFINITE); 131 | return 0; 132 | } 133 | 134 | -------------------------------------------------------------------------------- /TargetProcess/TargetProcess.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {506AC6AA-BB55-4C9E-B19A-6149B50CD7A7} 15 | Win32Proj 16 | TargetProcess 17 | 18 | 19 | 20 | Application 21 | true 22 | v120_xp 23 | MultiByte 24 | 25 | 26 | Application 27 | false 28 | v120_xp 29 | true 30 | MultiByte 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | true 56 | MultiThreadedDebug 57 | 58 | 59 | Console 60 | true 61 | 62 | 63 | 64 | 65 | Level3 66 | 67 | 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 72 | true 73 | MultiThreaded 74 | 75 | 76 | Console 77 | true 78 | true 79 | true 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /TargetProcess/TargetProcess.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /TargetProcess/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | printf("Test process started! PID: %u\n", GetCurrentProcessId()); 8 | 9 | DWORD dwThreadId = 0; 10 | auto workerThread = [](LPVOID) -> DWORD { 11 | DWORD dwTick = 0; 12 | while (1) { 13 | printf("%u) I'm working!\n", ++dwTick); 14 | Sleep(5000); 15 | } 16 | return 0; 17 | }; 18 | 19 | auto hThread = CreateThread(nullptr, 0, workerThread, nullptr, 0, &dwThreadId); 20 | assert(hThread); 21 | printf("Thread successfully created! TID: %u\n", dwThreadId); 22 | 23 | while (1) Sleep(1000); 24 | return 0; 25 | } 26 | 27 | --------------------------------------------------------------------------------